docbrown/app/assets/javascripts/initializers/initializeCommentDropdown.js
Nizar 7058d628af
Added Copy Permalink Functionality to Comment Dropdown (#8311)
* Added Copy Permalink Functionality to Comment Dropdown

Copy functionality is similar to the way 'copy article link' is implemented. It checks for the android bridge first, then the navigator, then fallsback to the default document copy command

Since the codes were really similar, I moved the copy functionality to a function of its own with callbacks and fallbacks as lambdas, and triggered it with the copyArticleLink and the copyPermalink

* Replaced Copy Permalink Callbacks with Promises

* Keep anchor tags instead of buttons (#1)

* copy permalink using anchor tag

* Missing closing button tag

* Adds 'Copied to Clipboard' Snackbar Message

* Patches bug introduced in #10323

Patch suggested in following comment: https://github.com/forem/forem/pull/8311\#pullrequestreview-492011202

* Removes import statement for addSnackbarItem and Suppresses ESLint Error

Initializer runs in global scope

* Unhandles exception when copying permalink so Honeybadger can handle it

* Replaces ButtonListener suffix for copyPermalink method with Listener

Co-authored-by: Fernando Valverde <fernando@visualcosita.com>
2020-11-11 08:32:10 -05:00

153 lines
4.5 KiB
JavaScript

/* global Runtime */
function initializeCommentDropdown() {
const announcer = document.getElementById('article-copy-link-announcer');
function removeClass(className) {
return (element) => element.classList.remove(className);
}
function getAllByClassName(className) {
return Array.from(document.getElementsByClassName(className));
}
function showAnnouncer() {
const { activeElement } = document;
const input =
activeElement.localName === 'clipboard-copy'
? activeElement.querySelector('input')
: document.getElementById('article-copy-link-input');
input.focus();
input.setSelectionRange(0, input.value.length);
announcer.hidden = false;
}
function hideAnnouncer() {
if (announcer) {
announcer.hidden = true;
}
}
function copyPermalink(event) {
event.preventDefault();
const permalink = event.target.href;
Runtime.copyToClipboard(permalink).then(() => {
// eslint-disable-next-line no-undef
addSnackbarItem({ message: 'Copied to clipboard' });
});
}
function copyArticleLink() {
const inputValue = document.getElementById('article-copy-link-input').value;
Runtime.copyToClipboard(inputValue).then(() => {
showAnnouncer();
});
}
function shouldCloseDropdown(event) {
var copyIcon = document.getElementById('article-copy-icon');
var isCopyIconChild = copyIcon && copyIcon.contains(event.target);
return !(
event.target.matches('.dropdown-icon') ||
event.target.matches('.dropbtn') ||
event.target.matches('clipboard-copy') ||
isCopyIconChild ||
event.target.parentElement.classList.contains('dropdown-link-row')
);
}
function removeClickListener() {
// disabling this rule because `removeEventListener` needs
// a reference to the specific handler. The function is hoisted.
// eslint-disable-next-line no-use-before-define
document.removeEventListener('click', outsideClickListener);
}
function removeCopyListener() {
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];
if (clipboardCopyElement) {
clipboardCopyElement.removeEventListener('click', copyArticleLink);
}
}
function removeAllShowing() {
getAllByClassName('crayons-dropdown').forEach(removeClass('block'));
}
function outsideClickListener(event) {
if (shouldCloseDropdown(event)) {
removeAllShowing();
hideAnnouncer();
removeClickListener();
}
}
function dropdownFunction(e) {
const button = e.currentTarget;
const dropdownContent = button.parentElement.getElementsByClassName(
'crayons-dropdown',
)[0];
if (!dropdownContent) {
return;
}
// Android native apps have enhanced sharing capabilities for Articles
const articleShowMoreClicked = button.id === 'article-show-more-button';
if (articleShowMoreClicked && Runtime.isNativeAndroid('shareText')) {
AndroidBridge.shareText(location.href);
return;
}
finalizeAbuseReportLink(
dropdownContent.querySelector('.report-abuse-link-wrapper'),
);
if (dropdownContent.classList.contains('block')) {
dropdownContent.classList.remove('block');
removeClickListener();
removeCopyListener();
hideAnnouncer();
} else {
removeAllShowing();
dropdownContent.classList.add('block');
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];
document.addEventListener('click', outsideClickListener);
if (clipboardCopyElement) {
clipboardCopyElement.addEventListener('click', copyArticleLink);
}
}
}
function finalizeAbuseReportLink(reportAbuseLink) {
// Add actual link location (SEO doesn't like these "useless" links, so adding in here instead of in HTML)
if (!reportAbuseLink) {
return;
}
reportAbuseLink.innerHTML = `<a href="${reportAbuseLink.dataset.path}" class="crayons-link crayons-link--block">Report Abuse</a>`;
}
function addDropdownListener(dropdown) {
if (!dropdown.getAttribute('has-dropdown-listener')) {
dropdown.addEventListener('click', dropdownFunction);
dropdown.setAttribute('has-dropdown-listener', 'true');
}
}
function copyPermalinkListener(copyPermalinkButton) {
copyPermalinkButton.addEventListener('click', copyPermalink);
}
setTimeout(function addListeners() {
getAllByClassName('dropbtn').forEach(addDropdownListener);
getAllByClassName('permalink-copybtn').forEach(copyPermalinkListener);
}, 100);
}