Skip to content

Instantly share code, notes, and snippets.

@ambrosiora
Created October 12, 2019 19:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ambrosiora/6d5d0501c51caa03749bc040e57cdf34 to your computer and use it in GitHub Desktop.
Save ambrosiora/6d5d0501c51caa03749bc040e57cdf34 to your computer and use it in GitHub Desktop.
$(document).ready(function() {
initHighlights();
});
var currentAnchor = null;
var tooltipPointerPositions = {
left: 46,
width: 14
};
var setCurrentAnchor = function(val) {
currentAnchor = val;
}
var hasTooltip = function() {
return ($('.tooltip-container').length == 1);
}
var canShowTooltip = function(selection) {
if (hasTooltip()) {
return false;
}
if (selection.type != 'Range' || selection.rangeCount <= 0) {
return false;
}
var range = selection.getRangeAt(0);
var start_parent = $(range.startContainer.parentNode);
var end_parent = $(range.endContainer.parentNode);
if (start_parent.closest('p').is(':not(.highlightable)')) {
return false;
}
if (start_parent.closest('p')[0] != end_parent.closest('p')[0]) {
return false;
}
return true;
}
var getAnchorType = function(anchor) {
var ret = false;
if (anchor) {
ret = anchor.constructor.name;
}
return ret;
}
var getTooltipTemplate = function() {
return '<div class="tooltip-container" tabindex=-1>\
<div class="tooltip-body";>\
<div class="tooltip-animation">\
<div class="tooltip-content">\
<div class="tooltip-adjuster">\
<div class="tooltip-item-container">\
<div class="tooltip-item">\
<button class="btnHighlight hyellow" data-hcolor="hyellow">\
<svg width="25" height="25" viewBox="0 0 25 25"><path d="M13.7 15.96l5.2-9.38-4.72-2.62-5.2 9.38 4.72 2.62zm-.5.89l-1.3 2.37-1.26.54-.7 1.26-3.8-.86 1.23-2.22-.2-1.35 1.31-2.37 4.73 2.62z" fill-rule="evenodd"></path></svg>\
</button>\
</div>\
</div>\
<div class="tooltip-item-container">\
<div class="tooltip-item">\
<button class="btnHighlight hblue" data-hcolor="hblue">\
<svg width="25" height="25" viewBox="0 0 25 25"><path d="M13.7 15.96l5.2-9.38-4.72-2.62-5.2 9.38 4.72 2.62zm-.5.89l-1.3 2.37-1.26.54-.7 1.26-3.8-.86 1.23-2.22-.2-1.35 1.31-2.37 4.73 2.62z" fill-rule="evenodd"></path></svg>\
</button>\
</div>\
</div>\
</div>\
<div class="tooltip-pointer" style="left: ' + tooltipPointerPositions.left + 'px;"></div>\
</div>\
</div>\
</div>\
</div>';
}
var getTooltipPlacement = function(clientRect) {
var bodyClientRect = document.body.getBoundingClientRect();
var tooltipHeight = $('.tooltip-body')[0].getClientRects()[0].height;
var computedLeft = (clientRect.left + (clientRect.width / 2)) - (tooltipPointerPositions.left + (tooltipPointerPositions.width / 2));
var computedTop = ((clientRect.top - tooltipHeight) - bodyClientRect.top) - 1;
return {
left: computedLeft,
top: computedTop,
tpClass: 'tp-down'
};
}
var tryShowTooltip = function(anchor) {
var clientRect = null;
removeTooltip();
switch (getAnchorType(anchor)) {
case 'Selection':
if (!canShowTooltip(anchor)) {
return false;
}
var range = anchor.getRangeAt(0);
clientRect = range.getClientRects()[0];
break;
case 'HTMLElement':
clientRect = anchor.getClientRects()[0];
break;
default:
return false;
}
setCurrentAnchor(anchor);
var html = getTooltipTemplate();
$('body').append(html);
var tooltipPlacement = getTooltipPlacement(clientRect);
var tooltipContainer = $('.tooltip-container');
tooltipContainer.find('.tooltip-body').css('transform', 'translate3d(' + tooltipPlacement.left + 'px, ' + tooltipPlacement.top + 'px, 0px)');
tooltipContainer.find('.tooltip-pointer').removeClass('tp-down, tp-up').addClass(tooltipPlacement.tpClass);
}
var removeTooltip = function() {
$('.tooltip-container').remove();
setCurrentAnchor(null);
}
var initHighlights = function() {
//buscar o json
/*mock resultado request recuperar seleções*/
$.ajax({
url: 'http://www.mocky.io/v2/5da207bb2f00007b00f418fe',
method: 'GET',
dataType: 'jsonp'
}).done(function(data, textStatus, jqXHR) {
$.each(data, function(index, item){
var selection = addSelection(item);
addHighlight(selection, item.highlightClassColor);
});
}).fail(function(jqXHR, textStatus, errorThrown) {
alert('Desculpe, não foi possível carregar suas marcações')
});
}
var addSelection = function (item) {
var el = $('#'+item.id);
if (!el || el.length == 0) {
return false;
}
el = el[0];
var range = document.createRange();
range.setStart(el.firstChild, item.startOffset);
range.setEnd(el.firstChild, item.endOffset);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
return selection;
}
var removeHighlight = function (currentAnchor) {
var p = $(currentAnchor).closest('p');
innerHtml = $(currentAnchor).html();
$(currentAnchor).replaceWith(innerHtml);
//Normalizando html
p.html(p.html().replace(/(\r\n|\n|\r)/gm, " "));
}
var addHighlight = function (currentAnchor, highlightClassColor) {
highlightClassColor = highlightClassColor || 'hyellow';
var className = 'highlightedText ' + highlightClassColor;
var elementMarkerName = 'mark';
if (currentAnchor.type != 'Range') {
return false;
}
var text = currentAnchor.toString();
var range = currentAnchor.getRangeAt(0);
var start_parent = $(range.startContainer.parentNode);
var end_parent = $(range.endContainer.parentNode);
//Não é um elemento highlightable ou Começou em um parágrafo e terminou em outro (não pode, igual medium não deixa)
if (start_parent.closest('p').is(':not(.highlightable)') || start_parent.closest('p')[0] != end_parent.closest('p')[0]) {
currentAnchor.removeAllRanges();
return false;
}
/*Começou a selecionar por cima de uma seleção*/
if (range.startOffset > 0 && start_parent.hasClass(className)) {
// var prefix = '<' + elementMarkerName + ' class="' + className + '">' + start_parent.html().substr(0, currentAnchor.focusOffset);
prefix = '<' + elementMarkerName + ' class="' + className + '">' + start_parent.html().substr(0, range.startOffset);
range.deleteContents();
var suffix = /*'<' + elementMarkerName + ' class="' + className + '">' +*/ text + '</' + elementMarkerName + '>';
start_parent.replaceWith(prefix + suffix);
} else {
range.deleteContents();
range.insertNode($('<' + elementMarkerName + ' class="' + className + '">' + text + '</' + elementMarkerName + '>')[0]);
//Remove all empty elements (deleteContents leaves the HTML in place)
$(elementMarkerName + '.' + className + ':empty').remove();
}
//retirando a seleção após executar as coisas
currentAnchor.removeAllRanges();
}
$('body').on('mouseup touchend', function(e) {
if ($(e.target).closest('.tooltip-container').length == 1 || (window.getSelection().type != 'Range' && $(e.target).is('mark.highlightedText'))) {
// if ($(e.target).closest('.tooltip-container').length == 1) {
e.preventDefault();
return false;
}
if (e.cancelable) {
e.preventDefault();
}
var selection = window.getSelection();
tryShowTooltip(selection);
});
$('body').on('click', '.btnHighlight', function(e) {
switch (getAnchorType(currentAnchor)) {
case 'Selection':
addHighlight(currentAnchor, $(this).data('hcolor'));
break;
case 'HTMLElement':
removeHighlight(currentAnchor);
break;
default:
return false;
}
removeTooltip();
});
$('body').on('click', 'mark.highlightedText', function(e) {
if (window.getSelection().type != 'Range') {
tryShowTooltip(this);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment