Greasy Fork is available in English.

Whova Session Streamlined

Remove obtrusive elements of a Whova browser session

// ==UserScript==
// @name         Whova Session Streamlined
// @namespace    https://github.com/amclark42/whova-session-streamlined
// @version      1.1
// @description  Remove obtrusive elements of a Whova browser session
// @author       Ash Clark
// @match        https://whova.com/portal/webapp/*
// @license      Unlicense
// ==/UserScript==

(function() {
  'use strict';

  console.log("Userscript loaded.");
  
  /* Create an internal CSS stylesheet for this page. */
  let addStyles = function () {
    var css, styles = '';
    css = document.createElement('style');
    styles += ".no-notify .small-red-dot, .no-notify .notification-circle,\n"
      + ".no-notify .red-tag.solid-tag { display: none; }\n";
    styles += ".btn-toggle { padding: 1em 0.5em; }\n";
    styles += ".btn-toggle:hover, .btn-toggle:focus { background-color: #cde }\n";
    styles += ".btn-toggle svg { margin: 0 0.5em; }\n";
    styles += ".whova-side-navigation-menu.collapsed { min-width:unset; width: auto; }\n"
    styles += ".collapsed.whova-side-navigation-menu #whova-side-navigation-base-section, "
      + ".collapsed.whova-side-navigation-menu #whova-side-nav-scroll { display:none; }\n"
    styles += ".main-content .page-content { flex: 1 1 90%; width: auto; }\n";
    styles += ".session-media-hub-video-player #session-video-iframe, .session-media-hub-video-player .session-external-player-wrapper"
      + "{ height: 80vh; }";
    styles += ".agendav3-session-details-page-container .agenda-v3-compact-boards-container" 
      + "{ min-width: fit-content; }\n";
    styles += ".tab-list-container { min-width: 350px; }\n";
    styles += ".collapsed.tab-list-container { min-width: unset; }\n";
    styles += ".collapsed.tab-list-container .tabs { flex-direction: column; }\n";
    styles += ".collapsed.tab-list-container .tab-panel-container { display: none; }\n";
    /* Add CSS styles to <head>. */
    css.appendChild(document.createTextNode(styles));
    document.getElementsByTagName('head')[0].appendChild(css);
  };
  // END addStyles()
  
  /* Recreate a SVG icon from Bootstrap:
      https://icons.getbootstrap.com/icons/signpost-split/ */
  const expandIcon = function () {
    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
        title = document.createElementNS('http://www.w3.org/2000/svg', 'title'),
        path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    svg.setAttributeNS(null, 'width', 16);
    svg.setAttributeNS(null, 'height', 16);
    svg.setAttributeNS(null, 'viewBox', '0 0 16 16');
    svg.setAttributeNS(null, 'fill', 'currentColor');
    title.appendChild(document.createTextNode('Toggle site navigation'));
    path.setAttributeNS(null, 'd', 
      'M7 7V1.414a1 1 0 0 1 2 0V2h5a1 1 0 0 1 .8.4l.975 1.3a.5.5 0 0 1 0 .6L14.8 5.6a1 1 0 0 1-.8.4H9v10H7v-5H2a1 1 0 0 1-.8-.4L.225 9.3a.5.5 0 0 1 0-.6L1.2 7.4A1 1 0 0 1 2 7h5zm1 3V8H2l-.75 1L2 10h6zm0-5h6l.75-1L14 3H8v2z');
    svg.appendChild(title);
    svg.appendChild(path);
    return svg;
  };
  // END expandIcon()
  
  /* Test a location pathname to determine if the current page is a Whova session. */
  let isSessionPage = function(page) {
    var regex = /\/portal\/webapp\/[\w_]+\/Agenda\/\w+/g;
    return regex.test(page);
  };
  // END isSessionPage()
  
  /* Tweak the DOM, set up styles, create event listeners. */
  let onLoad = function() {
    var sidebarNav, collapseBtnSide,
        pageNow, pagePrev, sessionModded,
        mutationOptions, mutationObserver;
    pageNow = window.location.pathname;
    pagePrev = pageNow;
    /* Clone the base toggle button for other uses. */
    collapseBtnSide = document.createElement('button');
    collapseBtnSide.classList.add('btn-toggle');
    /* Prepare the left-hand sidebar. */
    sidebarNav = document.getElementsByClassName('whova-side-navigation-menu');
    collapseBtnSide.setAttribute('id', 'toggle-sidenav');
    collapseBtnSide.addEventListener('click', toggleCollapse);
    collapseBtnSide.appendChild(expandIcon());
    /* Add custom CSS rules before directly modifying the DOM. */
    addStyles();
    if ( sidebarNav.length > 0 ) {
      sidebarNav = sidebarNav[0];
      try {
        sidebarNav.prepend(collapseBtnSide);
      } catch (err) {
        console.warn("Could not modify the sidebar nav.");
      }
    }
    /* Only modify the session page if the first page IS the session page. */
    if ( isSessionPage(pageNow) ) {
      updateSessionNav();
    }
    /* Monitor changes to the page, since Whova doesn't fully reload the page when 
      navigating around. */
    mutationObserver = new MutationObserver( function(records) {
      pageNow = window.location.pathname;
      if ( pageNow !== pagePrev ) {
        pagePrev = pageNow;
        console.log("Whova site navigated to new page: "+pageNow);
        if ( isSessionPage(pageNow) ) {
          console.log("Navigated to a Whova session.");
          sessionModded = false;
        }
      }
      /* Make sure that the session tabs navbar has been loaded before making any 
        changes. */
      if ( isSessionPage(pageNow) && !sessionModded
            && document.getElementsByClassName('tab-list-container').length > 0 ) {
        /* Wait a bit before modifying the session navbar. */
        setTimeout( function() { 
          if ( !sessionModded ) {
            sessionModded = true;
            console.log("Modifying the session navbar.");
            /* There is a possibility that updateSessionNav() will not have worked. 
              If so, sessionModded will be re-set and a future mutation may have 
              better luck. */
            sessionModded = updateSessionNav();
          }
        }, 300);
      }
    });
    // The kinds of observations to make.
    mutationOptions = { childList: true, subtree: true };
    mutationObserver.observe(document, mutationOptions);
  };
  // END onLoad()
  
  /* When a button is clicked to toggle a sidebar, try to toggle the 'collapsed' 
    class on the button's parent. */
  let toggleCollapse = function(event) {
    var container = event.target;
    if ( container.nodeName === "BUTTON" ) {
      container = container.parentElement;
    } else if ( container.nodeName === 'svg' ) {
      container = container.parentElement.parentElement;
    } else if ( container.nodeName === 'path' ) {
      container = container.parentElement.parentElement.parentElement;
    } else {
      console.warn(container.nodeName);
      return;
    }
    //console.log(container);
    container.classList.toggle('collapsed');
  };
  // END toggleCollapse()
  
  /* When one of the visible tabs is clicked on the right, open the sidebar. */
  let toggleCollapseIncidentally = function() {
    document.getElementsByClassName('tab-list-container')[0].classList.toggle(
      'collapsed', false);
  };
  // END toggleCollapseIncidentally()
  
  /* Use a class to prevent notifications from showing up. */
  let toggleNotifications = function() {
    document.getElementsByTagName('body')[0].classList.toggle('no-notify');
  };
  // END toggleNotifications()
  
  /* Prepare the right-hand sidebar inside a Whova session. Returns a boolean 
    indicating whether modifications have been successfully made. */
  let updateSessionNav = function() {
    var tabListNav, collapseBtnTab, notifyBtn;
    try {
      collapseBtnTab = document.createElement('button');
      collapseBtnTab.classList.add('btn-toggle');
      notifyBtn = collapseBtnTab.cloneNode(true);
      tabListNav = document.getElementsByClassName('tab-list-container');
      /* Make sure the tabs nav is available before making changes. */
      if ( tabListNav.length > 0 ) {
        tabListNav = tabListNav[0];
        tabListNav.classList.add('collapsed');
      } else {
        /* If there's nothing in the DOM we can augment, return early. */
        return false;
      }
      collapseBtnTab.setAttribute('id', 'toggle-tablist');
      collapseBtnTab.addEventListener('click', toggleCollapse);
      collapseBtnTab.appendChild(document.createTextNode("Toggle sidebar"));
      notifyBtn.appendChild(document.createTextNode("Toggle notifications"));
      notifyBtn.addEventListener('click', toggleNotifications);
      /* Add new elements to the page. */
      tabListNav.prepend(notifyBtn);
      tabListNav.prepend(collapseBtnTab);
      /* Make sure that clicking a tab in the right-hand nav will toggle the sidebar 
        open. */
      document.querySelectorAll('.tabs .tab-btn').forEach( function(btn) {
        btn.addEventListener('click', toggleCollapseIncidentally);
      });
    } catch (err) {
      /* Report the error in the console but recover from it. */
      console.warn(err);
      console.log("Userscript recovering.")
      return false;
    }
    return true;
  };
  // END updateSessionNav()
  
  /* Whova keeps loading content after the page is "complete". As such, we wait a 
    bit before running this userscript. */
  if (document.readyState == 'complete') {
    setTimeout(function() { onLoad(); }, 2500);
  } else {
    // Wait until page has loaded, then wait a bit more.
    window.addEventListener('load',function() {
      setTimeout(function() { onLoad(); }, 2500);
    });
  }
  
})();