diff --git a/funders/views.py b/funders/views.py index 8a2593f66dbad45d914f89e3efd0150c15f8749d..1b3d3b8c20ab40e39a335be12f57d250615c24f6 100644 --- a/funders/views.py +++ b/funders/views.py @@ -10,7 +10,7 @@ from .models import Funder, Grant from .forms import FunderRegistrySearchForm, FunderForm, GrantForm -@permission_required('scipost.can_publish_accepted_submission', raise_exception=True) +@permission_required('scipost.can_view_all_funding_info', raise_exception=True) def funders(request): funders = Funder.objects.all() form = FunderRegistrySearchForm() @@ -21,7 +21,7 @@ def funders(request): return render(request, 'funders/funders.html', context) -@permission_required('scipost.can_publish_accepted_submission', raise_exception=True) +@permission_required('scipost.can_view_all_funding_info', raise_exception=True) def query_crossref_for_funder(request): """ Checks Crossref's Fundref Registry for an entry @@ -41,7 +41,7 @@ def query_crossref_for_funder(request): return render(request, 'funders/query_crossref_for_funder.html', context) -@permission_required('scipost.can_publish_accepted_submission', raise_exception=True) +@permission_required('scipost.can_view_all_funding_info', raise_exception=True) def add_funder(request): form = FunderForm(request.POST or None) if form.is_valid(): @@ -63,7 +63,7 @@ def funder_publications(request, funder_id): return render(request, 'funders/funder_details.html', context) -@permission_required('scipost.can_publish_accepted_submission', raise_exception=True) +@permission_required('scipost.can_view_all_funding_info', raise_exception=True) def add_grant(request): grant_form = GrantForm(request.POST or None) if grant_form.is_valid(): diff --git a/notifications/migrations/0005_auto_20171105_1004.py b/notifications/migrations/0005_auto_20171105_1004.py new file mode 100644 index 0000000000000000000000000000000000000000..6fa563d7794c73ef134263774bd4dc39936b5a60 --- /dev/null +++ b/notifications/migrations/0005_auto_20171105_1004.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-11-05 09:04 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifications', '0004_merge_20171103_1132'), + ] + + operations = [ + migrations.AddField( + model_name='notification', + name='unread_datetime', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AlterField( + model_name='notification', + name='created', + field=models.DateTimeField(auto_now_add=True), + ), + ] diff --git a/notifications/migrations/0006_remove_notification_unread_datetime.py b/notifications/migrations/0006_remove_notification_unread_datetime.py new file mode 100644 index 0000000000000000000000000000000000000000..8de0a18add4020f5ac0f0715a493efb758f09adf --- /dev/null +++ b/notifications/migrations/0006_remove_notification_unread_datetime.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-11-05 09:09 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifications', '0005_auto_20171105_1004'), + ] + + operations = [ + migrations.RemoveField( + model_name='notification', + name='unread_datetime', + ), + ] diff --git a/notifications/models.py b/notifications/models.py index 9ba39d7c684158db8ec5de3fc6fbc4f8e11dc644..e05b53710ade32063ef292107119e6f9b0d4835c 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -62,7 +62,7 @@ class Notification(models.Model): action_object_object_id = models.CharField(max_length=255, blank=True, null=True) action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id') - created = models.DateTimeField(default=timezone.now) + created = models.DateTimeField(auto_now_add=True) # This field is for internal use only. It is used to prevent duplicate sending # of notifications. diff --git a/notifications/templatetags/notifications_tags.py b/notifications/templatetags/notifications_tags.py index 900fa7c96459869ac6522ed42bb86a3c0781e87b..8d8bccd2402cd1f213000b4597ba82bc67390833 100644 --- a/notifications/templatetags/notifications_tags.py +++ b/notifications/templatetags/notifications_tags.py @@ -18,38 +18,43 @@ def live_notify_list(context): if not user: return '' - html = '<div class="dropdown-menu notifications">' + html = '<div class="popover-template popover">' + html += '<div class="popover notifications" role="tooltip">' # User default links - html += '<h6 class="dropdown-header">Welcome {first_name} {last_name}</h6>'.format( + html += '<h6 class="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( + html += '<a class="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( + html += '<a class="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( + html += '<a class="item" href="{url}">Financial Administration</a>'.format( url=reverse('finances:finance')) + if user.has_perm('scipost.can_view_all_funding_info'): + html += '<a class="item" href="{url}">Funders</a>'.format( + url=reverse('funders:funders')) if user.has_perm('scipost.can_view_production'): - html += '<a class="dropdown-item" href="{url}">Production</a>'.format( + html += '<a class="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( + html += '<a class="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( + html += '<div class="divider"></div>' + html += '<a class="item" href="{url}">Logout</a>'.format( url=reverse('scipost:logout')) # Notifications - html += '<div class="dropdown-divider my-0"></div><h6 class="dropdown-header">Inbox</h6>' + html += '<div class="divider"></div><h6 class="header">Inbox</h6>' html += '<div class="live_notify_list"></div></div>' + html += '<div class="popover-body"></div></div>' return format_html(html) diff --git a/scipost/static/scipost/assets/config/preconfig.scss b/scipost/static/scipost/assets/config/preconfig.scss index 63ef8702d5ef1fb7c096e2ffaeeee6a3f3a3704a..67b14aebb660f6e677e7fb8e820338a89786ea26 100644 --- a/scipost/static/scipost/assets/config/preconfig.scss +++ b/scipost/static/scipost/assets/config/preconfig.scss @@ -65,12 +65,6 @@ $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 // diff --git a/scipost/static/scipost/assets/css/_navbar.scss b/scipost/static/scipost/assets/css/_navbar.scss index dc38e17d6eb38b02bee82f3dd8676017185bdddf..211d612f9d49f42ea5ea0de34305cc0f567830f8 100644 --- a/scipost/static/scipost/assets/css/_navbar.scss +++ b/scipost/static/scipost/assets/css/_navbar.scss @@ -94,6 +94,10 @@ .navbar-counter { position: relative; + .nav-link.notifications_container:hover { + background-color: #fff; + } + a.dropdown-toggle { min-width: 45px; } @@ -138,9 +142,13 @@ } .fa-inbox { - font-size: 150%; vertical-align: bottom; margin: 0 0.25rem; + min-width: 17px; + + &:before { + font-size: 150%; + } } &.show .fa-inbox { diff --git a/scipost/static/scipost/assets/css/_dropdown.scss b/scipost/static/scipost/assets/css/_notifications.scss similarity index 73% rename from scipost/static/scipost/assets/css/_dropdown.scss rename to scipost/static/scipost/assets/css/_notifications.scss index e1ca413f3a08e1c96d252ce5e4a33d5fc8dd60c1..8670e2f38dbbc8047210e2cf016255b074506a33 100644 --- a/scipost/static/scipost/assets/css/_dropdown.scss +++ b/scipost/static/scipost/assets/css/_notifications.scss @@ -3,16 +3,26 @@ background-color: $white; } +.popover-template { + display: none; +} + .notifications { - padding-top: 0; - padding-bottom: 0; + padding: 0; + min-width: 500px; - .dropdown-header { + .header { padding: 1rem 1rem 0.5rem 1rem; background-color: #f9f9f9; } - .dropdown-item { + li.item { + &[href]:hover { + background-color: #f9f9f9; + } + } + + .item { padding: 0.4rem 1rem; border-radius: 0; border-top: 1px solid #fff; @@ -22,6 +32,15 @@ justify-content: space-between; display: flex; + &[href] { + cursor: pointer; + } + + &.active, + &.active[href]:hover { + background-color: $scipost-lightestblue; + } + > div { white-space: normal; } @@ -31,8 +50,8 @@ } } - a.dropdown-item, - .dropdown-item a { + a.item, + .item a { color: $scipost-lightblue; &:hover { @@ -41,7 +60,7 @@ } .actions { - display: none; + // display: none; opacity: 0.0; transition: opacity 0.1s; width: 20px; @@ -65,17 +84,7 @@ } } - .dropdown-item:hover .actions { + .item:hover .actions { opacity: 1.0; } } - -@media (min-width: 768px) { - .notifications { - min-width: 500px; - - .actions { - display: block; - } - } -} diff --git a/scipost/static/scipost/assets/css/style.scss b/scipost/static/scipost/assets/css/style.scss index 0c8543be7bae804e5d6b33003dea8c56748b2c20..5b2d4702fc9744c9f3ab74936d10a968850e6049 100644 --- a/scipost/static/scipost/assets/css/style.scss +++ b/scipost/static/scipost/assets/css/style.scss @@ -21,7 +21,6 @@ @import "buttons"; @import "cards"; @import "code"; -@import "dropdown"; @import "form"; @import "grid"; @import "homepage"; @@ -31,6 +30,7 @@ @import "modal"; @import "navbar"; @import "nav"; +@import "notifications"; @import "page_header"; @import "pool"; @import "tables"; diff --git a/scipost/static/scipost/assets/js/notifications.js b/scipost/static/scipost/assets/js/notifications.js index a2d966ccd609d80ae51585dffda11ec2798b24c3..a20d3a146c7ff98bf3ac7a5642dce137ecd2dd2b 100644 --- a/scipost/static/scipost/assets/js/notifications.js +++ b/scipost/static/scipost/assets/js/notifications.js @@ -45,7 +45,9 @@ function update_list_callback(data, args) { var messages = items.map(function (item) { // Notification content - var message = ''; + var message = '', + link = ''; + if(typeof item.actor !== 'undefined'){ message += '<strong>' + item.actor + '</strong>'; } @@ -54,6 +56,7 @@ function update_list_callback(data, args) { } if(typeof item.target !== 'undefined'){ if(typeof item.forward_link !== 'undefined') { + link = item.forward_link; message += " <a href='" + item.forward_link + "'>" + item.target + "</a>"; } else { message += " " + item.target; @@ -79,24 +82,26 @@ function update_list_callback(data, args) { } // Complete list html - return '<li class="dropdown-item ' + (item.unread ? ' active' : '') + '"><div>' + message + '</div><div class="actions">' + mark_toggle + '</div></li>'; + if(link !== '') { + return '<li href="' + link + '" class="item ' + (item.unread ? ' active' : '') + '"><div>' + message + '</div><div class="actions">' + mark_toggle + '</div></li>'; + } else { + return '<li class="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>' + messages = '<li class="item px-5"><em>You have no new notifications</em></li>' } // Fill DOM - el.find('.live_notify_list').html(messages).trigger('refresh_notify_list'); + el.find('.live_notify_list').html(messages).parents('body').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); - }); + $(el).parents('.item').toggleClass('active'); + trigger_badge(); } @@ -113,14 +118,27 @@ function update_list(el) { fetch_api_data(update_list_callback, "/notifications/api/list/?mark_as_read=1", {'element': el}); } -// setTimeout(fetch_api_data, 1000); +function trigger_badge() { + $('.live_notify_badge').trigger('notification_count_updated'); +} +// Update Badge count every minute +var badge_timer = setInterval(trigger_badge, 60000); + +function initiate_popover() { + var template = $('.notifications_container .popover-template').html(); + $('.notifications_container a[data-toggle="popover"]').popover({ + trigger: 'focus', + template: template, + placement: 'bottom', + title: 'empty-on-purpose' + }) + .on('inserted.bs.popover', function() { + $('body').trigger('notification_open_list'); + }); +} $(function(){ - $('.notifications_container') - .on('show.bs.dropdown', function() { - $(this).trigger('notification_open_list'); - }) - .on('notification_open_list', function() { + $('body').on('notification_open_list', function() { update_list(this); }) @@ -129,22 +147,26 @@ $(function(){ }).trigger('notification_count_updated'); - $('.live_notify_list').on('refresh_notify_list', function() { + $('body').on('refresh_notify_list', function() { // Bloody js - $(this).find('li.dropdown-item').on('click', function(e) { + var list = $('.live_notify_list'); + list.find('li.item').on('click', function(e) { e.stopPropagation(); + }) + .filter('[href]').on('click', function(e) { + window.location.href = $(this).attr('href') }); - $(this).find('[data-toggle="tooltip"]').tooltip({ + list.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) { + list.find('.actions a.mark-toggle').on('click', function(e) { e.stopPropagation(); mark_toggle(this); }); }); - // initiate_popover(); + initiate_popover(); }); diff --git a/scipost/templates/scipost/navbar.html b/scipost/templates/scipost/navbar.html index 9136679e461c8b55fa9a691c384c92f66a96c3d5..6c0bea234470a3afe91bf080a4bf276f6978e84c 100644 --- a/scipost/templates/scipost/navbar.html +++ b/scipost/templates/scipost/navbar.html @@ -28,9 +28,9 @@ {% if user.is_authenticated %} {% if request.user|is_in_group:'Testers' %} - <li class="nav-item highlighted dropdown navbar-counter"> + <li class="nav-item highlighted 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"> + <a href="javascript:;" class="d-inline-block ml-1 badge_link" id="notifications_badge" data-toggle="popover"> <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" %}