Commit ae5c8a58 authored by Chad Woolley's avatar Chad Woolley

WIP - functionality of tweet tooltip working with Popper2, but needs styling

parent 22ddddd2
Pipeline #118048915 failed with stages
in 9 minutes and 59 seconds
document.addEventListener(
'DOMContentLoaded',
() => {
// TODO: there is a a bug, the DOMContentLoaded event does not always fire!
// And thus the listeners don't get set up and the tooltip doesn't work.
// You can fix it by a page reload.
// Not sure if this is just in dev, or in prod too...
console.log('SETTING UP LISTENERS IN DOMContentLoaded');
// document.body.addEventListener('mousedown', update);
document.body.addEventListener('mouseup', update);
document.addEventListener("input", update);
document.addEventListener("keydown", event => update(event, true));
window.addEventListener("scroll", update);
document.scrollingElement.addEventListener("scroll", update);
function update(event, hide) {
console.log(`CALLING update FROM EVENT: ${event.type}`);
const selection = document.getSelection();
const range = selection && selection.rangeCount && selection.getRangeAt(0);
const boundingClientRect = (range && range.getBoundingClientRect()) || { width: 0 }
// TODO: There is currently a bug if you click IN the current selection
// the mouseup event fires while there is still a selection, before the event
// causes it to be deselected, so the tooltip stays displayed.
// We need to detect if the mouseup event was within the current selection,
// and if so, go ahead and destroy the tooltip.
if (boundingClientRect.width <= 1 || hide) {
console.log('DESTROYING TOOLTIP!')
// either we want to hide it or there is not currently a valid selection,
// so destroy the tooltip if it exist and return
if (window.tooltipPopper) {
destroyTooltip();
}
return;
}
if (!window.tooltipPopper) {
console.log('CREATING TOOLTIP!')
// create popper and element if they don't yet exist
createTooltip(selection, boundingClientRect);
}
window.tooltipPopper.update();
}
function createTooltip(selection, boundingClientRect) {
const tooltipElement = createTooltipElement(selection);
createTooltipPopper(boundingClientRect, tooltipElement);
}
function createTooltipElement(selection) {
// create the containing element
const tooltipElement = document.createElement('div')
tooltipElement.setAttribute('class', 'highlight-tooltip')
// build the tweet link html content
const tweetHtml = buildTweetHtml(selection.toString())
// append the tweet link html content
tooltipElement.innerHTML = tweetHtml
document.querySelector('body').appendChild(tooltipElement)
return tooltipElement;
}
function createTooltipPopper(boundingClientRect, tooltipElement) {
const virtualElement = {
getBoundingClientRect: () => (boundingClientRect),
};
const popperOptions = {
placement: "top",
modifiers: { offset: { offset: "0,5" } },
}
window.tooltipPopper = Popper.createPopper(virtualElement, tooltipElement, popperOptions);
}
function destroyTooltip() {
const tooltipElement = window.tooltipPopper.state.elements.popper;
document.querySelector('body').removeChild(tooltipElement);
window.tooltipPopper = undefined
}
function buildTweetHtml(rawTweetText) {
const tweetText = buildTweetText(rawTweetText)
const tweetUrl = encodeURI(window.location.href);
const tweetTags = 'gitlab,handbook';
const tweetHref = `https://twitter.com/intent/tweet?url=${tweetUrl}&text=${tweetText}&hashtags=${tweetTags}`;
const tweetAnchorText = '<i class="fab fa-twitter"></i><span class="sr-only">Share on Twitter\n</span>';
const tweetHtml = `<a class="tweet-highlight-link" href="${tweetHref}" target="_blank">${tweetAnchorText}</a>`;
return tweetHtml;
}
function buildTweetText(rawTweetText) {
// twitter will ellipsify, but no need to send more than max - link width...
const maxTextLength = 265
// max lenght of 265 is a guess at whether ellipses will be needed or not after twitter trims text and adds link
const maybeEllipses = rawTweetText.length > maxTextLength ? '...' : ''
const trimmedRawTweetText = rawTweetText.substring(0, maxTextLength)
// twitter knows to preserve trailing ellipses and quote
const tweetText = encodeURI(`"${trimmedRawTweetText}${maybeEllipses}"`)
return tweetText
}
}
)
document.addEventListener(
'DOMContentLoaded',
() => {
// document.body.addEventListener('mouseup', onMouseUp);
// document.body.addEventListener('mousedown', onMouseDown);
function onMouseUp() {
if (
window.getSelection &&
window.getSelection().toString().length > 0 &&
!window.highlightedNodeParentElement
) {
showTweetTooltip(window.getSelection());
}
}
function onMouseDown(event) {
const clickedTweetHighlightLink = $(event.target).closest('.tweet-highlight-link').length !== 0
if (
window.highlightedNodeParentElement && !clickedTweetHighlightLink
) {
$(window.highlightedNodeParentElement).tooltip('destroy');
window.highlightedNodeParentElement = undefined;
}
}
function showTweetTooltip(selection) {
const parentElement = $(selection.anchorNode.parentElement);
window.highlightedNodeParentElement = parentElement;
const tweetHtml = buildTweetHtml(selection.toString());
const tooltipOptions = {
'animation': false,
'title': tweetHtml,
'placement': 'auto top',
'trigger': 'manual',
'html': true,
};
parentElement.tooltip(tooltipOptions).on('shown.bs.tooltip', positionTooltip).tooltip('show');
}
function positionTooltip() {
const rect = window.getSelection().getRangeAt(0).getBoundingClientRect();
const tooltipDOM = document.querySelector('.tooltip');
const xPosition = rect.x + (rect.width / 2)
const yPosition = window.scrollY + rect.y - tooltipDOM.getBoundingClientRect().height - 5;
tooltipDOM.style.left = xPosition + 'px';
tooltipDOM.style.top = yPosition + 'px';
}
function buildTweetHtml(rawTweetText) {
const tweetText = buildTweetText(rawTweetText)
const tweetUrl = encodeURI(window.location.href);
const tweetTags = 'gitlab,handbook';
const tweetHref = `https://twitter.com/intent/tweet?url=${tweetUrl}&text=${tweetText}&hashtags=${tweetTags}`;
const tweetAnchorText = '<i class="fab fa-twitter"></i><span class="sr-only">Share on Twitter\n</span>';
const tweetHtml = `<a class="tweet-highlight-link" href="${tweetHref}" target="_blank">${tweetAnchorText}</a>`;
return tweetHtml;
}
function buildTweetText(rawTweetText) {
// twitter will ellipsify, but no need to send more than max - link width...
const maxTextLength = 265
// max lenght of 265 is a guess at whether ellipses will be needed or not after twitter trims text and adds link
const maybeEllipses = rawTweetText.length > maxTextLength ? '...' : ''
const trimmedRawTweetText = rawTweetText.substring(0, maxTextLength)
// twitter knows to preserve trailing ellipses and quote
const tweetText = encodeURI(`"${trimmedRawTweetText}${maybeEllipses}"`)
return tweetText
}
}
)
// import { createPopper } from '@popperjs/core';
// From https://codepen.io/FezVrasta/pen/vWXQdq
class RangeRef {
constructor() {
this.updateRect();
const update = (evt, hide) => {
let selection = document.getSelection();
this.range = selection && selection.rangeCount && selection.getRangeAt(0);
this.updateRect(hide);
}
document
.querySelector("body")
.addEventListener("mouseup", update);
document
.querySelector("body")
.addEventListener("input", update);
document
.querySelector("body")
.addEventListener("keydown", evt => update(evt, true));
window
.addEventListener("scroll", update);
document
.scrollingElement
.addEventListener("scroll", update);
}
updateRect(hide) {
if (!hide && this.range) {
this.rect = this.range.getBoundingClientRect();
} else {
this.rect = {
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 0,
height: 0
};
}
this.rectChangedCallback(this.rect);
}
rectChangedCallback() {
// Abstract to be implemented
}
getBoundingClientRect() {
return this.rect;
}
get clientWidth() {
return this.rect.width;
}
get clientHeight() {
return this.rect.height;
}
}
const pop = document.getElementById("pop");
const rangeRef = new RangeRef();
const popper = new Popper(rangeRef, pop, {
placement: "top",
modifiers: { offset: { offset: "0,5" } },
});
rangeRef.rectChangedCallback = ({ width }) => {
if (width > 0) {
popper.scheduleUpdate();
pop.firstElementChild.classList.add('popper--visible');
} else {
pop.firstElementChild.classList.remove('popper--visible');
}
};
<%# From https://codepen.io/FezVrasta/pen/vWXQdq %>
<div id="pop" role="tooltip">
<div class="popper">
<i class="fa fa-bold"></i>
<i class="fa fa-italic"></i>
<i class="fa fa-link"></i>
<div x-arrow></div>
</div>
</div>
<!--<div id="pop" role="tooltip">-->
<!-- <div class="popper">-->
<!-- <i class="fa fa-bold"></i>-->
<!-- <i class="fa fa-italic"></i>-->
<!-- <i class="fa fa-link"></i>-->
<!-- <div x-arrow></div>-->
<!-- </div>-->
<!--</div>-->
<% add_extra_css('highlight-tooltip.css') %>
<% add_extra_js('bundles/tweet-highlight.js') %>
<% add_extra_js('bundles/highlight-tooltip.js') %>
= javascript_include_tag "libs/jquery.min.js"
= javascript_include_tag "libs/bootstrap.min.js"
-# = javascript_include_tag "https://unpkg.com/@popperjs/core@2"
= javascript_include_tag "https://unpkg.com/popper.js"
= javascript_include_tag "https://unpkg.com/@popperjs/core@2"
= javascript_include_tag "libs/jqBootstrapValidation.js"
= javascript_include_tag "scripts.js"
- if current_page.data.extra_js
......
......@@ -88,52 +88,3 @@
}
}
/* Editor styling */
.editor {
max-width: 700px;
margin-left: auto;
margin-right: auto;
font-family: Lora, sans-serif;
font-size: 21px;
line-height: 1.58;
}
.editor:focus {
outline: 0;
}
i {
width: 1.4em;
text-align: center;
}
hr {
border: 0;
}
hr::before {
content: ". . .";
color: rgba(0, 0, 0, 0.68);
text-align: center;
display: block;
width: 100%;
font-size: 1.5em;
position: relative;
top: -7px;
letter-spacing: 0.1em;
}
a {
text-decoration: none;
color: inherit;
cursor: pointer;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.68) 50%,
rgba(0, 0, 0, 0) 50%
);
background-repeat: repeat-x;
background-size: 2px 0.1em;
background-position: 0 1.07em;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment