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