<commit_before>// Copyright © 2015 <NAME>. All rights reserved.
// The following code is covered by the AGPL-3.0 license.

// Polyfill a few basic things.
['filter', 'forEach', 'map', 'reduce'].forEach(function (name) {
  Array[name] = function (array, callback, init) {
    return [][name].call(array, callback, init);
  };
});

// Automatically set up asynchronous JSON forms (all with a 'method' attribute).
Array.forEach(document.querySelectorAll('form[method]'), function (form) {
  setupAsyncForm(form);
  form.addEventListener('submit', function (event) {
    var elements = Array.filter(form.elements, function (element) {
      // Only consider `form.elements` that have a `name` attribute.
      return !!element.name;
    }).map(function (element) {
      // Extract values, properly handling elements with `type="checkbox"`.
      return {
        name: element.name,
        value: element.type === 'checkbox' ? element.checked : element.value
      };
    });

    // Build a JSON payload containing the submitted form data.
    var data = {};
    var method = form.getAttribute('method').toUpperCase();
    if (method === 'PATCH') {
      // Set up JSON Patch forms to submit an Array of JSON Patch operations.
      // See also: RFC 6902 - JSON Patch.
      data = elements.map(function (element) {
        return { op: 'add', path: element.name, value: element.value };
      });
    } else {
      // By default, submit a JSON Object that maps element names and values.
      elements.forEach(function (element) {
        data[element.name] = element.value;
      });
    }

    // Submit the JSON payload to the specified `form.action` URL.
    fetchAPI(method, form.action, data, function (error, data) {
      if (error) {
        updateFormStatus(form, 'error', String(error));
        return;
      }
      updateFormStatus(form, 'success', data ? data.message : null);
    });
  });
});

// FIXME: Remove this deprecated code.
// Automatically set up simple ajax forms (with 'data-action' attribute).
Array.forEach(document.querySelectorAll('form[data-action]'), function (form) {
  var id = '#' + form.getAttribute('id');
  var action = form.dataset.action;

  ajaxForm(id, action, function (form, data) {
    updateFormStatus(form, data.status, data.message);
  });
});

// FIXME: Remove this deprecated function.
// Set up an ajax <form>.
function ajaxForm (selector, action, callback) {
  var form = document.querySelector(selector);
  if (!form) {
    return;
  }

  setupAsyncForm(form);

  // Set-up the <form>'s ajax call.
  Scout(selector).on('submit', function (query) {
    query.action = action;
    query.data = getFormData(form);
    query.resp = function (data) {
      callback(form, data);
    };
    Array.forEach(form.elements, function (element) {
      element.blur();
      element.classList.add('disabled');
    });
  });
}

// Use `window.fetch()` to make an asynchronous Janitor API request.
function fetchAPI (method, url, data, callback) {
  var responseStatus = null;
  var options = {
    method: method.toUpperCase(),
    headers: new Headers({
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }),
    credentials: 'same-origin'
  };

  // Requests with method 'GET' or 'HEAD' cannot have `options.body`.
  if (data && ['GET', 'HEAD'].indexOf(options.method) < 0) {
    options.body = JSON.stringify(data, null, 2);
  }

  window.fetch(url, options).then(function (response) {
    // The server is responding!
    responseStatus = response.status;
    return responseStatus === 204 ? null : response.json();
  }).then(function (data) {
    // The response body was successfully parsed as JSON!
    if (data && data.error) {
      // The parsed JSON contains an error message.
      throw new Error(data.error);
    }

    if (responseStatus < 200 || responseStatus >= 300) {
      // The response status indicates something went wrong.
      throw new Error('Response status: ' + responseStatus);
    }

    // The request was successful!
    callback(null, data);
  }).catch(function (error) {
    // The request failed!
    callback(error);
  });
}

