diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index f1c78abc77..b0458d513c 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -1800,6 +1800,28 @@ aside .panel-body { font-size: 14px; } +/* Contact avatar click card */ +.userinfo.click-card { + position: relative; +} + +.userinfo.click-card > *:hover:after { + content: '⌄'; + color: #bebebe; + font-size: 1em; + font-weight: bold; + background-color: #ffffff; + text-align: center; + line-height: 40%; + position: absolute; + top: 0; + left: 0; + width: 33%; + height: 33%; + opacity: .8; + border-radius: 0 0 40% 0; +} + /* The lock symbol popup */ #panel { position: absolute; diff --git a/view/theme/frio/js/hovercard.js b/view/theme/frio/js/hovercard.js index 0236d9a075..464c7e06e1 100644 --- a/view/theme/frio/js/hovercard.js +++ b/view/theme/frio/js/hovercard.js @@ -8,18 +8,53 @@ * */ $(document).ready(function () { - // Elements with the class "userinfo" will get a hover-card. - // Note that this elements does need a href attribute which links to - // a valid profile url - $("body").on("mouseover", ".userinfo, .wall-item-responses a, .wall-item-bottom .mention a", function (e) { + let $body = $('body'); + // Prevents normal click action on click hovercard elements + $body.on('click', '.userinfo.click-card', function (e) { + e.preventDefault(); + }); + // This event listener needs to be declared before the one that removes + // all cards so that we can stop the immediate propagation of the event + // Since the manual popover appears instantly and the hovercard removal is + // on a 100ms delay, leaving event propagation immediately hides any click hovercard + $body.on('mousedown', '.userinfo.click-card', function (e) { + e.stopImmediatePropagation(); let timeNow = new Date().getTime(); - removeAllHovercards(e, timeNow); - let contact_url = false; + + let contactUrl = false; let targetElement = $(this); // get href-attribute if (targetElement.is('[href]')) { - contact_url = targetElement.attr('href'); + contactUrl = targetElement.attr('href'); + } else { + return true; + } + + // no hovercard for anchor links + if (contactUrl.substring(0, 1) === '#') { + return true; + } + + openHovercard(targetElement, contactUrl, timeNow); + }); + + // hover cards should be removed very easily, e.g. when any of these events happens + $body.on('mouseleave touchstart scroll mousedown submit keydown', function (e) { + // remove hover card only for desktiop user, since on mobile we open the hovercards + // by click event insteadof hover + removeAllHovercards(e, new Date().getTime()); + }); + + $body.on('mouseover', '.userinfo.hover-card, .wall-item-responses a, .wall-item-bottom .mention a', function (e) { + let timeNow = new Date().getTime(); + removeAllHovercards(e, timeNow); + let contactUrl = false; + let targetElement = $(this); + + // get href-attribute + if (targetElement.is('[href]')) { + contactUrl = targetElement.attr('href'); } else { return true; } @@ -30,88 +65,34 @@ $(document).ready(function () { } // no hovercard for anchor links - if (contact_url.substring(0, 1) === '#') { + if (contactUrl.substring(0, 1) === '#') { return true; } targetElement.attr('data-awaiting-hover-card', timeNow); - // store the title in an other data attribute beause bootstrap - // popover destroys the title.attribute. We can restore it later - let title = targetElement.attr("title"); - targetElement.attr({"data-orig-title": title, title: ""}); - - // if the device is a mobile open the hover card by click and not by hover - if (typeof is_mobile != "undefined") { - targetElement[0].removeAttribute("href"); - var hctrigger = 'click'; - } else { - var hctrigger = 'manual'; - } - - // Timeout until the hover-card does appear + // Delay until the hover-card does appear setTimeout(function () { if ( - targetElement.is(":hover") + targetElement.is(':hover') && parseInt(targetElement.attr('data-awaiting-hover-card'), 10) === timeNow && $('.hovercard').length === 0 - ) { // no card if there already is one open - // get an additional data atribute if the card is active - targetElement.attr('data-hover-card-active', timeNow); - // get the whole html content of the hover card and - // push it to the bootstrap popover - getHoverCardContent(contact_url, function (data) { - if (data) { - targetElement.popover({ - html: true, - placement: function () { - // Calculate the placement of the the hovercard (if top or bottom) - // The placement depence on the distance between window top and the element - // which triggers the hover-card - var get_position = $(targetElement).offset().top - $(window).scrollTop(); - if (get_position < 270) { - return "bottom"; - } - return "top"; - }, - trigger: hctrigger, - template: '
', - content: data, - container: "body", - sanitizeFn: function (content) { - return DOMPurify.sanitize(content) - }, - }).popover('show'); - } - }); + ) { + openHovercard(targetElement, contactUrl, timeNow); } }, 500); - }).on("mouseleave", ".userinfo, .wall-item-responses a, .wall-item-bottom .mention a", function (e) { // action when mouse leaves the hover-card - var timeNow = new Date().getTime(); - // copy the original title to the title atribute - var title = $(this).attr("data-orig-title"); - $(this).attr({"data-orig-title": "", title: title}); - removeAllHovercards(e, timeNow); - }); - - // hover cards should be removed very easily, e.g. when any of these events happen - $('body').on("mouseleave touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup", function (e) { - // remove hover card only for desktiop user, since on mobile we openen the hovercards - // by click event insteadof hover - if (typeof is_mobile == "undefined") { - var timeNow = new Date().getTime(); - removeAllHovercards(e, timeNow); - } + }).on('mouseleave', '.userinfo.hover-card, .wall-item-responses a, .wall-item-bottom .mention a', function (e) { // action when mouse leaves the hover-card + removeAllHovercards(e, new Date().getTime()); }); // if we're hovering a hover card, give it a class, so we don't remove it - $('body').on('mouseover', '.hovercard', function (e) { + $body.on('mouseover', '.hovercard', function (e) { $(this).addClass('dont-remove-card'); }); - $('body').on('mouseleave', '.hovercard', function (e) { + $body.on('mouseleave', '.hovercard', function (e) { $(this).removeClass('dont-remove-card'); - $(this).popover("hide"); + $(this).popover('hide'); }); }); // End of $(document).ready @@ -120,19 +101,61 @@ function removeAllHovercards(event, priorTo) { // don't remove hovercards until after 100ms, so user have time to move the cursor to it (which gives it the dont-remove-card class) setTimeout(function () { $.each($('.hovercard'), function () { - var title = $(this).attr("data-orig-title"); + let title = $(this).attr('data-orig-title'); // don't remove card if it was created after removeAllhoverCards() was called if ($(this).data('card-created') < priorTo) { // don't remove it if we're hovering it right now! if (!$(this).hasClass('dont-remove-card')) { - $('[data-hover-card-active="' + $(this).data('card-created') + '"]').removeAttr('data-hover-card-active'); - $(this).popover("hide"); + let $handle = $('[data-hover-card-active="' + $(this).data('card-created') + '"]'); + $handle.removeAttr('data-hover-card-active'); + + // Restoring the popover handle title + let title = $handle.attr('data-orig-title'); + $handle.attr({'data-orig-title': '', title: title}); + + $(this).popover('hide'); } } }); }, 100); } +function openHovercard(targetElement, contactUrl, timeNow) { + // store the title in a data attribute because Bootstrap + // popover destroys the title attribute. + let title = targetElement.attr('title'); + targetElement.attr({'data-orig-title': title, title: ''}); + + // get an additional data atribute if the card is active + targetElement.attr('data-hover-card-active', timeNow); + // get the whole html content of the hover card and + // push it to the bootstrap popover + getHoverCardContent(contactUrl, function (data) { + if (data) { + targetElement.popover({ + html: true, + placement: function () { + // Calculate the placement of the the hovercard (if top or bottom) + // The placement depence on the distance between window top and the element + // which triggers the hover-card + let get_position = $(targetElement).offset().top - $(window).scrollTop(); + if (get_position < 270) { + return 'bottom'; + } + return 'top'; + }, + trigger: 'manual', + template: '
', + content: data, + container: 'body', + sanitizeFn: function (content) { + return DOMPurify.sanitize(content) + }, + }).popover('show'); + } + }); +} + getHoverCardContent.cache = {}; function getHoverCardContent(contact_url, callback) { @@ -152,7 +175,7 @@ function getHoverCardContent(contact_url, callback) { } $.ajax({ - url: baseurl + "/contact/hovercard", + url: baseurl + '/contact/hovercard', data: postdata, success: function (data, textStatus, request) { getHoverCardContent.cache[nurl] = data; diff --git a/view/theme/frio/templates/event_stream_item.tpl b/view/theme/frio/templates/event_stream_item.tpl index 9264e9d2e3..2f2af2732e 100644 --- a/view/theme/frio/templates/event_stream_item.tpl +++ b/view/theme/frio/templates/event_stream_item.tpl @@ -27,7 +27,7 @@ {{/if}}
- {{$author_name}} + {{$author_name}}
{{if $location.map}}
{{$location.map nofilter}}
diff --git a/view/theme/frio/templates/nav.tpl b/view/theme/frio/templates/nav.tpl index 4b515efcd1..a2b5106a61 100644 --- a/view/theme/frio/templates/nav.tpl +++ b/view/theme/frio/templates/nav.tpl @@ -285,7 +285,7 @@