From 4f0015f15c83ee87a21315ce0220238c8bf7c433 Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Sun, 29 Oct 2017 21:10:18 +0100
Subject: [PATCH] Notification center 2.0

---
 .../templatetags/notifications_tags.py        |  52 ++-
 notifications/views.py                        |   7 +-
 production/views.py                           |   1 -
 .../scipost/assets/config/preconfig.scss      |   7 +
 .../scipost/assets/css/_breadcrumb.scss       |   1 +
 .../css/{_popover.scss => _dropdown.scss}     |  66 ++-
 .../static/scipost/assets/css/_homepage.scss  |  15 +-
 scipost/static/scipost/assets/css/_nav.scss   |  24 +-
 .../static/scipost/assets/css/_navbar.scss    |  70 ++--
 scipost/static/scipost/assets/css/_type.scss  |   2 +-
 scipost/static/scipost/assets/css/style.scss  |   2 +-
 .../static/scipost/assets/js/notifications.js | 385 +++++++++++-------
 scipost/templates/scipost/navbar.html         | 123 +++---
 13 files changed, 452 insertions(+), 303 deletions(-)
 rename scipost/static/scipost/assets/css/{_popover.scss => _dropdown.scss} (54%)

diff --git a/notifications/templatetags/notifications_tags.py b/notifications/templatetags/notifications_tags.py
index 42c62d09b..900fa7c96 100644
--- a/notifications/templatetags/notifications_tags.py
+++ b/notifications/templatetags/notifications_tags.py
@@ -1,35 +1,55 @@
 # -*- coding: utf-8 -*-
+from django.core.urlresolvers import reverse
 from django.template import Library
 from django.utils.html import format_html
 
 register = Library()
 
 
-@register.assignment_tag(takes_context=True)
-def notifications_unread(context):
-    user = user_context(context)
-    if not user:
-        return ''
-    return user.notifications.unread().count()
+@register.simple_tag(takes_context=True)
+def live_notify_badge(context, classes=''):
+    html = "<span class='live_notify_badge {classes}'>0</span>".format(classes=classes)
+    return format_html(html)
 
 
 @register.simple_tag(takes_context=True)
-def live_notify_badge(context, badge_class='live_notify_badge', classes=''):
+def live_notify_list(context):
     user = user_context(context)
     if not user:
         return ''
 
-    html = "<span class='{badge_class} {classes}' data-count='{unread}'>{unread}</span>".format(
-        badge_class=badge_class, unread=user.notifications.unread().count(),
-        classes=classes
-    )
-    return format_html(html)
+    html = '<div class="dropdown-menu notifications">'
+
+    # User default links
+    html += '<h6 class="dropdown-header">Welcome {first_name} {last_name}</h6>'.format(
+        first_name=user.first_name, last_name=user.last_name)
+
+    if hasattr(user, 'contributor'):
+        html += '<a class="dropdown-item" href="{url}">Personal Page</a>'.format(
+            url=reverse('scipost:personal_page'))
+
+    # User specific links
+    if user.has_perm('scipost.can_read_partner_page'):
+        html += '<a class="dropdown-item" href="{url}">Partner Page</a>'.format(
+            url=reverse('partners:dashboard'))
+    if user.has_perm('scipost.can_view_timesheets'):
+        html += '<a class="dropdown-item" href="{url}">Financial Administration</a>'.format(
+            url=reverse('finances:finance'))
+    if user.has_perm('scipost.can_view_production'):
+        html += '<a class="dropdown-item" href="{url}">Production</a>'.format(
+            url=reverse('production:production'))
+    if user.has_perm('scipost.can_view_pool'):
+        html += '<a class="dropdown-item" href="{url}">Submission Pool</a>'.format(
+            url=reverse('submissions:pool'))
 
+    # Logout links
+    html += '<div class="dropdown-divider my-0"></div>'
+    html += '<a class="dropdown-item" href="{url}">Logout</a>'.format(
+        url=reverse('scipost:logout'))
 
-@register.simple_tag
-def live_notify_list(list_class='live_notify_list', classes=''):
-    html = "<ul class='{list_class} {classes}'></ul>".format(list_class=list_class,
-                                                             classes=classes)
+    # Notifications
+    html += '<div class="dropdown-divider my-0"></div><h6 class="dropdown-header">Inbox</h6>'
+    html += '<div class="live_notify_list"></div></div>'
     return format_html(html)
 
 
diff --git a/notifications/views.py b/notifications/views.py
index bcdf7e3b0..8df20c6ab 100644
--- a/notifications/views.py
+++ b/notifications/views.py
@@ -119,8 +119,11 @@ def live_notification_list(request):
         struct['timesince'] = n.timesince()
 
         list.append(struct)
