renderedtext/render_async

View on GitHub
app/views/render_async/_request_vanilla.js.erb

Summary

Maintainability
Test Coverage
(function() {
  <% if turbolinks %>
  if (document.documentElement.hasAttribute("data-turbolinks-preview")) {
    return;
  }
  <% end %>
  <% if turbo %>
  if (document.documentElement.hasAttribute("data-turbo-preview")) {
    return;
  }
  <% end %>
  function createEvent(name, container) {
    var event = undefined;
    if (typeof(Event) === 'function') {
      event = new Event(name);
    } else {
      event = document.createEvent('Event');
      event.initEvent(name, true, true);
    }
    event.container = container
    return event;
  }

  function _runAfterDocumentLoaded(callback) {
    <% if turbolinks %>
    document.addEventListener("turbolinks:load", function(e) {
      e.target.removeEventListener(e.type, arguments.callee);
      callback();
    });
    <% elsif turbo %>
    document.addEventListener("turbo:load", function(e) {
      e.target.removeEventListener(e.type, arguments.callee);
      callback();
    });
    <% else %>
    document.addEventListener("DOMContentLoaded", callback);
    <% end %>
  }

  function _makeRequest(currentRetryCount) {
    var request = new XMLHttpRequest();
    var asyncRequest = true;
    var SUCCESS = 200;
    var ERROR = 400;

    request.open('<%= method %>', '<%= path.html_safe %>', asyncRequest);

    var headers = <%= headers.to_json.html_safe %>;
    var csrfTokenElement = document.querySelector('meta[name="csrf-token"]');
    if (csrfTokenElement)
      headers['X-CSRF-Token'] = csrfTokenElement.content;

    <% if retry_count_header %>
    if (typeof(currentRetryCount) === 'number') {
      headers['<%= retry_count_header.html_safe %>'] = currentRetryCount;
    }
    <% end %>

    Object.keys(headers).map(function(key) {
      request.setRequestHeader(key, headers[key]);
    });

    request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

    request.onreadystatechange = function() {
      if (request.readyState === 4) {
        if (request.status >= SUCCESS && request.status < ERROR) {
          var container = document.getElementById('<%= container_id %>');

          // If user navigated away before the request completed
          if (!container) return;

          <% if !interval && replace_container %>
          container.outerHTML = request.response;
          <% else %>
          container.innerHTML = request.response;
          <% end %>

          var loadEvent = createEvent('render_async_load', container);
          document.dispatchEvent(loadEvent);

          <% if event_name.present? %>
            var event = createEvent('<%= event_name %>', container);
            document.dispatchEvent(event);
          <% end %>
        } else {
          var skipErrorMessage = false;
          <% if retry_count > 0 %>
          skipErrorMessage = retry(currentRetryCount)
          <% end %>

          if (skipErrorMessage) return;

          var container = document.getElementById('<%= container_id %>');
          if (!container) return;

          container.outerHTML = '<%= error_message.try(:html_safe) %>';

          var errorEvent = createEvent(
            "<%= error_event_name || 'render_async_error' %>",
            container
          );
          errorEvent.retryCount = currentRetryCount

          document.dispatchEvent(errorEvent);
        }
      }
    };

    var body = "<%= escape_javascript(data.to_s.html_safe) %>";
    request.send(body);
  };

  <% if retry_count > 0 %>

  <% if retry_delay %>
  var _retryMakeRequest = function(currentRetryCount) {
    setTimeout(function() {
      _makeRequest(currentRetryCount)
    }, <%= retry_delay %>)
  }
  <% else %>
  var _retryMakeRequest = _makeRequest
  <% end %>

  function retry(currentRetryCount) {
    if (typeof(currentRetryCount) === 'number') {
      if (currentRetryCount >= <%= retry_count %>)
        return false;

      _retryMakeRequest(currentRetryCount + 1);
      return true;
    }

    _retryMakeRequest(1);
    return true;
  }
  <% end %>

  var _renderAsyncFunction = _makeRequest;

  var _interval;
  <% if interval %>
  var _renderAsyncFunction = function() {
    // If interval is already set, return
    if (typeof(_interval) === 'number') return

    _makeRequest();
    _interval = setInterval(_makeRequest, <%= interval %>);
  }

  var _clearRenderAsyncInterval = function() {
    if (typeof(_interval) === 'number'){
      clearInterval(_interval)
      _interval = undefined;
    }
  }

  function _setUpControlEvents() {
    var container = document.getElementById('<%= container_id %>');

    // Register a polling stop event on the container
    container.addEventListener("async-stop", _clearRenderAsyncInterval)

    // Register a start polling event on the container
    container.addEventListener("async-start", _renderAsyncFunction)
  }

  _runAfterDocumentLoaded(_setUpControlEvents)

  <% if turbolinks %>
  document.addEventListener("turbolinks:visit", _clearRenderAsyncInterval)
  <% end %>
  <% if turbo %>
  document.addEventListener("turbo:visit", _clearRenderAsyncInterval)
  <% end %>
  <% end %>

  <% if !replace_container %>
  function _setUpRefreshEvent() {
    var container = document.getElementById('<%= container_id %>');

    container.addEventListener('refresh', _renderAsyncFunction)
  }

  _runAfterDocumentLoaded(_setUpRefreshEvent)
  <% end %>

  <% if toggle %>
  function _setUpToggle() {
    var selectors = document.querySelectorAll('<%= toggle[:selector] %>');
    var handler = function(event) {
      if (typeof(_interval) === 'number') {
        clearInterval(_interval);
        _interval = undefined;
      } else {
        _renderAsyncFunction();
      }
      <% if toggle[:once] %>
      this.removeEventListener(event.type, handler);
      <% end %>
    };

    <% if toggle[:start] %>
    _renderAsyncFunction()
    <% end %>

    for (var i = 0; i < selectors.length; ++i) {
      selectors[i].addEventListener('<%= toggle[:event] || 'click' %>', handler)
    }
  }

  _runAfterDocumentLoaded(_setUpToggle);
  <% elsif !toggle %>
  _runAfterDocumentLoaded(_renderAsyncFunction);
  <% end %>
})();