]> git.mxchange.org Git - friendica.git/blob - view/theme/frio/js/hovercard.js
Merge pull request #9506 from annando/test-mysql-no-pdo
[friendica.git] / view / theme / frio / js / hovercard.js
1 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later
2 /*
3  * The javascript for friendicas hovercard. Bootstraps popover is needed.
4  *
5  * Much parts of the code are from Hannes Mannerheims <h@nnesmannerhe.im>
6  * qvitter code (https://github.com/hannesmannerheim/qvitter)
7  *
8  * It is licensed under the GNU Affero General Public License <http://www.gnu.org/licenses/>
9  *
10  */
11 $(document).ready(function () {
12         let $body = $('body');
13         // Prevents normal click action on click hovercard elements
14         $body.on('click', '.userinfo.click-card', function (e) {
15                 e.preventDefault();
16         });
17         // This event listener needs to be declared before the one that removes
18         // all cards so that we can stop the immediate propagation of the event
19         // Since the manual popover appears instantly and the hovercard removal is
20         // on a 100ms delay, leaving event propagation immediately hides any click hovercard
21         $body.on('mousedown', '.userinfo.click-card', function (e) {
22                 e.stopImmediatePropagation();
23                 let timeNow = new Date().getTime();
24
25                 let contactUrl = false;
26                 let targetElement = $(this);
27
28                 // get href-attribute
29                 if (targetElement.is('[href]')) {
30                         contactUrl = targetElement.attr('href');
31                 } else {
32                         return true;
33                 }
34
35                 // no hovercard for anchor links
36                 if (contactUrl.substring(0, 1) === '#') {
37                         return true;
38                 }
39
40                 openHovercard(targetElement, contactUrl, timeNow);
41         });
42
43         // hover cards should be removed very easily, e.g. when any of these events happens
44         $body.on('mouseleave touchstart scroll mousedown submit keydown', function (e) {
45                 // remove hover card only for desktiop user, since on mobile we open the hovercards
46                 // by click event insteadof hover
47                 removeAllHovercards(e, new Date().getTime());
48         });
49
50         $body.on('mouseover', '.userinfo.hover-card, .wall-item-responses a, .wall-item-bottom .mention a', function (e) {
51                 let timeNow = new Date().getTime();
52                 removeAllHovercards(e, timeNow);
53                 let contactUrl = false;
54                 let targetElement = $(this);
55
56                 // get href-attribute
57                 if (targetElement.is('[href]')) {
58                         contactUrl = targetElement.attr('href');
59                 } else {
60                         return true;
61                 }
62
63                 // no hover card if the element has the no-hover-card class
64                 if (targetElement.hasClass('no-hover-card')) {
65                         return true;
66                 }
67
68                 // no hovercard for anchor links
69                 if (contactUrl.substring(0, 1) === '#') {
70                         return true;
71                 }
72
73                 targetElement.attr('data-awaiting-hover-card', timeNow);
74
75                 // Delay until the hover-card does appear
76                 setTimeout(function () {
77                         if (
78                                 targetElement.is(':hover')
79                                 && parseInt(targetElement.attr('data-awaiting-hover-card'), 10) === timeNow
80                                 && $('.hovercard').length === 0
81                         ) {
82                                 openHovercard(targetElement, contactUrl, timeNow);
83                         }
84                 }, 500);
85         }).on('mouseleave', '.userinfo.hover-card, .wall-item-responses a, .wall-item-bottom .mention a', function (e) { // action when mouse leaves the hover-card
86                 removeAllHovercards(e, new Date().getTime());
87         });
88
89         // if we're hovering a hover card, give it a class, so we don't remove it
90         $body.on('mouseover', '.hovercard', function (e) {
91                 $(this).addClass('dont-remove-card');
92         });
93
94         $body.on('mouseleave', '.hovercard', function (e) {
95                 $(this).removeClass('dont-remove-card');
96                 $(this).popover('hide');
97         });
98 }); // End of $(document).ready
99
100 // removes all hover cards
101 function removeAllHovercards(event, priorTo) {
102         // 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)
103         setTimeout(function () {
104                 $.each($('.hovercard'), function () {
105                         let title = $(this).attr('data-orig-title');
106                         // don't remove card if it was created after removeAllhoverCards() was called
107                         if ($(this).data('card-created') < priorTo) {
108                                 // don't remove it if we're hovering it right now!
109                                 if (!$(this).hasClass('dont-remove-card')) {
110                                         let $handle = $('[data-hover-card-active="' + $(this).data('card-created') + '"]');
111                                         $handle.removeAttr('data-hover-card-active');
112
113                                         // Restoring the popover handle title
114                                         let title = $handle.attr('data-orig-title');
115                                         $handle.attr({'data-orig-title': '', title: title});
116
117                                         $(this).popover('hide');
118                                 }
119                         }
120                 });
121         }, 100);
122 }
123
124 function openHovercard(targetElement, contactUrl, timeNow) {
125         // store the title in a data attribute because Bootstrap
126         // popover destroys the title attribute.
127         let title = targetElement.attr('title');
128         targetElement.attr({'data-orig-title': title, title: ''});
129
130         // get an additional data atribute if the card is active
131         targetElement.attr('data-hover-card-active', timeNow);
132         // get the whole html content of the hover card and
133         // push it to the bootstrap popover
134         getHoverCardContent(contactUrl, function (data) {
135                 if (data) {
136                         targetElement.popover({
137                                 html: true,
138                                 placement: function () {
139                                         // Calculate the placement of the the hovercard (if top or bottom)
140                                         // The placement depence on the distance between window top and the element
141                                         // which triggers the hover-card
142                                         let get_position = $(targetElement).offset().top - $(window).scrollTop();
143                                         if (get_position < 270) {
144                                                 return 'bottom';
145                                         }
146                                         return 'top';
147                                 },
148                                 trigger: 'manual',
149                                 template: '<div class="popover hovercard" data-card-created="' + timeNow + '"><div class="arrow"></div><div class="popover-content hovercard-content"></div></div>',
150                                 content: data,
151                                 container: 'body',
152                                 sanitizeFn: function (content) {
153                                         return DOMPurify.sanitize(content)
154                                 },
155                         }).popover('show');
156                 }
157         });
158 }
159
160 getHoverCardContent.cache = {};
161
162 function getHoverCardContent(contact_url, callback) {
163         let postdata = {
164                 url: contact_url,
165         };
166
167         // Normalize and clean the profile so we can use a standardized url
168         // as key for the cache
169         let nurl = cleanContactUrl(contact_url).normalizeLink();
170
171         // If the contact is already in the cache use the cached result instead
172         // of doing a new ajax request
173         if (nurl in getHoverCardContent.cache) {
174                 callback(getHoverCardContent.cache[nurl]);
175                 return;
176         }
177
178         $.ajax({
179                 url: baseurl + '/contact/hovercard',
180                 data: postdata,
181                 success: function (data, textStatus, request) {
182                         getHoverCardContent.cache[nurl] = data;
183                         callback(data);
184                 },
185         });
186 }
187 // @license-end