diff --git a/mod/network.php b/mod/network.php index 2d9a829ce4..ea98004cb1 100644 --- a/mod/network.php +++ b/mod/network.php @@ -358,7 +358,7 @@ function networkConversation($a, $items, $mode, $update, $ordering = '') return $o; } -function network_content(App $a, $update = 0) +function network_content(App $a, $update = 0, $parent = 0) { if (!local_user()) { return Login::form(); @@ -385,7 +385,7 @@ function network_content(App $a, $update = 0) if ($nouveau) { $o = networkFlatView($a, $update); } else { - $o = networkThreadedView($a, $update); + $o = networkThreadedView($a, $update, $parent); } return $o; @@ -476,7 +476,7 @@ function networkFlatView(App $a, $update = 0) * @param integer $update Used for the automatic reloading * @return string HTML of the network content in flat view */ -function networkThreadedView(App $a, $update = 0) +function networkThreadedView(App $a, $update, $parent) { // Rawmode is used for fetching new content at the end of the page $rawmode = (isset($_GET['mode']) AND ( $_GET['mode'] == 'raw')); @@ -759,17 +759,19 @@ function networkThreadedView(App $a, $update = 0) // Fetch a page full of parent items for this page if ($update) { - if (Config::get('system', 'like_no_comment')) { - $sql_extra4 = " AND `item`.`verb` = '" . ACTIVITY_POST . "'"; + if (!empty($parent)) { +logger('Blubb: '.$parent); + $sql_extra4 = "`item`.`id` = ".intval($parent); } else { - $sql_extra4 = ''; + $sql_extra4 = "`item`.`unseen`"; } + $r = q("SELECT `item`.`parent-uri` AS `uri`, `item`.`parent` AS `item_id`, $sql_order AS `order_date` FROM `item` $sql_post_table STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` $sql_extra4 - AND NOT `item`.`moderated` AND `item`.`unseen` + WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` + AND NOT `item`.`moderated` AND $sql_extra4 $sql_extra3 $sql_extra $sql_range $sql_nets ORDER BY `order_date` DESC LIMIT 100", intval(local_user()) diff --git a/mod/update_network.php b/mod/update_network.php index fddbeba397..88b6fa2ee3 100644 --- a/mod/update_network.php +++ b/mod/update_network.php @@ -12,14 +12,15 @@ require_once "mod/network.php"; function update_network_content(App $a) { - $profile_uid = intval($_GET["p"]); + $profile_uid = intval($_GET['p']); + $parent = intval($_GET['item']); header("Content-type: text/html"); echo "\r\n"; echo "
"; if (!PConfig::get($profile_uid, "system", "no_auto_update") || ($_GET["force"] == 1)) { - $text = network_content($a, $profile_uid); + $text = network_content($a, $profile_uid, $parent); } else { $text = ""; } diff --git a/view/js/main.js b/view/js/main.js index 77c240f373..2d3d132c4a 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -1,755 +1,728 @@ - function resizeIframe(obj) { - //obj.style.height = 0; - _resizeIframe(obj, 0); - } +function resizeIframe(obj) { + _resizeIframe(obj, 0); +} - function _resizeIframe(obj, desth) { - var h = obj.style.height; - var ch = obj.contentWindow.document.body.scrollHeight; - if (h == (ch + 'px')) { +function _resizeIframe(obj, desth) { + var h = obj.style.height; + var ch = obj.contentWindow.document.body.scrollHeight; + + if (h == (ch + 'px')) { + return; + } + if (desth == ch && ch>0) { + obj.style.height = ch + 'px'; + } + setTimeout(_resizeIframe, 100, obj, ch); +} + +function openClose(theID) { + if (document.getElementById(theID).style.display == "block") { + document.getElementById(theID).style.display = "none" + } else { + document.getElementById(theID).style.display = "block" + } +} + +function openMenu(theID) { + var el = document.getElementById(theID) + + if (el) { + el.style.display = "block"; + } +} + +function closeMenu(theID) { + var el = document.getElementById(theID) + + if (el) { + el.style.display = "none"; + } +} + +function decodeHtml(html) { + var txt = document.createElement("textarea"); + + txt.innerHTML = html; + return txt.value; +} + +var src = null; +var prev = null; +var livetime = null; +var force_update = false; +var update_item = null; +var stopped = false; +var totStopped = false; +var timer = null; +var pr = 0; +var liking = 0; +var in_progress = false; +var langSelect = false; +var commentBusy = false; +var last_popup_menu = null; +var last_popup_button = null; +var lockLoadContent = false; + +$(function() { + $.ajaxSetup({cache: false}); + + /* setup comment textarea buttons */ + /* comment textarea buttons needs some "data-*" attributes to work: + * data-role="insert-formatting" : to mark the element as a formatting button + * data-bbcode="" : name of the bbcode element to insert. insertFormatting() will insert it as "[name][/name]" + * data-id="" : id of the comment, used to find other comment-related element, like the textarea + * */ + $('body').on('click','[data-role="insert-formatting"]', function(e) { + e.preventDefault(); + var o = $(this); + var bbcode = o.data('bbcode'); + var id = o.data('id'); + if (bbcode=="img") { + Dialog.doImageBrowser("comment", id); return; } - if (desth == ch && ch>0) { - obj.style.height = ch + 'px'; - } - setTimeout(_resizeIframe, 100, obj, ch); - } - - function openClose(theID) { - if(document.getElementById(theID).style.display == "block") { - document.getElementById(theID).style.display = "none" - } - else { - document.getElementById(theID).style.display = "block" - } - } - - function openMenu(theID) { - var el = document.getElementById(theID) - if (el) { - el.style.display = "block"; - } - } - - function closeMenu(theID) { - var el = document.getElementById(theID) - if (el) { - el.style.display = "none"; - } - } - - function decodeHtml(html) { - var txt = document.createElement("textarea"); - txt.innerHTML = html; - return txt.value; - } - - - var src = null; - var prev = null; - var livetime = null; - var force_update = false; - var stopped = false; - var totStopped = false; - var timer = null; - var pr = 0; - var liking = 0; - var in_progress = false; - var langSelect = false; - var commentBusy = false; - var last_popup_menu = null; - var last_popup_button = null; - var lockLoadContent = false; - - $(function() { - $.ajaxSetup({cache: false}); - - /* setup comment textarea buttons */ - /* comment textarea buttons needs some "data-*" attributes to work: - * data-role="insert-formatting" : to mark the element as a formatting button - * data-bbcode="" : name of the bbcode element to insert. insertFormatting() will insert it as "[name][/name]" - * data-id="" : id of the comment, used to find other comment-related element, like the textarea - * */ - $('body').on('click','[data-role="insert-formatting"]', function(e) { - e.preventDefault(); - var o = $(this); - var bbcode = o.data('bbcode'); - var id = o.data('id'); - if (bbcode=="img") { - Dialog.doImageBrowser("comment", id); - return; - } - insertFormatting(bbcode, id); - }); - - /* event from comment textarea button popups */ - /* insert returned bbcode at cursor position or replace selected text */ - $("body").on("fbrowser.image.comment", function(e, filename, bbcode, id) { - $.colorbox.close(); - var textarea = document.getElementById("comment-edit-text-" +id); - var start = textarea.selectionStart; - var end = textarea.selectionEnd; - textarea.value = textarea.value.substring(0, start) + bbcode + textarea.value.substring(end, textarea.value.length); - $(textarea).trigger('change'); - }); - - - - /* setup onoff widgets */ - $(".onoff input").each(function(){ - val = $(this).val(); - id = $(this).attr("id"); - $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden"); - - }); - $(".onoff > a").click(function(event){ - event.preventDefault(); - var input = $(this).siblings("input"); - var val = 1-input.val(); - var id = input.attr("id"); - $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden"); - $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden"); - input.val(val); - }); - - /* popup menus */ - function close_last_popup_menu() { - if(last_popup_menu) { - last_popup_menu.hide(); - last_popup_menu.off('click', function(e) {e.stopPropagation()}); - last_popup_button.removeClass("selected"); - last_popup_menu = null; - last_popup_button = null; - } - } - $('a[rel^="#"]').click(function(e){ - e.preventDefault(); - var parent = $(this).parent(); - var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id')); - close_last_popup_menu(); - if(isSelected) return false; - menu = $( $(this).attr('rel') ); - e.preventDefault(); - e.stopPropagation(); - if (menu.attr('popup')=="false") return false; - parent.toggleClass("selected"); - menu.toggle(); - if (menu.css("display") == "none") { - last_popup_menu = null; - last_popup_button = null; - } else { - last_popup_menu = menu; - last_popup_menu.on('click', function(e) {e.stopPropagation()}); - last_popup_button = parent; - $('#nav-notifications-menu').perfectScrollbar('update'); - } - return false; - }); - $('html').click(function() { - close_last_popup_menu(); - }); - - // fancyboxes - $("a.popupbox").colorbox({ - 'inline' : true, - 'transition' : 'elastic', - 'maxWidth' : '100%' - }); - $("a.ajax-popupbox").colorbox({ - 'transition' : 'elastic', - 'maxWidth' : '100%' - }); - - /* notifications template */ - var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html()); - var notifications_all = unescape($('
').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack - var notifications_mark = unescape($('
').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack - var notifications_empty = unescape($("#nav-notifications-menu").html()); - - /* enable perfect-scrollbars for different elements */ - $('#nav-notifications-menu, aside').perfectScrollbar(); - - /* nav update event */ - $('nav').bind('nav-update', function(e, data){ - var invalid = data.invalid || 0; - if(invalid == 1) { window.location.href=window.location.href } - - ['net', 'home', 'intro', 'mail', 'events', 'birthdays', 'notify'].forEach(function(type) { - var number = data[type]; - if (number == 0) { - number = ''; - $('#' + type + '-update').removeClass('show'); - } else { - $('#' + type + '-update').addClass('show'); - } - $('#' + type + '-update').text(number); - }); - - var intro = data['intro']; - if(intro == 0) { intro = ''; $('#intro-update-li').removeClass('show') } else { $('#intro-update-li').addClass('show') } - $('#intro-update-li').html(intro); - - var mail = data['mail']; - if(mail == 0) { mail = ''; $('#mail-update-li').removeClass('show') } else { $('#mail-update-li').addClass('show') } - $('#mail-update-li').html(mail); - - $(".sidebar-group-li .notify").removeClass("show"); - $(data.groups).each(function(key, group) { - var gid = group.id; - var gcount = group.count; - $(".group-"+gid+" .notify").addClass("show").text(gcount); - }); - - $(".forum-widget-entry .notify").removeClass("show"); - $(data.forums).each(function(key, forum) { - var fid = forum.id; - var fcount = forum.count; - $(".forum-"+fid+" .notify").addClass("show").text(fcount); - }); - - if (data.notifications.length == 0) { - $("#nav-notifications-menu").html(notifications_empty); - } else { - var nnm = $("#nav-notifications-menu"); - nnm.html(notifications_all + notifications_mark); - - var lastItemStorageKey = "notification-lastitem:" + localUser; - var notification_lastitem = parseInt(localStorage.getItem(lastItemStorageKey)); - var notification_id = 0; - - // Insert notifs into the notifications-menu - $(data.notifications).each(function(key, notif){ - var text = notif.message.format('' + notif.name + ''); - var contact = ('' + notif.name + ''); - var seenclass = (notif.seen == 1) ? "notify-seen" : "notify-unseen"; - var html = notifications_tpl.format( - notif.href, // {0} // link to the source - notif.photo, // {1} // photo of the contact - text, // {2} // preformatted text (autor + text) - notif.date, // {3} // date of notification (time ago) - seenclass, // {4} // visited status of the notification - new Date(notif.timestamp*1000), // {5} // date of notification - notif.url, // {6} // profile url of the contact - notif.message.format(contact), // {7} // preformatted html (text including author profile url) - '' // {8} // Deprecated - ); - nnm.append(html); - }); - - // Desktop Notifications - $(data.notifications.reverse()).each(function(key, e){ - notification_id = parseInt(e.timestamp); - if (notification_lastitem !== null && notification_id > notification_lastitem && Number(e.seen) === 0) { - if (getNotificationPermission() === "granted") { - var notification = new Notification(document.title, { - body: decodeHtml(e.message.replace('→ ', '').format(e.name)), - icon: e.photo, - }); - notification['url'] = e.href; - notification.addEventListener("click", function(ev){ - window.location = ev.target.url; - }); - } - } - - }); - notification_lastitem = notification_id; - localStorage.setItem(lastItemStorageKey, notification_lastitem) - - $("img[data-src]", nnm).each(function(i, el){ - // Add src attribute for images with a data-src attribute - // However, don't bother if the data-src attribute is empty, because - // an empty "src" tag for an image will cause some browsers - // to prefetch the root page of the Friendica hub, which will - // unnecessarily load an entire profile/ or network/ page - if($(el).data("src") != '') $(el).attr('src', $(el).data("src")); - }); - } - - var notif = data['notify']; - if (notif > 0){ - $("#nav-notifications-linkmenu").addClass("on"); - } else { - $("#nav-notifications-linkmenu").removeClass("on"); - } - - $(data.sysmsgs.notice).each(function(key, message){ - $.jGrowl(message, {sticky: true, theme: 'notice'}); - }); - $(data.sysmsgs.info).each(function(key, message){ - $.jGrowl(message, {sticky: false, theme: 'info', life: 5000}); - }); - - // Update the js scrollbars - $('#nav-notifications-menu').perfectScrollbar('update'); - - }); - - NavUpdate(); - // Allow folks to stop the ajax page updates with the pause/break key - $(document).keydown(function(event) { - if(event.keyCode == '8') { - var target = event.target || event.srcElement; - if (!/input|textarea/i.test(target.nodeName)) { - return false; - } - } - if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) { - event.preventDefault(); - if(stopped == false) { - stopped = true; - if (event.ctrlKey) { - totStopped = true; - } - $('#pause').html('pause'); - } else { - unpause(); - } - } else { - if (!totStopped) { - unpause(); - } - } - }); - - // Scroll to the next/previous thread when pressing J and K - $(document).keydown(function (event) { - var threads = $('.thread_level_1'); - if ((event.keyCode === 74 || event.keyCode === 75) && !$(event.target).is('textarea, input')) { - var scrollTop = $(window).scrollTop(); - if (event.keyCode === 75) { - threads = $(threads.get().reverse()); - } - threads.each(function(key, item) { - var comparison; - var top = $(item).offset().top - 100; - if (event.keyCode === 74) { - comparison = top > scrollTop + 1; - } else if (event.keyCode === 75) { - comparison = top < scrollTop - 1; - } - if (comparison) { - $('html, body').animate({ scrollTop: top }, 200); - return false; - } - }); - } - }); - - // Set an event listener for infinite scroll - if(typeof infinite_scroll !== 'undefined') { - $(window).scroll(function(e){ - if ($(document).height() != $(window).height()) { - // First method that is expected to work - but has problems with Chrome - if ($(window).scrollTop() > ($(document).height() - $(window).height() * 1.5)) - loadScrollContent(); - } else { - // This method works with Chrome - but seems to be much slower in Firefox - if ($(window).scrollTop() > (($("section").height() + $("header").height() + $("footer").height()) - $(window).height() * 1.5)) - loadScrollContent(); - } - }); - } - - + insertFormatting(bbcode, id); }); - function NavUpdate() { + /* event from comment textarea button popups */ + /* insert returned bbcode at cursor position or replace selected text */ + $("body").on("fbrowser.image.comment", function(e, filename, bbcode, id) { + $.colorbox.close(); + var textarea = document.getElementById("comment-edit-text-" +id); + var start = textarea.selectionStart; + var end = textarea.selectionEnd; + textarea.value = textarea.value.substring(0, start) + bbcode + textarea.value.substring(end, textarea.value.length); + $(textarea).trigger('change'); + }); - if (!stopped) { - var pingCmd = 'ping?format=json' + ((localUser != 0) ? '&f=&uid=' + localUser : ''); - $.get(pingCmd, function(data) { - if (data.result) { - // send nav-update event - $('nav').trigger('nav-update', data.result); + /* setup onoff widgets */ + $(".onoff input").each(function() { + val = $(this).val(); + id = $(this).attr("id"); + $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden"); + }); - // start live update - ['network', 'profile', 'community', 'notes', 'display'].forEach(function (src) { - if ($('#live-' + src).length) { - liveUpdate(src); - } - }); - if ($('#live-photos').length) { - if (liking) { - liking = 0; - window.location.href = window.location.href; - } - } - } - }) ; + $(".onoff > a").click(function(event) { + event.preventDefault(); + var input = $(this).siblings("input"); + var val = 1-input.val(); + var id = input.attr("id"); + $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden"); + $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden"); + input.val(val); + }); + + /* popup menus */ + function close_last_popup_menu() { + if (last_popup_menu) { + last_popup_menu.hide(); + last_popup_menu.off('click', function(e) {e.stopPropagation()}); + last_popup_button.removeClass("selected"); + last_popup_menu = null; + last_popup_button = null; } - timer = setTimeout(NavUpdate, updateInterval); } - - function liveUpdate(src) { - if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; } - if(($('.comment-edit-text-full').length) || (in_progress)) { - if(livetime) { - clearTimeout(livetime); - } - livetime = setTimeout(function() {liveUpdate(src)}, 5000); - return; + $('a[rel^="#"]').click(function(e) { + e.preventDefault(); + var parent = $(this).parent(); + var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id')); + close_last_popup_menu(); + if (isSelected) { + return false; } - if(livetime != null) - livetime = null; + menu = $( $(this).attr('rel') ); + e.preventDefault(); + e.stopPropagation(); + if (menu.attr('popup') == "false") { + return false; + } + parent.toggleClass("selected"); + menu.toggle(); + if (menu.css("display") == "none") { + last_popup_menu = null; + last_popup_button = null; + } else { + last_popup_menu = menu; + last_popup_menu.on('click', function(e) {e.stopPropagation()}); + last_popup_button = parent; + $('#nav-notifications-menu').perfectScrollbar('update'); + } + return false; + }); + $('html').click(function() { + close_last_popup_menu(); + }); - prev = 'live-' + src; + // fancyboxes + $("a.popupbox").colorbox({ + 'inline' : true, + 'transition' : 'elastic', + 'maxWidth' : '100%' + }); + $("a.ajax-popupbox").colorbox({ + 'transition' : 'elastic', + 'maxWidth' : '100%' + }); - in_progress = true; + /* notifications template */ + var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html()); + var notifications_all = unescape($('
').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack + var notifications_mark = unescape($('
').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack + var notifications_empty = unescape($("#nav-notifications-menu").html()); - if ($(document).scrollTop() == 0) - force_update = true; + /* enable perfect-scrollbars for different elements */ + $('#nav-notifications-menu, aside').perfectScrollbar(); - var udargs = ((netargs.length) ? '/' + netargs : ''); - var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0); + /* nav update event */ + $('nav').bind('nav-update', function(e, data) { + var invalid = data.invalid || 0; + if (invalid == 1) { + window.location.href=window.location.href + } - $.get(update_url,function(data) { - in_progress = false; - force_update = false; - // $('.collapsed-comments',data).each(function() { - // var ident = $(this).attr('id'); - // var is_hidden = $('#' + ident).is(':hidden'); - // if($('#' + ident).length) { - // $('#' + ident).replaceWith($(this)); - // if(is_hidden) - // $('#' + ident).hide(); - // } - //}); - - // add a new thread - $('.toplevel_item',data).each(function() { - var ident = $(this).attr('id'); - - if($('#' + ident).length == 0 && profile_page == 1) { - $('img',this).each(function() { - $(this).attr('src',$(this).attr('dst')); - }); - $('#' + prev).after($(this)); - } - else { - // Find out if the hidden comments are open, so we can keep it that way - // if a new comment has been posted - var id = $('.hide-comments-total', this).attr('id'); - if(typeof id != 'undefined') { - id = id.split('-')[3]; - var commentsOpen = $("#collapsed-comments-" + id).is(":visible"); - } - - $('img',this).each(function() { - $(this).attr('src',$(this).attr('dst')); - }); - //vScroll = $(document).scrollTop(); - $('html').height($('html').height()); - $('#' + ident).replaceWith($(this)); - - if(typeof id != 'undefined') { - if(commentsOpen) showHideComments(id); - } - $('html').height('auto'); - //$(document).scrollTop(vScroll); - } - prev = ident; - }); - - // reset vars for inserting individual items - - /* prev = 'live-' + src; - - $('.wall-item-outside-wrapper',data).each(function() { - var ident = $(this).attr('id'); - - if($('#' + ident).length == 0 && prev != 'live-' + src) { - $('img',this).each(function() { - $(this).attr('src',$(this).attr('dst')); - }); - $('#' + prev).after($(this)); - } - else { - $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago')); - if($('#' + ident + ' ' + '.comment-edit-text-empty').length) - $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper')); - $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total')); - $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like')); - $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike')); - $('#' + ident + ' ' + '.my-comment-photo').each(function() { - $(this).attr('src',$(this).attr('dst')); - }); - } - prev = ident; - }); - */ - $('.like-rotator').hide(); - if(commentBusy) { - commentBusy = false; - $('body').css('cursor', 'auto'); + ['net', 'home', 'intro', 'mail', 'events', 'birthdays', 'notify'].forEach(function(type) { + var number = data[type]; + if (number == 0) { + number = ''; + $('#' + type + '-update').removeClass('show'); + } else { + $('#' + type + '-update').addClass('show'); + } + $('#' + type + '-update').text(number); + }); + + var intro = data['intro']; + if (intro == 0) { + intro = ''; $('#intro-update-li').removeClass('show') + } else { + $('#intro-update-li').addClass('show') + } + + $('#intro-update-li').html(intro); + + var mail = data['mail']; + if (mail == 0) { + mail = ''; $('#mail-update-li').removeClass('show') + } else { + $('#mail-update-li').addClass('show') + } + + $('#mail-update-li').html(mail); + + $(".sidebar-group-li .notify").removeClass("show"); + $(data.groups).each(function(key, group) { + var gid = group.id; + var gcount = group.count; + $(".group-"+gid+" .notify").addClass("show").text(gcount); + }); + + $(".forum-widget-entry .notify").removeClass("show"); + $(data.forums).each(function(key, forum) { + var fid = forum.id; + var fcount = forum.count; + $(".forum-"+fid+" .notify").addClass("show").text(fcount); + }); + + if (data.notifications.length == 0) { + $("#nav-notifications-menu").html(notifications_empty); + } else { + var nnm = $("#nav-notifications-menu"); + nnm.html(notifications_all + notifications_mark); + + var lastItemStorageKey = "notification-lastitem:" + localUser; + var notification_lastitem = parseInt(localStorage.getItem(lastItemStorageKey)); + var notification_id = 0; + + // Insert notifs into the notifications-menu + $(data.notifications).each(function(key, notif) { + var text = notif.message.format('' + notif.name + ''); + var contact = ('' + notif.name + ''); + var seenclass = (notif.seen == 1) ? "notify-seen" : "notify-unseen"; + var html = notifications_tpl.format( + notif.href, // {0} // link to the source + notif.photo, // {1} // photo of the contact + text, // {2} // preformatted text (autor + text) + notif.date, // {3} // date of notification (time ago) + seenclass, // {4} // visited status of the notification + new Date(notif.timestamp*1000), // {5} // date of notification + notif.url, // {6} // profile url of the contact + notif.message.format(contact), // {7} // preformatted html (text including author profile url) + '' // {8} // Deprecated + ); + nnm.append(html); + }); + + // Desktop Notifications + $(data.notifications.reverse()).each(function(key, e) { + notification_id = parseInt(e.timestamp); + if (notification_lastitem !== null && notification_id > notification_lastitem && Number(e.seen) === 0) { + if (getNotificationPermission() === "granted") { + var notification = new Notification(document.title, { + body: decodeHtml(e.message.replace('→ ', '').format(e.name)), + icon: e.photo, + }); + notification['url'] = e.href; + notification.addEventListener("click", function(ev) { + window.location = ev.target.url; + }); + } + } + + }); + notification_lastitem = notification_id; + localStorage.setItem(lastItemStorageKey, notification_lastitem) + + $("img[data-src]", nnm).each(function(i, el) { + // Add src attribute for images with a data-src attribute + // However, don't bother if the data-src attribute is empty, because + // an empty "src" tag for an image will cause some browsers + // to prefetch the root page of the Friendica hub, which will + // unnecessarily load an entire profile/ or network/ page + if ($(el).data("src") != '') { + $(el).attr('src', $(el).data("src")); + } + }); + } + + var notif = data['notify']; + if (notif > 0) { + $("#nav-notifications-linkmenu").addClass("on"); + } else { + $("#nav-notifications-linkmenu").removeClass("on"); + } + + $(data.sysmsgs.notice).each(function(key, message) { + $.jGrowl(message, {sticky: true, theme: 'notice'}); + }); + $(data.sysmsgs.info).each(function(key, message) { + $.jGrowl(message, {sticky: false, theme: 'info', life: 5000}); + }); + + // Update the js scrollbars + $('#nav-notifications-menu').perfectScrollbar('update'); + }); + + NavUpdate(); + // Allow folks to stop the ajax page updates with the pause/break key + $(document).keydown(function(event) { + if (event.keyCode == '8') { + var target = event.target || event.srcElement; + if (!/input|textarea/i.test(target.nodeName)) { + return false; + } + } + + if (event.keyCode == '19' || (event.ctrlKey && event.which == '32')) { + event.preventDefault(); + if (stopped == false) { + stopped = true; + if (event.ctrlKey) { + totStopped = true; + } + $('#pause').html('pause'); + } else { + unpause(); + } + } else if (!totStopped) { + unpause(); + } + }); + + // Scroll to the next/previous thread when pressing J and K + $(document).keydown(function (event) { + var threads = $('.thread_level_1'); + if ((event.keyCode === 74 || event.keyCode === 75) && !$(event.target).is('textarea, input')) { + var scrollTop = $(window).scrollTop(); + if (event.keyCode === 75) { + threads = $(threads.get().reverse()); + } + threads.each(function(key, item) { + var comparison; + var top = $(item).offset().top - 100; + if (event.keyCode === 74) { + comparison = top > scrollTop + 1; + } else if (event.keyCode === 75) { + comparison = top < scrollTop - 1; + } + if (comparison) { + $('html, body').animate({ scrollTop: top }, 200); + return false; + } + }); + } + }); + + // Set an event listener for infinite scroll + if (typeof infinite_scroll !== 'undefined') { + $(window).scroll(function(e) { + if ($(document).height() != $(window).height()) { + // First method that is expected to work - but has problems with Chrome + if ($(window).scrollTop() > ($(document).height() - $(window).height() * 1.5)) + loadScrollContent(); + } else { + // This method works with Chrome - but seems to be much slower in Firefox + if ($(window).scrollTop() > (($("section").height() + $("header").height() + $("footer").height()) - $(window).height() * 1.5)) { + loadScrollContent(); + } } - /* autocomplete @nicknames */ - $(".comment-edit-form textarea").editor_autocomplete(baseurl+"/acl"); - /* autocomplete bbcode */ - $(".comment-edit-form textarea").bbco_autocomplete('bbcode'); }); } +}); - function imgbright(node) { - $(node).removeClass("drophide").addClass("drop"); +function NavUpdate() { + if (!stopped) { + var pingCmd = 'ping?format=json' + ((localUser != 0) ? '&f=&uid=' + localUser : ''); + $.get(pingCmd, function(data) { + if (data.result) { + // send nav-update event + $('nav').trigger('nav-update', data.result); + + // start live update + ['network', 'profile', 'community', 'notes', 'display'].forEach(function (src) { + if ($('#live-' + src).length) { + liveUpdate(src); + } + }); + if ($('#live-photos').length) { + if (liking) { + liking = 0; + window.location.href = window.location.href; + } + } + } + }); + } + timer = setTimeout(NavUpdate, updateInterval); +} + +function liveUpdate(src) { + if ((src == null) || (stopped) || (! profile_uid)) { + $('.like-rotator').hide(); return; } - function imgdull(node) { - $(node).removeClass("drop").addClass("drophide"); + if (($('.comment-edit-text-full').length) || (in_progress)) { + if (livetime) { + clearTimeout(livetime); + } + livetime = setTimeout(function() {liveUpdate(src)}, 5000); + return; } - // Since our ajax calls are asynchronous, we will give a few - // seconds for the first ajax call (setting like/dislike), then - // run the updater to pick up any changes and display on the page. - // The updater will turn any rotators off when it's done. - // This function will have returned long before any of these - // events have completed and therefore there won't be any - // visible feedback that anything changed without all this - // trickery. This still could cause confusion if the "like" ajax call - // is delayed and NavUpdate runs before it completes. + if (livetime != null) { + livetime = null; + } + prev = 'live-' + src; - function dolike(ident,verb) { - unpause(); - $('#like-rotator-' + ident.toString()).show(); - $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate ); - liking = 1; + in_progress = true; + + if ($(document).scrollTop() == 0) { force_update = true; } + var udargs = ((netargs.length) ? '/' + netargs : ''); + var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0) + '&item=' + update_item; - function dosubthread(ident) { - unpause(); - $('#like-rotator-' + ident.toString()).show(); - $.get('subthread/' + ident.toString(), NavUpdate ); - liking = 1; - } + $.get(update_url,function(data) { + in_progress = false; + force_update = false; + update_item = null; + // add a new thread + $('.toplevel_item',data).each(function() { + var ident = $(this).attr('id'); - function dostar(ident) { - ident = ident.toString(); - $('#like-rotator-' + ident).show(); - $.get('starred/' + ident, function(data) { - if(data.match(/1/)) { - $('#starred-' + ident).addClass('starred'); - $('#starred-' + ident).removeClass('unstarred'); - $('#star-' + ident).addClass('hidden'); - $('#unstar-' + ident).removeClass('hidden'); - } - else { - $('#starred-' + ident).addClass('unstarred'); - $('#starred-' + ident).removeClass('starred'); - $('#star-' + ident).removeClass('hidden'); - $('#unstar-' + ident).addClass('hidden'); - } - $('#like-rotator-' + ident).hide(); - }); - } - - function doignore(ident) { - ident = ident.toString(); - $('#like-rotator-' + ident).show(); - $.get('ignored/' + ident, function(data) { - if(data.match(/1/)) { - $('#ignored-' + ident).addClass('ignored'); - $('#ignored-' + ident).removeClass('unignored'); - $('#ignore-' + ident).addClass('hidden'); - $('#unignore-' + ident).removeClass('hidden'); - } - else { - $('#ignored-' + ident).addClass('unignored'); - $('#ignored-' + ident).removeClass('ignored'); - $('#ignore-' + ident).removeClass('hidden'); - $('#unignore-' + ident).addClass('hidden'); - } - $('#like-rotator-' + ident).hide(); - }); - } - - function getPosition(e) { - var cursor = {x:0, y:0}; - if ( e.pageX || e.pageY ) { - cursor.x = e.pageX; - cursor.y = e.pageY; - } - else { - if( e.clientX || e.clientY ) { - cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft; - cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop; - } - else { - if( e.x || e.y ) { - cursor.x = e.x; - cursor.y = e.y; - } - } - } - return cursor; - } - - var lockvisible = false; - - function lockview(event,id) { - event = event || window.event; - cursor = getPosition(event); - if(lockvisible) { - lockviewhide(); - } - else { - lockvisible = true; - $.get('lockview/' + id, function(data) { - $('#panel').html(data); - $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5}); - $('#panel').show(); - }); - } - } - - function lockviewhide() { - lockvisible = false; - $('#panel').hide(); - } - - function post_comment(id) { - unpause(); - commentBusy = true; - $('body').css('cursor', 'wait'); - $("#comment-preview-inp-" + id).val("0"); - $.post( - "item", - $("#comment-edit-form-" + id).serialize(), - function(data) { - if(data.success) { - $("#comment-edit-wrapper-" + id).hide(); - $("#comment-edit-text-" + id).val(''); - var tarea = document.getElementById("comment-edit-text-" + id); - if(tarea) - commentClose(tarea,id); - if(timer) clearTimeout(timer); - timer = setTimeout(NavUpdate,10); - force_update = true; - } - if(data.reload) { - window.location.href=data.reload; - } - }, - "json" - ); - return false; - } - - - function preview_comment(id) { - $("#comment-preview-inp-" + id).val("1"); - $("#comment-edit-preview-" + id).show(); - $.post( - "item", - $("#comment-edit-form-" + id).serialize(), - function(data) { - if(data.preview) { - $("#comment-edit-preview-" + id).html(data.preview); - $("#comment-edit-preview-" + id + " a").click(function() { return false; }); - } - }, - "json" - ); - return true; - } - - - - function showHideComments(id) { - if( $("#collapsed-comments-" + id).is(":visible")) { - $("#collapsed-comments-" + id).hide(); - $("#hide-comments-" + id).html(window.showMore); - } - else { - $("#collapsed-comments-" + id).show(); - $("#hide-comments-" + id).html(window.showFewer); - } - } - - - - function preview_post() { - $("#jot-preview").val("1"); - $("#jot-preview-content").show(); - $.post( - "item", - $("#profile-jot-form").serialize(), - function(data) { - if(data.preview) { - $("#jot-preview-content").html(data.preview); - $("#jot-preview-content" + " a").click(function() { return false; }); - } - }, - "json" - ); - $("#jot-preview").val("0"); - return true; - } - - - function unpause() { - // unpause auto reloads if they are currently stopped - totStopped = false; - stopped = false; - $('#pause').html(''); - } - - // load more network content (used for infinite scroll) - function loadScrollContent() { - if (lockLoadContent) return; - lockLoadContent = true; - - $("#scroll-loader").fadeIn('normal'); - - // the page number to load is one higher than the actual - // page number - infinite_scroll.pageno+=1; - - match = $("span.received").last(); - if (match.length > 0) { - received = match[0].innerHTML; - } else { - received = "0000-00-00 00:00:00"; - } - - match = $("span.created").last(); - if (match.length > 0) { - created = match[0].innerHTML; - } else { - created = "0000-00-00 00:00:00"; - } - - match = $("span.commented").last(); - if (match.length > 0) { - commented = match[0].innerHTML; - } else { - commented = "0000-00-00 00:00:00"; - } - - match = $("span.id").last(); - if (match.length > 0) { - id = match[0].innerHTML; - } else { - id = "0"; - } - // console.log("Received: " + received + " - Commented: " + commented+ " - Created: " + created + " - ID: " + id); - - // get the raw content from the next page and insert this content - // right before "#conversation-end" - $.get('network?mode=raw' + infinite_scroll.reload_uri + '&last_received=' + received + '&last_commented=' + commented + '&last_created=' + created + '&last_id=' + id + '&page=' + infinite_scroll.pageno, function(data) { - $("#scroll-loader").hide(); - if ($(data).length > 0) { - - $(data).insertBefore('#conversation-end'); - lockLoadContent = false; + if ($('#' + ident).length == 0 && profile_page == 1) { + $('img',this).each(function() { + $(this).attr('src',$(this).attr('dst')); + }); + $('#' + prev).after($(this)); } else { - $("#scroll-end").fadeIn('normal'); + // Find out if the hidden comments are open, so we can keep it that way + // if a new comment has been posted + var id = $('.hide-comments-total', this).attr('id'); + if (typeof id != 'undefined') { + id = id.split('-')[3]; + var commentsOpen = $("#collapsed-comments-" + id).is(":visible"); + } + + $('img',this).each(function() { + $(this).attr('src',$(this).attr('dst')); + }); + $('html').height($('html').height()); + $('#' + ident).replaceWith($(this)); + + if (typeof id != 'undefined') { + if (commentsOpen) { + showHideComments(id); + } + } + $('html').height('auto'); } + prev = ident; + }); + + $('.like-rotator').hide(); + if (commentBusy) { + commentBusy = false; + $('body').css('cursor', 'auto'); + } + /* autocomplete @nicknames */ + $(".comment-edit-form textarea").editor_autocomplete(baseurl+"/acl"); + /* autocomplete bbcode */ + $(".comment-edit-form textarea").bbco_autocomplete('bbcode'); + }); +} + +function imgbright(node) { + $(node).removeClass("drophide").addClass("drop"); +} + +function imgdull(node) { + $(node).removeClass("drop").addClass("drophide"); +} + +// Since our ajax calls are asynchronous, we will give a few +// seconds for the first ajax call (setting like/dislike), then +// run the updater to pick up any changes and display on the page. +// The updater will turn any rotators off when it's done. +// This function will have returned long before any of these +// events have completed and therefore there won't be any +// visible feedback that anything changed without all this +// trickery. This still could cause confusion if the "like" ajax call +// is delayed and NavUpdate runs before it completes. + +function dolike(ident,verb) { + unpause(); + $('#like-rotator-' + ident.toString()).show(); + $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate ); + liking = 1; + force_update = true; + update_item = ident.toString(); +} + +function dosubthread(ident) { + unpause(); + $('#like-rotator-' + ident.toString()).show(); + $.get('subthread/' + ident.toString(), NavUpdate ); + liking = 1; +} + +function dostar(ident) { + ident = ident.toString(); + $('#like-rotator-' + ident).show(); + $.get('starred/' + ident, function(data) { + if (data.match(/1/)) { + $('#starred-' + ident).addClass('starred'); + $('#starred-' + ident).removeClass('unstarred'); + $('#star-' + ident).addClass('hidden'); + $('#unstar-' + ident).removeClass('hidden'); + } else { + $('#starred-' + ident).addClass('unstarred'); + $('#starred-' + ident).removeClass('starred'); + $('#star-' + ident).removeClass('hidden'); + $('#unstar-' + ident).addClass('hidden'); + } + $('#like-rotator-' + ident).hide(); + }); +} + +function doignore(ident) { + ident = ident.toString(); + $('#like-rotator-' + ident).show(); + $.get('ignored/' + ident, function(data) { + if (data.match(/1/)) { + $('#ignored-' + ident).addClass('ignored'); + $('#ignored-' + ident).removeClass('unignored'); + $('#ignore-' + ident).addClass('hidden'); + $('#unignore-' + ident).removeClass('hidden'); + } else { + $('#ignored-' + ident).addClass('unignored'); + $('#ignored-' + ident).removeClass('ignored'); + $('#ignore-' + ident).removeClass('hidden'); + $('#unignore-' + ident).addClass('hidden'); + } + $('#like-rotator-' + ident).hide(); + }); +} + +function getPosition(e) { + var cursor = {x:0, y:0}; + + if (e.pageX || e.pageY) { + cursor.x = e.pageX; + cursor.y = e.pageY; + } else { + if (e.clientX || e.clientY) { + cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft; + cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop; + } else if (e.x || e.y) { + cursor.x = e.x; + cursor.y = e.y; + } + } + return cursor; +} + +var lockvisible = false; + +function lockview(event,id) { + event = event || window.event; + cursor = getPosition(event); + if (lockvisible) { + lockviewhide(); + } else { + lockvisible = true; + $.get('lockview/' + id, function(data) { + $('#panel').html(data); + $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5}); + $('#panel').show(); }); } +} - function bin2hex(s){ +function lockviewhide() { + lockvisible = false; + $('#panel').hide(); +} + +function post_comment(id) { + unpause(); + commentBusy = true; + $('body').css('cursor', 'wait'); + $("#comment-preview-inp-" + id).val("0"); + $.post( + "item", + $("#comment-edit-form-" + id).serialize(), + function(data) { + if (data.success) { + $("#comment-edit-wrapper-" + id).hide(); + $("#comment-edit-text-" + id).val(''); + var tarea = document.getElementById("comment-edit-text-" + id); + if (tarea) { + commentClose(tarea,id); + } + if (timer) { + clearTimeout(timer); + } + timer = setTimeout(NavUpdate,10); + force_update = true; + update_item = id; + } + if (data.reload) { + window.location.href=data.reload; + } + }, + "json" + ); + return false; +} + +function preview_comment(id) { + $("#comment-preview-inp-" + id).val("1"); + $("#comment-edit-preview-" + id).show(); + $.post( + "item", + $("#comment-edit-form-" + id).serialize(), + function(data) { + if (data.preview) { + $("#comment-edit-preview-" + id).html(data.preview); + $("#comment-edit-preview-" + id + " a").click(function() { return false; }); + } + }, + "json" + ); + return true; +} + +function showHideComments(id) { + if ($("#collapsed-comments-" + id).is(":visible")) { + $("#collapsed-comments-" + id).hide(); + $("#hide-comments-" + id).html(window.showMore); + } else { + $("#collapsed-comments-" + id).show(); + $("#hide-comments-" + id).html(window.showFewer); + } +} + +function preview_post() { + $("#jot-preview").val("1"); + $("#jot-preview-content").show(); + $.post( + "item", + $("#profile-jot-form").serialize(), + function(data) { + if (data.preview) { + $("#jot-preview-content").html(data.preview); + $("#jot-preview-content" + " a").click(function() { return false; }); + } + }, + "json" + ); + $("#jot-preview").val("0"); + return true; +} + +function unpause() { + // unpause auto reloads if they are currently stopped + totStopped = false; + stopped = false; + $('#pause').html(''); +} + +// load more network content (used for infinite scroll) +function loadScrollContent() { + if (lockLoadContent) { + return; + } + lockLoadContent = true; + + $("#scroll-loader").fadeIn('normal'); + + // the page number to load is one higher than the actual + // page number + infinite_scroll.pageno+=1; + + match = $("span.received").last(); + if (match.length > 0) { + received = match[0].innerHTML; + } else { + received = "0000-00-00 00:00:00"; + } + + match = $("span.created").last(); + if (match.length > 0) { + created = match[0].innerHTML; + } else { + created = "0000-00-00 00:00:00"; + } + + match = $("span.commented").last(); + if (match.length > 0) { + commented = match[0].innerHTML; + } else { + commented = "0000-00-00 00:00:00"; + } + + match = $("span.id").last(); + if (match.length > 0) { + id = match[0].innerHTML; + } else { + id = "0"; + } + + // get the raw content from the next page and insert this content + // right before "#conversation-end" + $.get('network?mode=raw' + infinite_scroll.reload_uri + '&last_received=' + received + '&last_commented=' + commented + '&last_created=' + created + '&last_id=' + id + '&page=' + infinite_scroll.pageno, function(data) { + $("#scroll-loader").hide(); + if ($(data).length > 0) { + $(data).insertBefore('#conversation-end'); + lockLoadContent = false; + } else { + $("#scroll-end").fadeIn('normal'); + } + }); +} + +function bin2hex(s) { // Converts the binary representation of data to hex // // version: 812.316 @@ -770,44 +743,44 @@ } return a.join(''); - } +} - function groupChangeMember(gid, cid, sec_token) { - $('body .fakelink').css('cursor', 'wait'); - $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) { - $('#group-update-wrapper').html(data); - $('body .fakelink').css('cursor', 'auto'); - }); - } +function groupChangeMember(gid, cid, sec_token) { + $('body .fakelink').css('cursor', 'wait'); + $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) { + $('#group-update-wrapper').html(data); + $('body .fakelink').css('cursor', 'auto'); + }); +} - function profChangeMember(gid,cid) { - $('body .fakelink').css('cursor', 'wait'); - $.get('profperm/' + gid + '/' + cid, function(data) { - $('#prof-update-wrapper').html(data); - $('body .fakelink').css('cursor', 'auto'); - }); - } - - function contactgroupChangeMember(gid,cid) { - $('body').css('cursor', 'wait'); - $.get('contactgroup/' + gid + '/' + cid, function(data) { - $('body').css('cursor', 'auto'); - }); - } +function profChangeMember(gid,cid) { + $('body .fakelink').css('cursor', 'wait'); + $.get('profperm/' + gid + '/' + cid, function(data) { + $('#prof-update-wrapper').html(data); + $('body .fakelink').css('cursor', 'auto'); + }); +} +function contactgroupChangeMember(gid,cid) { + $('body').css('cursor', 'wait'); + $.get('contactgroup/' + gid + '/' + cid, function(data) { + $('body').css('cursor', 'auto'); + }); +} function checkboxhighlight(box) { - if($(box).is(':checked')) { - $(box).addClass('checkeditem'); - } - else { - $(box).removeClass('checkeditem'); - } + if ($(box).is(':checked')) { + $(box).addClass('checkeditem'); + } else { + $(box).removeClass('checkeditem'); + } } function notifyMarkAll() { $.get('notify/mark/all', function(data) { - if(timer) clearTimeout(timer); + if (timer) { + clearTimeout(timer); + } timer = setTimeout(NavUpdate,1000); force_update = true; }); @@ -818,19 +791,19 @@ function notifyMarkAll() { * "{0} and {1}".format('zero','uno'); **/ String.prototype.format = function() { - var formatted = this; - for (var i = 0; i < arguments.length; i++) { - var regexp = new RegExp('\\{'+i+'\\}', 'gi'); - formatted = formatted.replace(regexp, arguments[i]); - } - return formatted; + var formatted = this; + for (var i = 0; i < arguments.length; i++) { + var regexp = new RegExp('\\{'+i+'\\}', 'gi'); + formatted = formatted.replace(regexp, arguments[i]); + } + return formatted; }; // Array Remove Array.prototype.remove = function(item) { - to=undefined; from=this.indexOf(item); - var rest = this.slice((to || from) + 1 || this.length); - this.length = from < 0 ? this.length + from : from; - return this.push.apply(this, rest); + to=undefined; from=this.indexOf(item); + var rest = this.slice((to || from) + 1 || this.length); + this.length = from < 0 ? this.length + from : from; + return this.push.apply(this, rest); }; function previewTheme(elm) { @@ -847,13 +820,16 @@ function getNotificationPermission() { if (window["Notification"] === undefined) { return null; } - if (Notification.permission === 'granted') { - var val = localStorage.getItem('notification-permissions'); - if (val === null) return 'denied'; + + if (Notification.permission === 'granted') { + var val = localStorage.getItem('notification-permissions'); + if (val === null) { + return 'denied'; + } return val; - } else { - return Notification.permission; - } + } else { + return Notification.permission; + } } /** @@ -909,7 +885,9 @@ var Dialog = { _get_url : function(type, name, id) { var hash = name; - if (id !== undefined) hash = hash + "-" + id; + if (id !== undefined) { + hash = hash + "-" + id; + } return baseurl + "/fbrowser/"+type+"/?mode=minimal#"+hash; },