forked from laurent22/joplin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Show "ctrl+click to open" tooltip over links
This is a potential fix for laurent22#10199. This particular fix displays a custom tooltip, in addition to the OS tooltip. The custom tooltip is shown above the target element, while the OS tooltip (at least on my Linux system) is shown below. After this, I plan to work on a different fix that changes the content of the OS tooltip, and changes it back before saving. This would be a similar approach to laurent22#10359, except change the content in the rich text editor, rather than in `turndown`. This has the advantage of also working for HTML notes.
- Loading branch information
1 parent
97ddb67
commit f2b302d
Showing
4 changed files
with
150 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import type { Editor } from 'tinymce'; | ||
import { useEffect } from 'react'; | ||
import { themeStyle } from '@joplin/lib/theme'; | ||
import { _ } from '@joplin/lib/locale'; | ||
import shim from '@joplin/lib/shim'; | ||
|
||
const useStyles = (editor: Editor|null, themeId: number) => { | ||
useEffect(() => { | ||
if (!editor) { | ||
return () => {}; | ||
} | ||
|
||
const theme = themeStyle(themeId); | ||
const style = document.createElement('style'); | ||
style.appendChild(document.createTextNode(` | ||
@keyframes show-tooltip { | ||
0% { opacity: 0; } | ||
100% { opacity: 0.8; } | ||
} | ||
.joplin-link-tooltip { | ||
padding-bottom: 10px; | ||
visibility: hidden; | ||
opacity: 0; | ||
pointer-events: none; | ||
display: inline-block; | ||
position: fixed; | ||
transition: 0.2s ease opacity; | ||
} | ||
.joplin-link-tooltip > div { | ||
background-color: ${theme.backgroundColor2}; | ||
color: ${theme.color2}; | ||
padding: 4px; | ||
border-radius: 4px; | ||
} | ||
.joplin-link-tooltip.-visible { | ||
visibility: visible; | ||
opacity: 0.8; | ||
} | ||
`)); | ||
document.head.appendChild(style); | ||
|
||
return () => { | ||
style.remove(); | ||
}; | ||
}, [editor, themeId]); | ||
}; | ||
|
||
const useLinkTooltips = (editor: Editor|null, themeId: number) => { | ||
useStyles(editor, themeId); | ||
|
||
useEffect(() => { | ||
if (!editor) return () => {}; | ||
|
||
const tooltip = document.createElement('div'); | ||
const tooltipContent = document.createElement('div'); | ||
tooltip.replaceChildren(tooltipContent); | ||
tooltip.ariaLive = 'polite'; | ||
tooltip.classList.add('joplin-link-tooltip'); | ||
document.body.appendChild(tooltip); | ||
|
||
let showAtTimeout: ReturnType<typeof setTimeout>|null = null; | ||
const cancelShowTooltip = () => { | ||
if (showAtTimeout) { | ||
clearTimeout(showAtTimeout); | ||
showAtTimeout = null; | ||
} | ||
}; | ||
const showTooltipAt = (x: number, y: number) => { | ||
cancelShowTooltip(); | ||
|
||
const delay = 700; | ||
showAtTimeout = setTimeout(() => { | ||
x = Math.max(0, Math.min(window.innerWidth - tooltip.clientWidth, x)); | ||
|
||
tooltip.style.left = `${x}px`; | ||
tooltip.style.top = `${y}px`; | ||
tooltip.classList.add('-visible'); | ||
}, delay); | ||
}; | ||
|
||
const hideTooltip = () => { | ||
tooltip.classList.remove('-visible'); | ||
tooltipContent.textContent = ''; | ||
cancelShowTooltip(); | ||
}; | ||
|
||
const onMouseOver = (event: MouseEvent) => { | ||
let element = event.target as HTMLElement; | ||
let counter = 0; | ||
while (element.tagName !== 'A' || !('href' in element)) { | ||
element = element.parentElement; | ||
if (!element || counter++ > 5) { | ||
return; | ||
} | ||
} | ||
|
||
if (shim.isMac()) { | ||
tooltipContent.textContent = _('cmd+click to open: %s', element.title || element.href); | ||
} else { | ||
tooltipContent.textContent = _('ctrl+click to open: %s', element.title || element.href); | ||
} | ||
|
||
const bbox = element.getBoundingClientRect(); | ||
const frameBBox = editor.getContentAreaContainer().getBoundingClientRect(); | ||
|
||
// Position just below the element. | ||
showTooltipAt( | ||
bbox.left + bbox.width / 2 + frameBBox.left - tooltip.clientWidth / 2, | ||
bbox.top - tooltip.clientHeight + frameBBox.top, | ||
); | ||
|
||
const onMouseLeave = () => { | ||
hideTooltip(); | ||
element.removeEventListener('mouseleave', onMouseLeave); | ||
}; | ||
element.addEventListener('mouseleave', onMouseLeave); | ||
}; | ||
|
||
const clearEventListeners = () => { | ||
editor.getDoc().removeEventListener('mouseover', onMouseOver); | ||
}; | ||
|
||
const rebuildEventListeners = () => { | ||
clearEventListeners(); | ||
|
||
editor.getDoc().addEventListener('mouseover', onMouseOver, false); | ||
}; | ||
rebuildEventListeners(); | ||
editor.on('SetContent', rebuildEventListeners); | ||
editor.on('keyup', hideTooltip); | ||
editor.on('click', hideTooltip); | ||
|
||
return () => { | ||
editor.off('SetContent', rebuildEventListeners); | ||
tooltip.remove(); | ||
clearEventListeners(); | ||
}; | ||
}, [editor]); | ||
}; | ||
|
||
export default useLinkTooltips; |
f2b302d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Screenshot:
Above, the black box below the content is the Electron-created tooltip and the gray box is the custom tooltip.