byceps/byceps

View on GitHub
byceps/static/behavior/common.js

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * Register a function to be called when the document is "ready", i.e.
 * all the markup has been placed on the page.
 *
 * It does not wait until additional resources (stylesheets, images,
 * subframes) have been loaded.
 */
function onDomReady(callback) {
  if (document.readyState === 'complete' || document.readyState !== 'loading') {
    // The document has already fully loaded.
    callback();
  } else {
    document.addEventListener('DOMContentLoaded', callback);
  }
}


// ---------------------------------------------------------------------
// XHR requests

function post_on_click(selector) {
  _request_on_click(selector, 'POST');
}

function post_on_click_then_reload(selector) {
  _request_on_click_then_reload(selector, 'POST');
}

function confirmed_post_on_click(selector, confirmation_label) {
  _confirmed_request_on_click(selector, confirmation_label, 'POST');
}

function confirmed_post_on_click_then_reload(selector, confirmation_label) {
  _confirmed_request_on_click_then_reload(selector, confirmation_label, 'POST');
}

function delete_on_click(selector) {
  _request_on_click(selector, 'DELETE');
}

function delete_on_click_then_reload(selector) {
  _request_on_click_then_reload(selector, 'DELETE');
}

function confirmed_delete_on_click(selector, confirmation_label) {
  _confirmed_request_on_click(selector, confirmation_label, 'DELETE');
}

function confirmed_delete_on_click_then_reload(selector, confirmation_label) {
  _confirmed_request_on_click_then_reload(selector, confirmation_label, 'DELETE');
}

function _request_on_click(selector, method) {
  _onClickCallbackWithHref(selector, href => {
    _ajax_then_redirect_to_location_response_header(method, href);
  });
}

function _request_on_click_then_reload(selector, method) {
  _onClickCallbackWithHref(selector, href => {
    _ajax_then_reload(method, href);
  });
}

function _confirmed_request_on_click(selector, confirmation_label, method) {
  _onClickCallbackWithHref(selector, href => {
    if (confirm(confirmation_label)) {
      _ajax_then_redirect_to_location_response_header(method, href);
    };
  });
}

function _confirmed_request_on_click_then_reload(selector, confirmation_label, method) {
  _onClickCallbackWithHref(selector, href => {
    if (confirm(confirmation_label)) {
      _ajax_then_reload(method, href);
    };
  });
}


function _onClickCallbackWithHref(selector, callback) {
  const elements = document.querySelectorAll(selector);
  elements.forEach(element => {
    element.addEventListener('click', event => {
      const href = element.getAttribute('href');
      callback(href);

      event.preventDefault();
    });
  });
}

function _ajax_then_redirect_to_location_response_header(method, request_url) {
  _ajax(method, request_url, response => {
    if (response.status == 204) {
      const redirectUrl = response.headers.get('Location');
      if (redirectUrl !== null) {
        location.href = redirectUrl;
      }
    }
  });
}

function _ajax_then_reload(method, request_url) {
  _ajax(method, request_url, response => {
    if (response.status == 204) {
      location.href = location.href;
    }
  });
}

function _ajax(method, url, on_complete) {
  fetch(url, {method: method})
    .then(response => on_complete(response));
}


// ---------------------------------------------------------------------
// dropdown menus


/**
 * Make dropdown menus open if their respective trigger is clicked.
 */
function enableDropdownMenuToggles() {
  const dropdownToggles = document.querySelectorAll('.dropdown .dropdown-toggle');
  dropdownToggles.forEach(triggerElement => {
    triggerElement.addEventListener('click', event => {
      const dropdown = triggerElement.parentNode;
      dropdown.classList.toggle('open');

      event.preventDefault();
    });
  });
}


/**
 * Close all open dropdown menus but the one that has been clicked (if
 * any).
 */
function closeOpenDropdownMenus(clickTarget) {
  const openDropdowns = document.querySelectorAll('.dropdown.open');
  openDropdowns.forEach(openDropdown => {
    if (!openDropdown.contains(clickTarget)) {
      // Click was outside of this dropdown menu, so close it.
      openDropdown.classList.remove('open');
    }
  });
}


// Add behavior to dropdown menus.
onDomReady(() => {
  enableDropdownMenuToggles();

  // Close open dropdowns if user clicks outside of an open dropdown.
  document.addEventListener('click', event => closeOpenDropdownMenus(event.target));
});


// ---------------------------------------------------------------------
// clipboard


/**
 * Register an element as click trigger to copy the value of a field to
 * the clipboard.
 */
function enableCopyToClipboard(triggerElementId) {
  const triggerElement = document.getElementById(triggerElementId);
  if (triggerElement === null) {
    return;
  }

  triggerElement.addEventListener('click', () => {
    const fieldId = triggerElement.dataset.fieldId;
    const field = document.getElementById(fieldId);

    field.focus();
    field.select();
    try {
      document.execCommand('copy');
    } catch (err) {}
    field.blur();
  });
}


// ---------------------------------------------------------------------
// forms


// Disable the submit button of forms with class
// `disable-submit-button-on-submit` on submit.
onDomReady(() => {
  const formsWhoseSubmitButtonShouldBeDisabledOnSubmit = document
      .querySelectorAll('form.disable-submit-button-on-submit');

  formsWhoseSubmitButtonShouldBeDisabledOnSubmit.forEach(form => {
    form.addEventListener('submit', () => {
      const submitButton = form.querySelector('button[type="submit"]');
      submitButton.disabled = true;
      submitButton.innerHTML += ' <svg class="icon spinning"><use xlink:href="/static/style/icons.svg#spinner"></use></svg>';
    });
  });
});


// ---------------------------------------------------------------------
// log-out


// Enable log-out.
onDomReady(() => {
  document.querySelectorAll('a[data-action="log-out"]')
    .forEach(anchor => {
      anchor.addEventListener('click', event => {
        if (confirm('Wirklich abmelden?')) {
          const href = anchor.getAttribute('href');
          fetch(href, {method: 'POST'})
            .then(response => location.href = anchor.dataset.redirectTarget);
        };

        event.preventDefault();
      });
    });
});