Skip to content
Snippets Groups Projects
Select Git revision
  • 715fa1881de122b7101091dd13affe0f6a17c429
  • main default protected
  • studip-rector
  • ci-opt
  • course-members-export-as-word
  • data-vue-app
  • pipeline-improvements
  • webpack-optimizations
  • rector
  • icon-renewal
  • http-client-and-factories
  • jsonapi-atomic-operations
  • vueify-messages
  • tic-2341
  • 135-translatable-study-areas
  • extensible-sorm-action-parameters
  • sorm-configuration-trait
  • jsonapi-mvv-routes
  • docblocks-for-magic-methods
19 results

personal_notifications.js

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    personal_notifications.js 7.73 KiB
    import Favico from 'favico.js';
    import Cache from './cache.js';
    import PageLayout from './page_layout.js';
    import { $gettextInterpolate, $ngettext } from './gettext';
    
    var stack = {};
    var audio_notification = false;
    var directlydeleted = [];
    var favicon = null;
    
    function updateFavicon(text) {
        if (favicon === null) {
            var valid = $('head')
                .find('link[rel=icon]')
                .first();
            $('head')
                .find('link[rel*=icon]')
                .not(valid)
                .remove();
    
            favicon = new Favico({
                bgColor: '#d60000',
                textColor: '#fff',
                fontStyle: 'normal',
                fontFamily: 'Lato',
                position: 'right',
                type: 'rectangle'
            });
        }
        favicon.badge(text);
    }
    
    // Wrapper function that creates a desktop notification from given data
    function create_desktop_notification(data) {
        var notification = new Notification(STUDIP.STUDIP_SHORT_NAME, {
            body: data.text,
            icon: data.avatar,
            tag: data.id
        });
        notification.addEventListener('click', () => {
            location.href = STUDIP.URLHelper.getURL(`dispatch.php/jsupdater/mark_notification_read/${notification.tag}`);
        });
    }
    
    // Handler for all notifications received by an ajax request
    function process_notifications({ notifications }) {
        var cache = Cache.getInstance('desktop.notifications');
        var ul = $('<ul/>');
        var changed = false;
        var new_stack = {};
    
        notifications.forEach(notification => {
            if (directlydeleted.indexOf(notification.personal_notification_id) !== -1) {
                return;
            }
    
            ul.append(notification.html);
    
            var id = $('.notification:last', ul).data().id;
            new_stack[id] = notification;
            if (notification.html_id) {
                $(`#${notification.html_id}`).on('mouseenter', PersonalNotifications.isVisited);
            }
    
            changed = changed || stack[id] === undefined;
    
            // Check if notifications should be sent (depends on the
            // Notification itself and session storage)
            if (
                window.Notification === undefined
                || Notification.permission !== 'granted'
                || cache.has(notification.id)
            ) {
                return;
            }
    
            // If it's okay let's create a notification
            create_desktop_notification(notification);
    
            cache.set(id, true);
        });
    
        // Anything changed? Replace stack and display
        if (changed || Object.keys(stack).length !== Object.keys(new_stack).length) {
            stack = new_stack;
            $('#notification_list > ul').replaceWith(ul);
        }
    
        PersonalNotifications.update();
        directlydeleted = [];
    }
    
    const PersonalNotifications = {
        initialize () {
            if ($('#notification_marker .count').length > 0) {
                $('#notification_list .notification').map(function() {
                    var data = $(this).data();
                    stack[data.id] = data;
                });
    
                STUDIP.JSUpdater.register(
                    'personalnotifications',
                    process_notifications,
                    null,
                    60000
                );
    
                if ($('#audio_notification').length > 0) {
                    audio_notification = $('#audio_notification').get(0);
                    audio_notification.load();
                }
    
                if ('Notification' in window) {
                    $('#notification_list .enable-desktop-notifications')
                        .toggle(Notification.permission === 'default')
                        .click(STUDIP.PersonalNotifications.activate);
                }
            }
    
            // Special handling for personal notifications:
            $('#notification-container').on('mouseover mouseout', function (event) {
                $(this).attr('aria-expanded', $(this).attr('aria-expanded') === 'true' ? 'false' : 'true');
            });
        },
        activate () {
            Promise.resolve(Notification.requestPermission()).then(permission => {
                $('#notification_list .enable-desktop-notifications')
                    .toggle(permission === 'default');
            });
        },
        markAsRead (event) {
            var notification = $(this).closest('.notification'),
                id = notification.data().id;
            PersonalNotifications.sendReadInfo(id, notification);
            return false;
        },
        markAllAsRead (event) {
            var notifications = $(this)
                .parent()
                .find('.notification');
            PersonalNotifications.sendReadInfo('all', notifications);
            return false;
        },
        sendReadInfo (id, notification) {
            $.get(STUDIP.URLHelper.getURL(`dispatch.php/jsupdater/mark_notification_read/${id}`)).done(() => {
                if (notification) {
                    var count = notification.length;
                    notification.toggle('blind', 'fast', function() {
                        var data = $(this).data();
                        delete stack[data.id];
                        $(this).remove();
    
                        count -= 1;
                        if (count === 0) {
                            PersonalNotifications.update();
                        }
                    });
                }
            });
        },
        update () {
            var count = _.values(stack).length;
            var old_count = parseInt($('#notification_marker .count').text(), 10);
            var really_new = 0;
            $('#notification_list > ul > li').each(function() {
                if (parseInt($(this).data('timestamp'), 10) > parseInt($('#notification_marker').data('lastvisit'), 10)) {
                    really_new += 1;
                }
            });
            if (really_new > 0) {
                $('#notification_marker')
                    .data('seen', false);
                $('#avatar-menu-container')
                    .addClass('alert');
                PageLayout.title_prefix = '(!) ';
            } else {
                $('#avatar-menu-container').removeClass('alert');
                PageLayout.title_prefix = '';
            }
            if (count) {
                $('#notification-container').addClass('hoverable');
                $('#notification_marker').prop('disabled', false);
                if (count > old_count && audio_notification !== false) {
                    audio_notification.play();
                }
            } else {
                $('#notification-container').removeClass('hoverable');
                $('#notification_marker').prop('disabled', true);
            }
            if (old_count !== count) {
                $('#notification_marker .count').text(count);
                let notification_text = $ngettext('%{ count } Benachrichtigung', '%{ count } Benachrichtigungen', count);
                $('#notification_marker').attr('title', $gettextInterpolate(notification_text, {count: count}));
                updateFavicon(count);
                $('#notification-container .mark-all-as-read').toggleClass('invisible', count < 2);
            }
        },
        isVisited () {
            const id = this.id;
            $.each(stack, (index, notification) => {
                if (notification.html_id === id) {
                    PersonalNotifications.sendReadInfo(notification.personal_notification_id);
    
                    delete stack[index];
    
                    $(`.notification[data-id=${notification.personal_notification_id}]`).fadeOut(function () {
                        $(this).remove();
                    });
    
                    directlydeleted.push(notification.personal_notification_id);
    
                    PersonalNotifications.update();
                }
            });
        },
        setSeen () {
            if ($('#notification_marker').data('seen')) {
                return;
            }
            $('#notification_marker').data('seen', true);
    
            $.get(STUDIP.URLHelper.getURL('dispatch.php/jsupdater/notifications_seen')).then(time => {
                $('#notification_marker')
                    .data('lastvisit', time);
                $('#avatar-menu-container')
                    .removeClass('alert');
                    
            });
        }
    };
    
    export default PersonalNotifications;