-        if request.GET.get('mark_as_read'):
-            n.mark_as_read()
+
+    if request.GET.get('mark_as_read'):
+        # Mark all as read
+        request.user.notifications.mark_all_as_read()
+
     data = {
         'unread_count': request.user.notifications.unread().count(),
         'list': list
diff --git a/production/views.py b/production/views.py
index 49bfa8926..cc7e0d406 100644
--- a/production/views.py
+++ b/production/views.py
@@ -1,4 +1,3 @@
-import datetime
 import mimetypes
 
 from django.contrib import messages
diff --git a/scipost/static/scipost/assets/config/preconfig.scss b/scipost/static/scipost/assets/config/preconfig.scss
index 7ddb10372..29b5ca618 100644
--- a/scipost/static/scipost/assets/config/preconfig.scss
+++ b/scipost/static/scipost/assets/config/preconfig.scss
@@ -65,6 +65,13 @@ $card-shadow-color: #ccc;
 $card-grey-border-bottom-color: #d0d1d5;
 $card-grey-border-color: #e5e6e9 #dfe0e4 $card-grey-border-bottom-color;
 
+// Dropdown
+//
+$dropdown-link-active-color: $scipost-darkblue;
+$dropdown-link-active-bg: $scipost-lightestblue;
+$dropdown-header-color: $scipost-darkblue;
+
+
 // breadcrumb
 //
 $breadcrumb-bg: #f9f9f9;
diff --git a/scipost/static/scipost/assets/css/_breadcrumb.scss b/scipost/static/scipost/assets/css/_breadcrumb.scss
index cbb8d8e6b..4e3915ebc 100644
--- a/scipost/static/scipost/assets/css/_breadcrumb.scss
+++ b/scipost/static/scipost/assets/css/_breadcrumb.scss
@@ -9,6 +9,7 @@
     .container {
         width: 100%;
         display: flex;
+        flex-wrap: nowrap;
     }
 
     .breadcrumb-item {
diff --git a/scipost/static/scipost/assets/css/_popover.scss b/scipost/static/scipost/assets/css/_dropdown.scss
similarity index 54%
rename from scipost/static/scipost/assets/css/_popover.scss
rename to scipost/static/scipost/assets/css/_dropdown.scss
index 5ef240e8b..a8517a229 100644
--- a/scipost/static/scipost/assets/css/_popover.scss
+++ b/scipost/static/scipost/assets/css/_dropdown.scss
@@ -1,43 +1,18 @@
-.popover {
-    width: 500px;
-    box-shadow: #ccc 0px 1px 2px 1px;
-}
 
 .navbar-counter .nav-link:hover {
     background-color: $white;
 }
 
-.popover.bs-popover-bottom,
-.popover.bs-popover-auto[x-placement^="bottom"] {
-    .arrow::before {
-        border-bottom-color: rgb(221, 221, 221);
-    }
-
-    .arrow::after {
-        border-bottom-color: #f7f7f7;
-    }
-}
-
 .notifications {
-    border: 0;
-    border-radius: 0;
-
-    .popover-header {
-        font-size: 100%;
-        padding: 0.3rem 1rem;
-        font-weight: 600;
-        text-transform: uppercase;
-
-        a {
-            color: $scipost-darkblue;
-        }
-    }
+    padding-top: 0;
+    padding-bottom: 0;
 
-    .popover-body {
-        padding: 0;
+    .dropdown-header {
+        padding: 1rem 1rem 0.5rem 1rem;
+        background-color: #f9f9f9;
     }
 
-    &.popover .list-group-item {
+    .dropdown-item {
         padding: 0.4rem 1rem;
         border-radius: 0;
         border-top: 1px solid #fff;
@@ -47,18 +22,31 @@
         justify-content: space-between;
         display: flex;
 
+        > div {
+            white-space: normal;
+        }
+
         &:last-child {
             border-bottom: 0;
         }
     }
+    a.dropdown-item {
+        color: $scipost-lightblue;
+
+        &:hover {
+            text-decoration: underline;
+        }
+    }
 
     .actions {
-        display: block;
+        display: none;
         opacity: 0.0;
         transition: opacity 0.1s;
         width: 20px;
         height: 100%;
-        padding-left: 0.25rem;
+        padding-left: 1rem;
+        padding-right: 0.5rem;
+        padding-bottom: 0.1rem;
 
         .fa[data-toggle="tooltip"] {
             font-size: 1em;
@@ -75,11 +63,17 @@
         }
     }
 
-    .list-group-item:hover .actions {
+    .dropdown-item:hover .actions {
         opacity: 1.0;
     }
 }
 
-.popover-header {
-    font-size: initial;
+@media (min-width: 768px) {
+    .notifications {
+        min-width: 500px;
+
+        .actions {
+            display: block;
+        }
+    }
 }
diff --git a/scipost/static/scipost/assets/css/_homepage.scss b/scipost/static/scipost/assets/css/_homepage.scss
index 16da6e2fd..2940939bb 100644
--- a/scipost/static/scipost/assets/css/_homepage.scss
+++ b/scipost/static/scipost/assets/css/_homepage.scss
@@ -24,8 +24,6 @@
         max-height: 100%;
         height: 100%;
         -webkit-overflow-scrolling: touch;
-        padding-left: 1rem;
-        padding-right: 1rem;
     }
 
     .main-panel {
@@ -44,6 +42,8 @@
         border-left: 1px solid #ddd;
         position: relative;
         padding-top: 0.25rem;
+        padding-left: 1rem;
+        padding-right: 1rem;
         margin-top: 2rem;
 
         .card {
@@ -70,10 +70,15 @@
             padding-right: 0;
         }
     }
+}
+
 
-    @media (min-width: 768px) {
+@media (min-width: 768px) {
+    .has-sidebar {
         .main-panel {
             width: calc(100% - 350px);
+            padding-left: 1rem;
+            padding-right: 1rem;
         }
         .sidebar {
             width: 350px;
@@ -94,8 +99,10 @@
             }
         }
     }
+}
 
-    @media (min-width: 1280px) {
+@media (min-width: 1280px) {
+    .has-sidebar {
         .main-panel {
             width: calc(100% - 400px);
         }
diff --git a/scipost/static/scipost/assets/css/_nav.scss b/scipost/static/scipost/assets/css/_nav.scss
index 955179539..d2057d423 100644
--- a/scipost/static/scipost/assets/css/_nav.scss
+++ b/scipost/static/scipost/assets/css/_nav.scss
@@ -68,6 +68,10 @@ nav.main-nav {
     }
 }
 
+.nav {
+    flex-wrap: nowrap;
+}
+
 nav.submenu {
     margin-top: -1.5rem;
     margin-bottom: 1rem;
@@ -78,11 +82,27 @@ nav.submenu {
     border-bottom: 1px solid #ddd;
 
     .item {
-        padding: 0 0.5rem;
-        border-right: 2px solid #fff;
+        padding: 0.1rem 0.5rem;
+        white-space: nowrap;
+        display: block;
     }
     .item:first-child,
     .item:last-child {
         border-right: 0;
     }
 }
+
+@media (min-width: 768px) {
+    nav.submenu {
+        display: flex;
+        flex-wrap: nowrap;
+        flex-direction: row;
+
+        .item {
+            padding-top: 0;
+            padding-bottom: 0;
+            display: inline;
+            border-right: 2px solid #fff;
+        }
+    }
+}
diff --git a/scipost/static/scipost/assets/css/_navbar.scss b/scipost/static/scipost/assets/css/_navbar.scss
index a1ffa8e02..cc1fbe753 100644
--- a/scipost/static/scipost/assets/css/_navbar.scss
+++ b/scipost/static/scipost/assets/css/_navbar.scss
@@ -4,6 +4,8 @@
  */
 .navbar {
     margin-bottom: 1.5rem;
+    display: block;
+    flex-wrap: nowrap;
 
     &.main-nav {
         border-bottom: 1px solid #ddd;
@@ -25,10 +27,6 @@
         }
     }
 
-    .navbar-nav {
-        flex-direction: row;
-    }
-
     .active > .nav-link {
         border-color: $scipost-darkblue;
         box-shadow: 0 1px 0 0 #ccc;
@@ -37,9 +35,25 @@
     .highlighted > .nav-link {
         background-color: rgba(255, 255, 255, 0.6);
     }
+}
 
-    .nav-item {
-        margin-right: 0.5rem;
+@media (min-width: 768px) {
+    .navbar {
+        display: flex;
+
+        .navbar-nav {
+            margin-right: auto;
+            display: flex;
+            flex-direction: row;
+        }
+
+        .nav-item {
+            margin-right: 0.5rem;
+        }
+
+        [data-toggle="collapse"] {
+            display: none;
+        }
     }
 }
 
@@ -92,47 +106,51 @@
             content: "\f0f3";
         }
     }
+}
 
-    .badge {
-        vertical-align: top;
-        margin-left: -15px;
-        margin-top: -5px;
-        height: 16px;
-        min-width: 16px;
-        line-height: 10px;
-        display: none;
-        padding: 0.25em;
-        border-radius: 99px;
-        border: 1px solid #f9f9f9;
-    }
+.live_notify_badge {
+    vertical-align: top;
+    margin-left: -15px;
+    margin-top: -5px;
+    height: 16px;
+    min-width: 16px;
+    line-height: 10px;
+    display: none;
+    padding: 0.25em;
+    border-radius: 99px;
+    border: 1px solid #f9f9f9;
 }
 
 .notifications_container {
-    color: $scipost-lightestblue;
+    .badge_link {
+        color: $scipost-lightestblue;
+
+        // &::after {
+        //     content: none;
+        // }
+    }
 
     .user {
         color: $scipost-darkblue;
     }
 
-    .fa {
+    .fa-inbox {
         font-size: 150%;
         vertical-align: bottom;
         margin: 0 0.25rem;
     }
 
     &.positive_count {
-        color: $scipost-orange;
+        .badge_link {
+            color: $scipost-orange;
+        }
 
         .user {
             color: $scipost-darkblue;
         }
 
-        .badge {
+        .live_notify_badge {
             display: inline-block;
         }
     }
-
-    &::after {
-        content: none;
-    }
 }
diff --git a/scipost/static/scipost/assets/css/_type.scss b/scipost/static/scipost/assets/css/_type.scss
index 056fe6dcb..fbe387a33 100644
--- a/scipost/static/scipost/assets/css/_type.scss
+++ b/scipost/static/scipost/assets/css/_type.scss
@@ -31,7 +31,7 @@ h4 {
     line-height: normal;
 }
 
-h5, h6 {
+h5 {
     font-weight: 300;
 }
 
diff --git a/scipost/static/scipost/assets/css/style.scss b/scipost/static/scipost/assets/css/style.scss
index be68d3198..0c8543be7 100644
--- a/scipost/static/scipost/assets/css/style.scss
+++ b/scipost/static/scipost/assets/css/style.scss
@@ -21,6 +21,7 @@
 @import "buttons";
 @import "cards";
 @import "code";
+@import "dropdown";
 @import "form";
 @import "grid";
 @import "homepage";
@@ -32,7 +33,6 @@
 @import "nav";
 @import "page_header";
 @import "pool";
-@import "popover";
 @import "tables";
 @import "tooltip";
 @import "type";
diff --git a/scipost/static/scipost/assets/js/notifications.js b/scipost/static/scipost/assets/js/notifications.js
index 49fbe7f24..a3feab2b5 100644
--- a/scipost/static/scipost/assets/js/notifications.js
+++ b/scipost/static/scipost/assets/js/notifications.js
@@ -8,143 +8,130 @@ var notify_api_url_mark_all_read = "/notifications/mark-all-as-read/";
 var notify_fetch_count = "5";
 var notify_refresh_period = 60000;
 var consecutive_misfires = 0;
-var registered_functions = [fill_notification_badge];
 
 
-function initiate_popover(reinitiate) {
-    if(typeof reinitiate == 'undefined') {
-        reinitiate = false;
-    }
-
-    var notification_template = '<div class="popover notifications" role="tooltip"><div class="arrow"></div><p class="popover-header"></p><div class="popover-body"></div></div>';
-
-    function get_notifications_title() {
-        return 'My inbox';
-    }
-
-    function get_notifications() {
-        var _str = '<ul id="notification-list" class="update_notifications list-group"><div class="w-100 text-center py-4"><i class="fa fa-circle-o-notch fa-2x fa-spin fa-fw"></i><span class="sr-only">Loading...</span></div></ul>';
-        get_notification_list();
-        return _str;
-    }
-
-    $('.popover [data-toggle="tooltip"]').tooltip('dispose')
-    $('#notifications_badge').popover('dispose').popover({
-        animation: false,
-        trigger: 'click',
-        title: get_notifications_title,
-        template: notification_template,
-        content: get_notifications,
-        container: 'body',
-        offset: '0, 9px',
-        placement: "bottom",
-        html: true
-    }).on('inserted.bs.popover', function() {
-        // Bloody js
-        setTimeout(function() {
-            $('.popover [data-toggle="tooltip"]').tooltip({
-                animation: false,
-                delay: {"show": 500, "hide": 100},
-                fallbackPlacement: 'clockwise',
-                placement: 'bottom'
-            });
-            $('.popover .actions a').on('click', function() {
-                mark_toggle(this)
-            })
-            $('.popover a.mark_all_read').on('click', function() {
-                mark_all_read(this)
-            })
-        }, 1000);
-    });
-    if (reinitiate) {
-        $('#notifications_badge').popover('show')
-    }
-}
+// function initiate_popover(reinitiate) {
+//     if(typeof reinitiate == 'undefined') {
+//         reinitiate = false;
+//     }
+//
+    // var notification_template = '<div class="popover notifications" role="tooltip"><div class="arrow"></div><p class="popover-header"></p><div class="popover-body"></div></div>';
+    //
+    // function get_notifications() {
+    //     var _str = '<ul id="notification-list" class="update_notifications list-group"><div class="w-100 text-center py-4"><i class="fa fa-circle-o-notch fa-2x fa-spin fa-fw"></i><span class="sr-only">Loading...</span></div></ul>';
+    //     get_notification_list();
+    //     return _str;
+    // }
+    //
+    // $('.popover [data-toggle="tooltip"]').tooltip('dispose')
+    // $('#notifications_badge').popover('dispose').popover({
+    //     animation: false,
+    //     trigger: 'click',
+    //     title: 'My inbox',
+    //     template: notification_template,
+    //     content: get_notifications,
+    //     container: 'body',
+    //     offset: '0, 9px',
+    //     placement: "bottom",
+    //     html: true
+    // }).on('inserted.bs.popover', function() {
+    //     // Bloody js
+    //     setTimeout(function() {
+    //         $('.popover [data-toggle="tooltip"]').tooltip({
+    //             animation: false,
+    //             delay: {"show": 500, "hide": 100},
+    //             fallbackPlacement: 'clockwise',
+    //             placement: 'bottom'
+    //         });
+    //         $('.popover .actions a').on('click', function() {
+    //             mark_toggle(this)
+    //         })
+    //     }, 1000);
+    // });
+    // if (reinitiate) {
+    //     $('#notifications_badge').popover('show')
+    // }
+// }
+//
+// function request_reinitiate(url) {
+//     var r = new XMLHttpRequest();
+//     r.addEventListener('readystatechange', function(event){
+//         if (this.readyState == 4 && this.status == 200) {
+//             fetch_api_data()
+//             initiate_popover(reinitiate=true)
+//         }
+//     })
+//     r.open("GET", url, true);
+//     r.send();
+// }
+//
+// function mark_all_read(el) {
+//     request_reinitiate(notify_api_url_mark_all_read + '?json=1')
+// }
+//
 
-function request_reinitiate(url) {
-    var r = new XMLHttpRequest();
-    r.addEventListener('readystatechange', function(event){
-        if (this.readyState == 4 && this.status == 200) {
-            fetch_api_data()
-            initiate_popover(reinitiate=true)
-        }
-    })
-    r.open("GET", url, true);
-    r.send();
-}
+//
+//
+// function fill_notification_badge(data) {
+//     var badges = document.getElementsByClassName(notify_badge_class);
+//     var container = $('.' + notify_container_class);
+//     if (badges) {
+//         for(var i = 0; i < badges.length; i++){
+//             badges[i].innerHTML = data.unread_count;
+//             if (data.unread_count > 0) {
+//                 container.addClass('positive_count');
+//             } else {
+//                 container.removeClass('positive_count');
+//             }
+//         }
+//     }
+// }
+//
+// function get_notification_list() {
+//     fetch_api_data(notify_api_url_list, true, function(data) {
+//
+//         var messages = data.list.map(function (item) {
+//             var message = "<div>";
+//             if(typeof item.actor !== 'undefined'){
+//                 message += '<strong>' + item.actor + '</strong>';
+//             }
+//             if(typeof item.verb !== 'undefined'){
+//                 message += " " + item.verb;
+//             }
+//             if(typeof item.target !== 'undefined'){
+//                 if(typeof item.forward_link !== 'undefined') {
+//                     message += " <a href='" + item.forward_link + "'>" + item.target + "</a>";
+//                 } else {
+//                     message += " " + item.target;
+//                 }
+//             }
+//             if(typeof item.timesince !== 'undefined'){
+//                 message += "<br><small class='text-muted'>" + item.timesince + " ago</small>";
+//             }
+//             message += "</div>";
+//
+            // if(item.unread) {
+            //     var mark_as_read = '<div class="actions"><a href="javascript:;" data-slug="' + item.slug + '"><i class="fa fa-circle" data-toggle="tooltip" data-placement="auto" title="Mark as read" aria-hidden="true"></i></a></div>';
+            // } else {
+            //     var mark_as_read = '<div class="actions"><a href="javascript:;" data-slug="' + item.slug + '"><i class="fa fa-circle-o" data-toggle="tooltip" data-placement="auto" title="Mark as unread" aria-hidden="true"></i></a></div>';
+            // }
+//             return '<li class="list-group-item ' + (item.unread ? ' active' : '') + '">' + message + mark_as_read + '</li>';
+//         }).join('');
+//
+        // if (messages == '') {
+        //     messages = '<div class="text-center px-2 py-3"><i class="fa fa-star-o fa-2x" aria-hidden="true"></i><h3>You have no new notifications</h3></div>'
+        // }
+//
+//         document.getElementById('notification-list').innerHTML = messages;
+//     });
+// }
 
-function mark_all_read(el) {
-    request_reinitiate(notify_api_url_mark_all_read + '?json=1')
-}
-
-function mark_toggle(el) {
-    request_reinitiate(notify_api_url_toggle_read + $(el).data('slug') + '/?json=1')
-}
-
-
-function fill_notification_badge(data) {
-    var badges = document.getElementsByClassName(notify_badge_class);
-    var container = $('.' + notify_container_class);
-    if (badges) {
-        for(var i = 0; i < badges.length; i++){
-            badges[i].innerHTML = data.unread_count;
-            if (data.unread_count > 0) {
-                container.addClass('positive_count');
-            } else {
-                container.removeClass('positive_count');
-            }
-        }
-    }
-}
-
-function get_notification_list() {
-    fetch_api_data(notify_api_url_list, true, function(data) {
-
-        var messages = data.list.map(function (item) {
-            var message = "<div>";
-            if(typeof item.actor !== 'undefined'){
-                message += '<strong>' + item.actor + '</strong>';
-            }
-            if(typeof item.verb !== 'undefined'){
-                message += " " + item.verb;
-            }
-            if(typeof item.target !== 'undefined'){
-                if(typeof item.forward_link !== 'undefined') {
-                    message += " <a href='" + item.forward_link + "'>" + item.target + "</a>";
-                } else {
-                    message += " " + item.target;
-                }
-            }
-            if(typeof item.timesince !== 'undefined'){
-                message += "<br><small class='text-muted'>" + item.timesince + " ago</small>";
-            }
-            message += "</div>";
-
-            if(item.unread) {
-                var mark_as_read = '<div class="actions"><a href="javascript:;" data-slug="' + item.slug + '"><i class="fa fa-circle" data-toggle="tooltip" data-placement="auto" title="Mark as read" aria-hidden="true"></i></a></div>';
-            } else {
-                var mark_as_read = '<div class="actions"><a href="javascript:;" data-slug="' + item.slug + '"><i class="fa fa-circle-o" data-toggle="tooltip" data-placement="auto" title="Mark as unread" aria-hidden="true"></i></a></div>';
-            }
-            return '<li class="list-group-item ' + (item.unread ? ' active' : '') + '">' + message + mark_as_read + '</li>';
-        }).join('');
-
-        if (messages == '') {
-            messages = '<div class="text-center px-2 py-3"><i class="fa fa-star-o fa-2x" aria-hidden="true"></i><h3>You have no new notifications</h3></div>'
-        }
-
-        document.getElementById('notification-list').innerHTML = messages;
-    });
-}
-
-function fetch_api_data(url, once, callback) {
+function fetch_api_data(callback, url, args) {
     if (!url) {
         var url = notify_api_url_count;
     }
-    if (!once) {
-        var once = false;
-    }
 
-    if (registered_functions.length > 0) {
+    if (callback) {
         //only fetch data if a function is setup
         var r = new XMLHttpRequest();
         r.addEventListener('readystatechange', function(event){
@@ -152,11 +139,8 @@ function fetch_api_data(url, once, callback) {
                 if (this.status === 200){
                     consecutive_misfires = 0;
                     var data = JSON.parse(r.responseText);
-                    registered_functions.forEach(function (func) { func(data); });
-                    if (callback) {
-                        return callback(data);
-                    }
-                }else{
+                    return callback(data, args);
+                } else {
                     consecutive_misfires++;
                 }
             }
@@ -164,32 +148,127 @@ function fetch_api_data(url, once, callback) {
         r.open("GET", url + '?max=' + notify_fetch_count, true);
         r.send();
     }
-    var timer = null;
-    if (!once) {
-        if (consecutive_misfires < 10 && !once) {
-            timer = setTimeout(fetch_api_data, notify_refresh_period);
-        } else {
-            var badges = document.getElementsByClassName(notify_badge_class);
-            if (badges) {
-                for (var i=0; i < badges.length; i++){
-                    badges[i].innerHTML = "!";
-                    badges[i].title = "Connection lost!"
-                }
+}
+
+// setTimeout(fetch_api_data, 1000);
+
+
+function update_counter_callback(data, args) {
+    var counter = data['unread_count'];
+    var el = $(args['element']);
+
+    if (typeof counter == 'undefined') {
+        counter = 0;
+    }
+
+    el.html(counter);
+    if (counter > 0) {
+        el.parents('.notifications_container').addClass('positive_count')
+    } else {
+        el.parents('.notifications_container').removeClass('positive_count')
+    }
+}
+
+function update_list_callback(data, args) {
+    var items = data['list'];
+    var el = $(args['element']);
+
+    var messages = items.map(function (item) {
+        // Notification content
+        var message = '';
+        if(typeof item.actor !== 'undefined'){
+            message += '<strong>' + item.actor + '</strong>';
+        }
+        if(typeof item.verb !== 'undefined'){
+            message += " " + item.verb;
+        }
+        if(typeof item.target !== 'undefined'){
+            if(typeof item.forward_link !== 'undefined') {
+                message += " <a href='" + item.forward_link + "'>" + item.target + "</a>";
+            } else {
+                message += " " + item.target;
             }
         }
-    }
+        if(typeof item.timesince !== 'undefined'){
+            message += "<br><small class='text-muted'>" + item.timesince + " ago</small>";
+        }
+
+        // Notification actions
+        if(item.unread) {
+            var mark_toggle = '<a href="javascript:;" class="mark-toggle" data-slug="' + item.slug + '"><i class="fa fa-circle" data-toggle="tooltip" data-placement="auto" title="Mark as read" aria-hidden="true"></i></a>';
+        } else {
+            var mark_toggle = '<a href="javascript:;" class="mark-toggle" data-slug="' + item.slug + '"><i class="fa fa-circle-o" data-toggle="tooltip" data-placement="auto" title="Mark as unread" aria-hidden="true"></i></a>';
+        }
 
-    return stop;
-    function stop() {
-        if (timer) {
-            clearTimeout(timer);
-            timer = 0;
+        if(typeof item.forward_link !== 'undefined') {
+            mark_toggle += "<br><a href='" + item.forward_link + "' data-toggle='tooltip' data-placement='auto' title='Go to item'><i class='fa fa-share' aria-hidden='true'></i></a>";
         }
+
+        // Complete list html
+        return '<li class="dropdown-item ' + (item.unread ? ' active' : '') + '"><div>' + message + '</div><div class="actions">' + mark_toggle + '</div></li>';
+    }).join('');
+
+    if (messages == '') {
+        messages = '<li class="dropdown-item px-5"><em>You have no new notifications</em></li>'
     }
+
+    // Fill DOM
+    el.find('.live_notify_list').html(messages).trigger('refresh_notify_list');
+}
+
+function update_mark_callback(data, args) {
+    var el = $(args['element']);
+    $(el).parents('.dropdown-item').toggleClass('active');
+
+    // $('.live_notify_badge').each(function(index, el) {
+    //     update_counter(el);
+    // });
 }
 
-setTimeout(fetch_api_data, 1000);
+
+function update_counter(el) {
+    fetch_api_data(update_counter_callback, "/notifications/api/unread_count/", {'element': el});
+}
+
+function mark_toggle(el) {
+    var url = "/notifications/mark-toggle/" + $(el).data('slug') + "?json=1";
+    fetch_api_data(update_mark_callback, url, {'element': el});
+}
+
+function update_list(el) {
+    fetch_api_data(update_list_callback, "/notifications/api/list/?mark_as_read=1", {'element': el});
+}
 
 $(function(){
-    initiate_popover();
+    $('.notifications_container')
+    .on('show.bs.dropdown', function() {
+        $(this).trigger('notification_open_list');
+    })
+    .on('notification_open_list', function() {
+        update_list(this);
+    })
+
+    $('.live_notify_badge').on('notification_count_updated', function() {
+        update_counter(this);
+    }).trigger('notification_count_updated');
+
+
+    $('.live_notify_list').on('refresh_notify_list', function() {
+        // Bloody js
+        $(this).find('li.dropdown-item').on('click', function(e) {
+            e.stopPropagation();
+        });
+        $(this).find('[data-toggle="tooltip"]').tooltip({
+            animation: false,
+            delay: {"show": 500, "hide": 100},
+            fallbackPlacement: 'clockwise',
+            placement: 'bottom'
+        });
+        $(this).find('.actions a.mark-toggle').on('click', function(e) {
+            e.stopPropagation();
+            mark_toggle(this);
+        });
+    });
+
+    // initiate_popover();
 });
diff --git a/scipost/templates/scipost/navbar.html b/scipost/templates/scipost/navbar.html
index 93ccffea2..ff16f034b 100644
--- a/scipost/templates/scipost/navbar.html
+++ b/scipost/templates/scipost/navbar.html
@@ -3,74 +3,75 @@
 {% load scipost_extras %}
 
 
-<nav class="navbar navbar-scroll navbar-light main-nav navbar-expand-lg">
-    <div class="navbar-scroll-inner">
-        <ul class="navbar-nav mr-auto">
-          <li class="nav-item{% if request.path == '/' %} active{% endif %}">
-            <a href="{% url 'scipost:index' %}" class="nav-link">Home</a>
-          </li>
-          <li class="nav-item{% if '/journals/' in request.path %} active{% endif %}">
-            <a href="{% url 'journals:journals' %}" class="nav-link">Journals</a>
-          </li>
-          <li class="nav-item{% if '/submissions/' in request.path %} active{% endif %}">
-            <a class="nav-link" href="{% url 'submissions:submissions' %}">Submissions</a>
-          </li>
-          <li class="nav-item{% if '/commentaries/' in request.path %} active{% endif %}">
-            <a class="nav-link" href="{% url 'commentaries:commentaries' %}">Commentaries</a>
+<nav class="navbar navbar-light main-nav navbar-expand-lg">
+    <ul id="menu-navbar" class="navbar-nav collapse">
+      <li class="nav-item{% if request.path == '/' %} active{% endif %}">
+        <a href="{% url 'scipost:index' %}" class="nav-link">Home</a>
+      </li>
+      <li class="nav-item{% if '/journals/' in request.path %} active{% endif %}">
+        <a href="{% url 'journals:journals' %}" class="nav-link">Journals</a>
+      </li>
+      <li class="nav-item{% if '/submissions/' in request.path %} active{% endif %}">
+        <a class="nav-link" href="{% url 'submissions:submissions' %}">Submissions</a>
+      </li>
+      <li class="nav-item{% if '/commentaries/' in request.path %} active{% endif %}">
+        <a class="nav-link" href="{% url 'commentaries:commentaries' %}">Commentaries</a>
+      </li>
+      <li class="nav-item{% if '/theses/' in request.path %} active{% endif %}">
+        <a class="nav-link" href="{% url 'theses:theses' %}">Theses</a>
+      </li>
+      <li class="nav-item{% if '/about' in request.path %} active{% endif %}">
+        <a class="nav-link" href="{% url 'scipost:about' %}">About SciPost</a>
+      </li>
+
+
+
+      {% if user.is_authenticated %}
+        {% if request.user|is_in_group:'Testers' %}
+          <li class="nav-item highlighted dropdown navbar-counter">
+            <div class="nav-link notifications_container">
+                <a href="javascript:;" class="d-inline-block ml-1 dropdown-toggle badge_link" id="notifications_badge" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                    <span class="user">{% if user.last_name %}{% if user.contributor %}{{ user.contributor.get_title_display }} {% endif %}{{ user.first_name }} {{ user.last_name }}{% else %}{{ user.username }}{% endif %}</span>
+                    <i class="fa fa-inbox" aria-hidden="true"></i>
+                    {% live_notify_badge classes="badge badge-pill badge-primary" %}
+                </a>
+                {% live_notify_list %}
+            </div>
+
           </li>
-          <li class="nav-item{% if '/theses/' in request.path %} active{% endif %}">
-            <a class="nav-link" href="{% url 'theses:theses' %}">Theses</a>
+      {% else %}
+          <li class="nav-item highlighted">
+            <span class="nav-link">Logged in as {{ user.username }}</span>
           </li>
-          <li class="nav-item{% if '/about' in request.path %} active{% endif %}">
-            <a class="nav-link" href="{% url 'scipost:about' %}">About SciPost</a>
+      {% endif %}
+          <li class="nav-item">
+              <a class="nav-link" href="{% url 'scipost:logout' %}">Logout</a>
           </li>
-
-          {% if user.is_authenticated %}
-            {% if request.user|is_in_group:'Testers' %}
-              <li class="nav-item highlighted dropdown navbar-counter">
-                <div class="nav-link">
-                    <a href="javascript:;" class="d-inline-block ml-1 dropdown-toggle notifications_container" id="notifications_badge">
-                        <span class="user">{% if user.last_name %}{% if user.contributor %}{{ user.contributor.get_title_display }} {% endif %}{{ user.first_name }} {{ user.last_name }}{% else %}{{ user.username }}{% endif %}</span>
-                        <i class="fa fa-inbox" aria-hidden="true"></i>
-                        {% live_notify_badge classes="badge badge-pill badge-primary" %}
-                    </a>
-                    {% live_notify_list classes="update_notifications d-none" %}
-                </div>
-
-              </li>
-          {% else %}
-              <li class="nav-item highlighted">
-                <span class="nav-link">Logged in as {{ user.username }}</span>
+          {% if perms.scipost.can_view_production %}
+              <li class="nav-item{% if '/production' in request.path %} active{% endif %}">
+                <a class="nav-link" href="{% url 'production:production' %}">Production</a>
               </li>
           {% endif %}
-              <li class="nav-item">
-                  <a class="nav-link" href="{% url 'scipost:logout' %}">Logout</a>
+          {% if user.contributor %}
+              <li class="nav-item{% if '/personal_page' in request.path %} active{% endif %}">
+                <a class="nav-link" href="{% url 'scipost:personal_page' %}">Personal Page</a>
               </li>
-              {% if perms.scipost.can_view_production %}
-                  <li class="nav-item{% if '/production' in request.path %} active{% endif %}">
-                    <a class="nav-link" href="{% url 'production:production' %}">Production</a>
-                  </li>
-              {% endif %}
-              {% if user.contributor %}
-                  <li class="nav-item{% if '/personal_page' in request.path %} active{% endif %}">
-                    <a class="nav-link" href="{% url 'scipost:personal_page' %}">Personal Page</a>
-                  </li>
-              {% endif %}
-              {% if user.partner_contact %}
-                  <li class="nav-item{% if '/partners/dashboard' in request.path %} active{% endif %}">
-                    <a class="nav-link" href="{% url 'partners:dashboard' %}">Partner Page</a>
-                  </li>
-              {% endif %}
-          {% else %}
-              <li class="nav-item{% if request.path == '/login/' %} active{% endif %}">
-                <a class="nav-link" href="{% url 'scipost:login' %}">Login</a>
+          {% endif %}
+          {% if user.partner_contact %}
+              <li class="nav-item{% if '/partners/dashboard' in request.path %} active{% endif %}">
+                <a class="nav-link" href="{% url 'partners:dashboard' %}">Partner Page</a>
               </li>
           {% endif %}
+      {% else %}
+          <li class="nav-item{% if request.path == '/login/' %} active{% endif %}">
+            <a class="nav-link" href="{% url 'scipost:login' %}">Login</a>
+          </li>
+      {% endif %}
 
-        </ul>
-        <form action="{% url 'scipost:search' %}" method="get" class="form-inline search-nav-form">
-            <input class="form-control" id="id_q" maxlength="100" name="q" type="text" required="required" value="{{search_query|default:''}}">
-            <input class="btn btn-secondary" type="submit" value="Search">
-        </form>
-    </div>
+    </ul>
+    <a class="btn btn-block my-2" data-toggle="collapse" href="#menu-navbar" aria-expanded="false" aria-controls="menu-navbar">Show menu <i class="fa fa-angle-down" aria-hidden="true"></i></a>
+    <form action="{% url 'scipost:search' %}" method="get" class="form-inline search-nav-form">
+        <input class="form-control" id="id_q" maxlength="100" name="q" type="text" required="required" value="{{search_query|default:''}}">
+        <input class="btn btn-secondary" type="submit" value="Search">
+    </form>
 </nav>
-- 
GitLab