$()

in pontoon/base/static/js/main.js [143:453]


$(function () {
  /*
   * If Google Analytics is enabled, the translate frontend will send additional about Ajax calls.
   *
   * To send an event to GA, We pass following informations:
   * event category - hardcoded 'ajax' string.
   * event action - hardcoded 'request' string.
   * event label - contains url that was called by $.ajax() call.
   *
   * GA Analytics enriches every event with additional information like e.g. browser, resolution, country etc.
   */
  $(document).ajaxComplete(function (event, jqXHR, settings) {
    if (typeof ga !== 'function') {
      return;
    }

    ga('send', 'event', 'ajax', 'request', settings.url);
  });

  /*
   * Display Pontoon Add-On Promotion, if:
   *
   * - Promotion not dismissed
   * - Add-On not installed
   * - Page loaded on Firefox or Chrome (add-on not available for other browsers)
   */
  setTimeout(function () {
    const dismissed = !$('#addon-promotion').length;
    const installed = window.PontoonAddon && window.PontoonAddon.installed;
    if (!dismissed && !installed) {
      const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1;
      const isChrome = navigator.userAgent.indexOf('Chrome') !== -1;
      let downloadHref = '';
      if (isFirefox) {
        downloadHref =
          'https://addons.mozilla.org/firefox/addon/pontoon-tools/';
      }
      if (isChrome) {
        downloadHref =
          'https://chrome.google.com/webstore/detail/pontoon-add-on/gnbfbnpjncpghhjmmhklfhcglbopagbb';
      }
      if (downloadHref) {
        $('#addon-promotion').find('.get').attr('href', downloadHref);
        $('body').addClass('addon-promotion-active');
      }
    }
    // window.PontoonAddon is made available by the Pontoon Add-On,
    // but not immediatelly after the DOM is ready
  }, 1000);

  // Dismiss Add-On Promotion
  $('#addon-promotion .dismiss').click(function () {
    Pontoon.NProgressUnbind();

    $.ajax({
      url: '/dismiss-addon-promotion/',
      success: function () {
        $('body').removeClass('addon-promotion-active');
      },
    });

    Pontoon.NProgressBind();
  });

  // Hide Add-On Promotion if Add-On installed while active
  window.addEventListener('message', (event) => {
    // only allow messages from authorized senders (extension content script, or Pontoon itself)
    if (event.origin !== window.origin || event.source !== window) {
      return;
    }
    let data;
    switch (typeof event.data) {
      case 'object':
        data = event.data;
        break;
      case 'string':
        // backward compatibility
        // TODO: remove some reasonable time after https://github.com/MikkCZ/pontoon-addon/pull/155 is released
        // and convert this switch into a condition
        try {
          data = JSON.parse(event.data);
        } catch {
          return;
        }
        break;
    }
    if (data && data._type === 'PontoonAddonInfo' && data.value) {
      if (data.value.installed === true) {
        $('body').removeClass('addon-promotion-active');
      }
    }
  });

  Pontoon.NProgressBind();

  // Log display of the unread notification icon
  if ($('#notifications').is('.unread')) {
    Pontoon.logUxAction(
      'Render: Unread notifications icon',
      'Notifications 1.0',
      {
        pathname: window.location.pathname,
      },
    );
  }

  // Initialize the timeago plugin on the notifications
  $('time.timeago').timeago();

  // Log clicks on the notifications icon
  $('#notifications .button').click(function () {
    if ($('#notifications').is('.opened')) {
      return;
    }

    Pontoon.logUxAction('Click: Notifications icon', 'Notifications 1.0', {
      pathname: window.location.pathname,
      unread: $('#notifications').is('.unread'),
    });
  });

  // Display any notifications
  const notifications = $('.notification li');
  if (notifications.length) {
    Pontoon.endLoader(notifications.text());
  }

  // Close notification on click
  $('body > header').on('click', '.notification', function () {
    Pontoon.closeNotification();
  });

  // Mark notifications as read when notification menu opens
  $('#notifications.unread .button').click(function () {
    Pontoon.markAllNotificationsAsRead();
  });

  function getRedirectUrl() {
    return window.location.pathname + window.location.search;
  }

  // Sign out button action
  $('.sign-out a, #sign-out a').on('click', function (ev) {
    const $this = $(this),
      $form = $this.find('form');

    ev.preventDefault();
    $form.prop('action', $this.prop('href') + '?next=' + getRedirectUrl());
    $form.submit();
  });

  // Show/hide menu on click
  $('body').on('click', '.selector', function (e) {
    if (!$(this).siblings('.menu').is(':visible')) {
      e.stopPropagation();
      $('.menu:not(".permanent")').hide();
      $('.select').removeClass('opened');
      $(this)
        .siblings('.menu')
        .show()
        .end()
        .parents('.select')
        .addClass('opened');
      $('.menu:not(".permanent"):visible input[type=search]')
        .focus()
        .trigger('input');
    }
  });

  // Hide menus on click outside
  $('body').bind('click.main', function () {
    $('.menu:not(".permanent")').hide();
    $('.select').removeClass('opened');
    $('.menu:not(".permanent") li').removeClass('hover');
  });

  // Menu hover
  $('body')
    .on('mouseenter', '.menu li', function () {
      // Ignore on nested menus
      if ($(this).parents('li').length) {
        return false;
      }

      $('.menu li.hover').removeClass('hover');
      $(this).toggleClass('hover');
    })
    .on('mouseleave', '.menu li', function () {
      // Ignore on nested menus
      if ($(this).parents('li').length) {
        return false;
      }

      $('.menu li.hover').removeClass('hover');
    });

  // Menu search
  $('body')
    .on('click', '.menu input[type=search]', function (e) {
      e.stopPropagation();
    })
    .on('input.search', '.menu input[type=search]', function (e) {
      // Tab
      if (e.which === 9) {
        return;
      }

      const ul = $(this).parent().siblings('ul'),
        val = $(this).val(),
        // Only search a limited set if defined
        limited = ul.find('li.limited').length > 0 ? '.limited' : '';

      ul.find('li' + limited)
        .show()
        .end()
        .find('li' + limited + ':not(":containsi(\'' + val + '\')")')
        .hide();

      if (ul.find('li:not(".no-match"):visible').length === 0) {
        ul.find('.no-match').show();
      } else {
        ul.find('.no-match').hide();
      }
    })
    .on('keydown.search', '.menu input[type=search]', function (e) {
      // Prevent form submission on Enter
      if (e.which === 13) {
        return false;
      }
    });

  // General keyboard shortcuts
  generalShortcutsHandler = function (e) {
    const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');

    function moveMenu(type) {
      const options =
        type === 'up' ? ['first', 'last', -1] : ['last', 'first', 1];
      const items = menu.find(
        'li:visible:not(.horizontal-separator, :has(li))',
      );
      let element = null;

      if (
        hovered.length === 0 ||
        menu.find('li:not(:has(li)):visible:' + options[0]).is('.hover')
      ) {
        menu.find('li.hover').removeClass('hover');
        element = items[options[1]]();
      } else {
        const current = menu.find('li.hover'),
          next = items.index(current) + options[2];

        current.removeClass('hover');
        element = $(items.get(next));
      }

      if (element) {
        const behavior = mediaQuery.matches ? 'auto' : 'smooth';
        element.addClass('hover');
        element[0].scrollIntoView({
          behavior: behavior,
          block: 'nearest',
        });
      }
    }

    const key = e.which;

    if ($('.menu:not(".permanent")').is(':visible')) {
      // eslint-disable-next-line no-var
      var menu = $('.menu:not(".permanent"):visible'),
        hovered = menu.find('li.hover');

      // Skip for the tabs
      if (menu.is('.tabs')) {
        return;
      }

      // Up arrow
      if (key === 38) {
        moveMenu('up');
        return false;
      }

      // Down arrow
      if (key === 40) {
        moveMenu('down');
        return false;
      }

      // Enter: confirm
      if (key === 13) {
        const a = hovered.find('a');
        if (a.length > 0) {
          a.click();
        } else {
          hovered.click();
        }
        return false;
      }

      // Escape: close
      if (key === 27) {
        $('body').click();
        return false;
      }
    }
  };
  $('html').on('keydown', generalShortcutsHandler);
});