// Set up a <form> element that submits asynchronously.
function setupAsyncForm (form) {
  if (!form) {
    return;
  }

  // Re-enable all fields and hide any previous feedback.
  function resetFormStatus () {
    updateFormStatus(form);
  }

  // Process all <form> input elements (like <input>, <textarea>, …).
  Array.forEach(form.elements, function (element) {
    element.addEventListener('change', resetFormStatus);
    element.addEventListener('keydown', resetFormStatus);
  });

  // Elements can specify an event to submit the <form>.
  Array.forEach(form.querySelectorAll('[data-submit-on]'), function (element) {
    element.addEventListener(element.dataset.submitOn, function (event) {
      form.dispatchEvent(new Event('submit', { cancelable: true }));
    });
  });

  // Set-up the <form>'s visual feedback if needed.
  if (form.classList.contains('has-feedback')) {
    addFormFeedback(form);
  }

  form.addEventListener('submit', function (event) {
    // Disable all form elements while waiting for the server.
    Array.forEach(form.elements, function (element) {
      if (element.classList.contains('form-control-feedback')) {
        return;
      }
      element.blur();
      element.classList.add('disabled');
    });
    // Ensure that submitting the <form> doesn't reload the page.<commit_msg>Don't auto-blur form elements upon submit.<commit_after>// Copyright © 2015 <NAME>. All rights reserved.
// The following code is covered by the AGPL-3.0 license.

// Polyfill a few basic things.
['filter', 'forEach', 'map', 'reduce'].forEach(function (name) {
  Array[name] = function (array, callback, init) {
    return [][name].call(array, callback, init);
  };
});

// Automatically set up asynchronous JSON forms (all with a 'method' attribute).
Array.forEach(document.querySelectorAll('form[method]'), function (form) {
  setupAsyncForm(form);
  form.addEventListener('submit', function (event) {
    var elements = Array.filter(form.elements, function (element) {
      // Only consider `form.elements` that have a `name` attribute.
      return !!element.name;
    }).map(function (element) {
      // Extract values, properly handling elements with `type="checkbox"`.
      return {
        name: element.name,
        value: element.type === 'checkbox' ? element.checked : element.value
      };
    });

    // Build a JSON payload containing the submitted form data.
    var data = {};
    var method = form.getAttribute('method').toUpperCase();
    if (method === 'PATCH') {
      // Set up JSON Patch forms to submit an Array of JSON Patch operations.
      // See also: RFC 6902 - JSON Patch.
      data = elements.map(function (element) {
        return { op: 'add', path: element.name, value: element.value };
      });
    } else {
      // By default, submit a JSON Object that maps element names and values.
      elements.forEach(function (element) {
        data[element.name] = element.value;
      });
    }

    // Submit the JSON payload to the specified `form.action` URL.
    fetchAPI(method, form.action, data, function (error, data) {
      if (error) {
        updateFormStatus(form, 'error', String(error));
        return;
      }
      updateFormStatus(form, 'success', data ? data.message : null);
    });
  });
});

// FIXME: Remove this deprecated code.
// Automatically set up simple ajax forms (with 'data-action' attribute).
Array.forEach(document.querySelectorAll('form[data-action]'), function (form) {
  var id = '#' + form.getAttribute('id');
  var action = form.dataset.action;

  ajaxForm(id, action, function (form, data) {
    updateFormStatus(form, data.status, data.message);
  });
});

// FIXME: Remove this deprecated function.
// Set up an ajax <form>.
function ajaxForm (selector, action, callback) {
  var form = document.querySelector(selector);
  if (!form) {
    return;
  }

  setupAsyncForm(form);

  // Set-up the <form>'s ajax call.
  Scout(selector).on('submit', function (query) {
    query.action = action;
    query.data = getFormData(form);
    query.resp = function (data) {
      callback(form, data);
    };
    Array.forEach(form.elements, function (element) {
      element.classList.add('disabled');
    });
  });
}

// Use `window.fetch()` to make an asynchronous Janitor API request.
function fetchAPI (method, url, data, callback) {
  var responseStatus = null;
  var options = {
    method: method.toUpperCase(),
    headers: new Headers({
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }),
    credentials: 'same-origin'
  };

  // Requests with method 'GET' or 'HEAD' cannot have `options.body`.
  if (data && ['GET', 'HEAD'].indexOf(options.method) < 0) {
    options.body = JSON.stringify(data, null, 2);
  }

  window.fetch(url, options).then(function (response) {
    // The server is responding!
    responseStatus = response.status;
    return responseStatus === 204 ? null : response.json();
  }).then(function (data) {
    // The response body was successfully parsed as JSON!
    if (data && data.error) {
      // The parsed JSON contains an error message.
      throw new Error(data.error);
    }

    if (responseStatus < 200 || responseStatus >= 300) {
      // The response status indicates something went wrong.
      throw new Error('Response status: ' + responseStatus);
    }

    // The request was successful!
    callback(null, data);
  }).catch(function (error) {
    // The request failed!
    callback(error);
  });
}

// Set up a <form> element that submits asynchronously.
function setupAsyncForm (form) {
  if (!form) {
    return;
  }

  // Re-enable all fields and hide any previous feedback.
  function resetFormStatus () {
    updateFormStatus(form);
  }

  // Process all <form> input elements (like <input>, <textarea>, …).
  Array.forEach(form.elements, function (element) {
    element.addEventListener('change', resetFormStatus);
    element.addEventListener('keydown', resetFormStatus);
  });

  // Elements can specify an event to submit the <form>.
  Array.forEach(form.querySelectorAll('[data-submit-on]'), function (element) {
    element.addEventListener(element.dataset.submitOn, function (event) {
      form.dispatchEvent(new Event('submit', { cancelable: true }));
    });
  });

  // Set-up the <form>'s visual feedback if needed.
  if (form.classList.contains('has-feedback')) {
    addFormFeedback(form);
  }

  form.addEventListener('submit', function (event) {
    // Disable all form elements while waiting for the server.
    Array.forEach(form.elements, function (element) {
      if (element.classList.contains('form-control-feedback')) {
        return;
      }
      element.classList.add('disabled');
    });
    // Ensure that submitting the <form> doesn't reload the page.
{'fraction_non_alphanumeric': 0.14183551847437426, 'fraction_numerical': 0.003850738058127808, 'mean_word_length': 3.147528517110266, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7180690', 'n_tokens_mistral': 3170, 'n_tokens_neox': 3081, 'n_words': 932}