peter-tanner.github.io/_javascript/modules/components/clipboard.js

144 lines
3.1 KiB
JavaScript
Raw Normal View History

2024-10-13 04:56:18 +08:00
/**
* Clipboard functions
*
* Dependencies:
* clipboard.js (https://github.com/zenorocha/clipboard.js)
*/
import Tooltip from 'bootstrap/js/src/tooltip';
const clipboardSelector = '.code-header>button';
const ICON_DEFAULT = 'far fa-clipboard';
const ICON_SUCCESS = 'fas fa-check';
const ATTR_TIMEOUT = 'timeout';
const ATTR_TITLE_SUCCEED = 'data-title-succeed';
const ATTR_TITLE_ORIGIN = 'data-bs-original-title';
const TIMEOUT = 2000; // in milliseconds
function isLocked(node) {
if (node.hasAttribute(ATTR_TIMEOUT)) {
let timeout = node.getAttribute(ATTR_TIMEOUT);
if (Number(timeout) > Date.now()) {
return true;
}
}
return false;
}
function lock(node) {
node.setAttribute(ATTR_TIMEOUT, Date.now() + TIMEOUT);
}
function unlock(node) {
node.removeAttribute(ATTR_TIMEOUT);
}
function showTooltip(btn) {
const succeedTitle = btn.getAttribute(ATTR_TITLE_SUCCEED);
btn.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
Tooltip.getInstance(btn).show();
}
function hideTooltip(btn) {
Tooltip.getInstance(btn).hide();
btn.removeAttribute(ATTR_TITLE_ORIGIN);
}
function setSuccessIcon(btn) {
const icon = btn.children[0];
icon.setAttribute('class', ICON_SUCCESS);
}
function resumeIcon(btn) {
const icon = btn.children[0];
icon.setAttribute('class', ICON_DEFAULT);
}
function setCodeClipboard() {
const clipboardList = document.querySelectorAll(clipboardSelector);
if (clipboardList.length === 0) {
return;
}
// Initial the clipboard.js object
const clipboard = new ClipboardJS(clipboardSelector, {
target: (trigger) => {
const codeBlock = trigger.parentNode.nextElementSibling;
return codeBlock.querySelector('code .rouge-code');
}
});
[...clipboardList].map(
(elem) =>
new Tooltip(elem, {
placement: 'left'
})
);
clipboard.on('success', (e) => {
const trigger = e.trigger;
e.clearSelection();
if (isLocked(trigger)) {
return;
}
setSuccessIcon(trigger);
showTooltip(trigger);
lock(trigger);
setTimeout(() => {
hideTooltip(trigger);
resumeIcon(trigger);
unlock(trigger);
}, TIMEOUT);
});
}
function setLinkClipboard() {
const btnCopyLink = document.getElementById('copy-link');
if (btnCopyLink === null) {
return;
}
btnCopyLink.addEventListener('click', (e) => {
const target = e.target;
if (isLocked(target)) {
return;
}
// Copy URL to clipboard
navigator.clipboard.writeText(window.location.href).then(() => {
const defaultTitle = target.getAttribute(ATTR_TITLE_ORIGIN);
const succeedTitle = target.getAttribute(ATTR_TITLE_SUCCEED);
// Switch tooltip title
target.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
Tooltip.getInstance(target).show();
lock(target);
setTimeout(() => {
target.setAttribute(ATTR_TITLE_ORIGIN, defaultTitle);
unlock(target);
}, TIMEOUT);
});
});
btnCopyLink.addEventListener('mouseleave', (e) => {
Tooltip.getInstance(e.target).hide();
});
}
export function initClipboard() {
setCodeClipboard();
setLinkClipboard();
}