var each = (a,c)=> Array.prototype.forEach.call(a, c); var node = elem => elem instanceof window.$ ? elem[0] : elem; var smrm = elem => getComputedStyle(node(elem)).animationName!=="none"?node(elem).addEventListener('animationend',node(elem).remove):node(elem).remove(); function beyond(node) { var rect = node.getBoundingClientRect(); return ( (rect.x + rect.width) < 0 || (rect.y + rect.height) < 0 || (rect.x > window.innerWidth || rect.y > window.innerHeight) ); } var popup = 'popup', popupA = 'popupA', popupF = 'popupF', hilite = 'highlighted' ; var nav = { setHighlight: (/*HTMLElement | JQuery*/ post, /*boolean*/ status) => { switch (status) { case true: node(post).classList.add(hilite); break; case false: node(post).classList.remove(hilite); break; case undefined: node(post).classList.contains(hilite) ? node(post).classList.add(hilite) : node(post).classList.add(hilite) ; break; default: break; } }, clonePost: (clonedPost, parent, rm) => { switch (rm) { case true: case undefined: clonedPost.attr('id', clonedPost.attr('id')+'_copy'); clonedPost.addClass(popup); clonedPost.addClass(popupA); getComputedStyle(node(clonedPost)).animationName != 'none' ? clonedPost.on( 'animationend', e => e.target.classList.remove(popupA) ) : clonedPost.removeClass(popupA) ; parent.append(clonedPost); break; case false: clonedPost.addClass(popupF); smrm(clonedPost); break; default: break; } return clonedPost; }, } function enableFastNavigation() { // Highlights and popups function highlightOnLinkEnter(/*JQuery*/ post, /*JQuery*/ link) { nav.setHighlight(post, true); link.on('mouseleave', function mouseLeave() { nav.setHighlight(post, false); link.off('mouseleave', mouseLeave); }); } function popup(/*JQuery*/ clonedPost, /*JQuery*/ link) { var popupDeletionTimer = null; var parentPost = link.parent().parent(); /* Callbacks * W: Each one assumes that clonedPost and link are valid JQuery objects.*/ const cbs = { _initiateCountdown: () => { popupDeletionTimer = setTimeout( () => { nav.clonePost(clonedPost, parentPost, false); link.removeAttr('locked'); }, 1000 ); }, /* Postlink mouseleave callback. */ linkLeave: function linkLeave(e) { cbs._initiateCountdown(); clonedPost.on('mouseenter', cbs.popupEnter); link.off('mouseleave'); }, /* Fires when cursor leaves a popup. */ popupLeave: function postLeave() { cbs._initiateCountdown(); clonedPost.on('mouseenter', cbs.popupEnter); }, /* Fires if cursor returns onto a popup before postDeletionTimer's time is up. Otherwise popup will be removed from document. */ popupEnter: function postEnter() { clearTimeout(popupDeletionTimer); postDeletionTimer = null; clonedPost.off('mouseenter', popupEnter); } }; if (link.attr('locked')) return; link.attr('locked', true); nav.clonePost(clonedPost, parentPost); let _l = node(link), _ld = _l.getBoundingClientRect(); clonedPost .css('position', 'absolute') .css('left', _l.offsetLeft + 'px') .css('top', _l.offsetTop + _ld.height + 'px') ; link.on('mouseleave', cbs.linkLeave); clonedPost.on('mouseleave', cbs.popupLeave); } function show(e) { let link = $(e.target), numb = link.text().substr(2), post = $(`#reply${numb}`) || null; if (node(post)) { if( beyond(node(post)) ) { let _embed = node(post).cloneNode(true); each(_embed.children, item => { if (item.classList.contains(popup)) item.remove(); }); popup($(_embed), link); } else { highlightOnLinkEnter(post, link); } } } $(document).on('mouseenter', '.message a[href*="res"]', show); } document.addEventListener('DOMContentLoaded', enableFastNavigation);