MediaWiki:AjaxSubmit.js

From VCSEwiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// ajaxSubmit
//   Submit a form through Ajax. Doesn't handle file uploads yet.
//
// Parameters:
//   form                 DOM element   The form to submit
//   button      optional DOM element   If set and a submit button of 'form', is added to the
//                                      form arguments sent
//   func        optional Function      Function to call once the call has been made or the
//                                      result has arrived, if want_result == true
//   want_result optional Boolean       If true, call func with the result of the submit once
//                                      it has arrived. Otherwise, call func as soon as the
//                                      submit request has been received by the server, and
//                                      ignore any result of the submit.
//
// Notes:
//   Func should be a function (request). If func is not defined,
//   ajaxSubmit just submits the form and ignores any result.
function ajaxSubmit (form, button, func, want_result)
{
  
  if (want_result && (!func || typeof (func) != 'function' || func.length < 1)) {
    /**** TODO: improve error handling: should throw an exception! */
    alert (  'Logic error in ajaxSubmit: func must be function (request).');
    return;
  }
  if (func && typeof (func) != 'function') {
    /**** TODO: improve error handling: should throw an exception! */
    alert ('Error in ajaxSubmit: func must be a function, found a ' + typeof (func) + '.');
    return;
  }

  var is_simple = false;
  // True if it's a GET request, or if the form is 'application/x-www-form-urlencoded'
  var boundary  = null; 
  // Otherwise, it's 'multipart/form-data', and the multipart delimiter is 'boundary'
  
  function encode_entry (name, value)
  {
    if (!name || name.length === 0 || !value || value.length === 0) return null;
    if (!boundary)
      return name + '=' + encodeURIComponent (value);
    else
      return boundary + '\r\n'
           + 'Content-Disposition: form-data; name="' + name + '"\r\n'
           + '\r\n'
           + value.replace(/\r?\n/g, '\r\n') + '\r\n'; // RFC 2046: newlines always must be represented as CR-LF
  }
  
  function encode_field (element)
  {
    var name = element.name;
    if (!name || name.length === 0) name = element.id;
    return encode_entry (name, element.value);
  }
  
  function form_add_argument (args, field)
  {
    if (!field || field.length === 0) return args;
    if (!args || args.length === 0) return field;
    if (is_simple)
      return args + '&' + field;
    else
      return args + field;
  }
  
  var request;
  if (window.LAPI && window.LAPI.Ajax && window.LAPI.Ajax.getRequest) {
    request = window.LAPI.Ajax.getRequest();
  } else {
    try {
      request = new window.XMLHttpRequest();
    } catch (anything) {
      if (window.ActiveXObject) request = new window.ActiveXObject('Microsoft.XMLHTTP');
    }
  }
  var method    = form.getAttribute ('method').toUpperCase ();
  var uri       = form.getAttribute ('action');
  if (uri.length >= 2 && uri.substring(0, 2) == '//') {
    // Protocol-relative URI; can cause trouble on IE7
    uri = document.location.protocol + uri;
  } else if (uri.charAt (0) == '/') {
    // Some browsers already expand the action URI (e.g. Opera 9.26)
    uri = mw.config.get('wgServer') + uri;
    if (uri.length >= 2 && uri.substring(0, 2) == '//') uri = document.location.protocol + uri;
  }
  // Encode the field values

  var is_get    = method == 'GET';
  var encoding  = form.getAttribute ('enctype');
  if (encoding) {
    encoding = encoding.toLowerCase ();
    if (encoding.length === 0) encoding = null;
  }
  is_simple =
    is_get || !encoding || encoding == 'application/x-www-form-urlencoded';

  var args            = "";
  var boundary_string = '----' + mw.config.get('wgArticleId')+mw.config.get('wgCurRevisionId') + 'auto_submit_by_lupo';

  boundary = null;
  
  if (!is_simple) boundary = '--' + boundary_string;

  for (var i = 0; i < form.elements.length; i++) {
    var element       = form.elements[i];
    var single_select = false;
    switch (element.type) {
      case 'checkbox':
      case 'radio':
        if (!element.checked) break;
        // else fall-through
        /*jshint: -W086*/
      case 'hidden':
      case 'text':
      case 'password':
      case 'textarea':
        args = form_add_argument (args, encode_field (element));
        break;
      case 'select-one':
        single_select = true;
        // fall-through
      case 'select-multiple':
        var name = element.name || element.id || "";
        if (name.length === 0) break;
        for (var j = 0; j < element.length; j++) {
          if (element[j].selected) {
            var value = element[j].value || element[j].text;
            args = form_add_argument (args, encode_entry (name, value));
            if (single_select) break; // No need to scan the rest
          }
        }
        break;
      case 'file':
        break;
    }
  }
  if (button && button.form == form && button.type == 'submit')
    args = form_add_argument (args, encode_field (button));
    
  // Close the multipart request
  if (!is_simple && args.length > 0) args = args + boundary;

  if (method == 'GET') {
    uri = uri + (uri.indexOf('?') < 0 ? '?' : '&') + args; args = null;
  }
  // Make the request
  request.open (method, uri, true);
  if (want_result && request.overrideMimeType) request.overrideMimeType ('application/xml');
  request.setRequestHeader ('Pragma', 'cache=no');
  request.setRequestHeader ('Cache-Control', 'no-transform');
  if (method == 'POST') {
    if (!encoding) encoding = 'application/x-www-form-urlencoded';
    if (!is_simple) {
      request.setRequestHeader (
        'Content-type', encoding + '; charset=UTF-8; boundary="' + boundary_string + '"');
    } else {
      request.setRequestHeader ('Content-type', encoding);
    }
  }
  request.onreadystatechange =
    function() {
      if (want_result) {
        if (request.readyState < 4) return;
        func (request);
      } else {
        // Call func as soon as the request has been sent and we start getting the result.
        if (request.readyState == 3 && func) func (request);
      }
    };
  request.send (args);
}

// submitAndClose
//   Submit a form and close the window containing it as soon as the request has been
//   received by the server
//
// Parameters:
//   form   DOM element   The form to submit.
function submitAndClose (form)
{
  ajaxSubmit (form, null, function () { window.close (); });
}