From 38e916075717f1d9a72e64e7ed62ad1c1f98d5fd Mon Sep 17 00:00:00 2001 From: Aref Shafaei Date: Fri, 13 Oct 2023 11:22:41 -0700 Subject: [PATCH] refactor copy to clipboard functions + change tooltip as a feedback to users the share and cite popup links were not using the same function as permalink, and were only using the deprecated API for clipboard which wasn't working properly on some browsers. we also decided to change the tooltip as a feedback to users. to make sure the tooltip is displayed in the proper place I had to change the tooltip component a bit. --- src/components/modals/share-cite-modal.tsx | 59 +++++++++++++------ src/components/recordset/recordset.tsx | 25 ++++++-- src/components/share-cite-button.tsx | 1 + src/components/tooltip.tsx | 46 ++++++++++----- src/utils/message-map.ts | 2 +- src/utils/ui-utils.ts | 31 ++++------ .../recordset/presentation.spec.js | 2 +- 7 files changed, 106 insertions(+), 60 deletions(-) diff --git a/src/components/modals/share-cite-modal.tsx b/src/components/modals/share-cite-modal.tsx index 4107ab7a7..aebf5d02c 100644 --- a/src/components/modals/share-cite-modal.tsx +++ b/src/components/modals/share-cite-modal.tsx @@ -14,11 +14,12 @@ import { LogActions } from '@isrd-isi-edu/chaise/src/models/log'; // services import { ConfigService } from '@isrd-isi-edu/chaise/src/services/config'; import { LogService } from '@isrd-isi-edu/chaise/src/services/log'; +import $log from '@isrd-isi-edu/chaise/src/services/logger'; // utils import { resolvePermalink } from '@isrd-isi-edu/chaise/src/utils/uri-utils'; import { getVersionDate, humanizeTimestamp } from '@isrd-isi-edu/chaise/src/utils/date-time-utils'; - +import { copyToClipboard } from '@isrd-isi-edu/chaise/src/utils/ui-utils'; export type ShareCiteModalProps = { /** @@ -75,6 +76,10 @@ const ShareCiteModal = ({ logStackPath, }: ShareCiteModalProps): JSX.Element => { + const DEFAULT_COPY_TOOLTIP = 'Copy link URL to clipboard.'; + const [versionLinkCopyTooltip, setVersionLinkCopyTooltip] = useState(DEFAULT_COPY_TOOLTIP); + const [liveLinkCopyTooltip, setLiveLinkCopyTooltip] = useState(DEFAULT_COPY_TOOLTIP); + const logCitationDownload = () => { LogService.logClientAction({ action: LogService.getActionString(LogActions.CITE_BIBTEXT_DOWNLOAD, logStackPath), @@ -82,25 +87,41 @@ const ShareCiteModal = ({ }, reference.defaultLogInfo); }; - const copyToClipboard = (text: string, action: string) => { + /** + * set the tooltip of the copy button + * @param isVersionLink whether this is for the version link or live link + * @param str the tooltip + */ + const setLinkCopyTooltip = (isVersionLink: boolean, str: string) => { + if (isVersionLink) { + setVersionLinkCopyTooltip(str) + } else { + setLiveLinkCopyTooltip(str); + } + } + + /** + * the callback for clicking on the copy link button + * @param isVersionLink whether this is for the version link or live link + */ + const onCopyToClipboard = (isVersionLink: boolean) => { + const action = isVersionLink ? LogActions.SHARE_VERSIONED_LINK_COPY : LogActions.SHARE_LIVE_LINK_COPY; + const text = isVersionLink ? versionLink : liveLink; + LogService.logClientAction({ action: LogService.getActionString(action, logStackPath), stack: logStack ? logStack : LogService.getStackObject() }, reference.defaultLogInfo); - // Create a dummy input to put the text string into it, select it, then copy it - // this has to be done because of HTML security and not letting scripts just copy stuff to the clipboard - // it has to be a user initiated action that is done through the DOM object - const dummy = document.createElement('input'); - dummy.setAttribute('visibility', 'hidden'); - dummy.setAttribute('display', 'none'); - document.body.appendChild(dummy); - // dummy.setAttribute('id', 'copy_id'); - // document.getElementById('copy_id')!.value = text; - dummy.value = text; - dummy.select(); - document.execCommand('copy'); - document.body.removeChild(dummy); + copyToClipboard(text).then(() => { + setLinkCopyTooltip(isVersionLink, 'Copied!'); + setTimeout(() => { + setLinkCopyTooltip(isVersionLink, DEFAULT_COPY_TOOLTIP); + }, 1000); + }).catch((err) => { + $log.warn('failed to copy with the following error:'); + $log.warn(err); + }) } const citationReady = !!citation && citation.isReady; @@ -183,10 +204,10 @@ const ShareCiteModal = ({ ({versionDateRelative}) - + copyToClipboard(versionLink, LogActions.SHARE_VERSIONED_LINK_COPY)} + onClick={() => onCopyToClipboard(true)} /> @@ -195,10 +216,10 @@ const ShareCiteModal = ({ }

Live Link - + copyToClipboard(liveLink, LogActions.SHARE_LIVE_LINK_COPY)} + onClick={() => onCopyToClipboard(false)} />

diff --git a/src/components/recordset/recordset.tsx b/src/components/recordset/recordset.tsx index 294d98599..fc6778ad5 100644 --- a/src/components/recordset/recordset.tsx +++ b/src/components/recordset/recordset.tsx @@ -18,7 +18,7 @@ import Title from '@isrd-isi-edu/chaise/src/components/title'; import TableHeader from '@isrd-isi-edu/chaise/src/components/recordset/table-header'; // hooks -import { useEffect, useRef, useState } from 'react'; +import React, { AnchorHTMLAttributes, useEffect, useRef, useState } from 'react'; import useError from '@isrd-isi-edu/chaise/src/hooks/error'; import useRecordset from '@isrd-isi-edu/chaise/src/hooks/recordset'; @@ -162,6 +162,8 @@ const RecordsetInner = ({ const [savedQueryUpdated, setSavedQueryUpdated] = useState(false); + const [permalinkTooltip, setPermalinkTooltip] = useState(MESSAGE_MAP.tooltip.permalink); + const mainContainer = useRef(null); const topRightContainer = useRef(null); const topLeftContainer = useRef(null); @@ -529,11 +531,26 @@ const RecordsetInner = ({ const recordsetLink = getRecordsetLink(); - const copyPermalink = () => { + /** + * the callback for when permalink button is clicked + */ + const copyPermalink = (e: React.MouseEvent) => { + // avoid the navigation + e.preventDefault(); + // log the action logRecordsetClientAction(LogActions.PERMALINK_LEFT); - copyToClipboard(recordsetLink); + // copy to the clipboard + copyToClipboard(recordsetLink).then(() => { + setPermalinkTooltip('Copied!'); + setTimeout(() => { + setPermalinkTooltip(MESSAGE_MAP.tooltip.permalink); + }, 1000); + }).catch((err) => { + $log.warn('failed to copy with the following error:') + $log.warn(err); + }) } /** @@ -823,7 +840,7 @@ const RecordsetInner = ({ reference={reference} disabled={isLoading || !page || page.length === 0} /> - +