includes/clientside/static/editor.js
author Dan
Wed, 17 Mar 2010 14:21:46 -0400
changeset 1222 d1ded7b4c775
parent 1102 faef5e62e1e0
child 1227 bdac73ed481e
permissions -rw-r--r--
Fixed username not being decoded in Special:ActivateAccount

// Javascript routines for the page editor

// Idle time required for autosave, in seconds
var AUTOSAVE_TIMEOUT = 15;
var AutosaveTimeoutObj = null;
var editor_img_path = cdnPath + '/images/editor';
var editor_save_lock = false;
var editor_wikitext_transform_enable = true;

window.ajaxEditor = function(revid)
{
  if ( KILL_SWITCH )
    return true;
  if ( editor_open )
    return true;
  load_component(['l10n', 'template-compiler', 'messagebox', 'fadefilter', 'flyin', 'toolbar']);
  selectButtonMinor('edit');
  selectButtonMajor('article');
  setAjaxLoading();
  
  var rev_id_uri = ( revid ) ? '&revid=' + revid : '';
  ajaxGet(stdAjaxPrefix + '&_mode=getsource' + rev_id_uri, function(ajax)
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        unsetAjaxLoading();
        
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          handle_invalid_json(response);
          return false;
        }
        
        response = parseJSON(response);
        if ( response.mode == 'error' )
        {
          unselectAllButtonsMinor();
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_server'), response.error);
          return false;
        }
        
        if ( !response.auth_view_source )
        {
          unselectAllButtonsMinor();
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_access_denied_title'), $lang.get('editor_err_access_denied_body'));
          return false;
        }
        
        // do we need to enter a captcha before saving the page?
        var captcha_hash = ( response.require_captcha ) ? response.captcha_id : false;
        
        ajaxBuildEditor((!response.auth_edit), response.time, response.allow_wysiwyg, captcha_hash, response.revid, response.undo_info, response);
      }
    });
}

window.ajaxBuildEditor = function(readonly, timestamp, allow_wysiwyg, captcha_hash, revid, undo_info, response)
{
  // Set flags
  // We don't want the fancy confirmation framework to trigger if the user is only viewing the page source
  if ( !readonly )
  {
    editor_open = true;
    disableUnload();
  }
  
  // Destroy existing contents of page container
  if ( editor_use_modal_window )
  {
    darken(true, 70, 'enano_editor_darkener');
    // Build a div with 80% width, centered, and 10px from the top of the window
    var edcon = document.createElement('div');
    edcon.style.position = 'absolute';
    edcon.style.backgroundColor = '#FFFFFF';
    edcon.style.padding = '10px';
    edcon.style.width = '80%';
    edcon.style.zIndex = getHighestZ() + 1;
    edcon.id = 'ajaxEditContainerModal';
    
    // Positioning
    var top = getScrollOffset() + 10;
    var left = ( getWidth() / 10 ) - 10; // 10% of window width on either side - 10px for padding = perfect centering effect
    edcon.style.top = String(top) + 'px';
    edcon.style.left = String(left) + 'px';
    var body = document.getElementsByTagName('body')[0];
    
    // Set opacity to 0
    domObjChangeOpac(0, edcon);
    body.appendChild(edcon);
  }
  else
  {
    var edcon = document.getElementById('ajaxEditContainer');
    for ( var i = edcon.childNodes.length - 1; i >= 0; i-- )
    {
      edcon.removeChild(edcon.childNodes[i]);
    }
  }
  
  var content = response.src;
  
  //
  // BUILD EDITOR
  //
  
  var heading = document.createElement('h3');
  heading.style.cssFloat = 'left';
  heading.style.styleFloat = 'left';
  heading.style.marginTop = '0px';
  heading.style.marginBottom = '0px';
  heading.appendChild(document.createTextNode($lang.get('editor_msg_editor_heading')));
  
  // Plaintext/wikitext toggler
  // Only build the editor if using TinyMCE is allowed. THIS IS WEAK
  // AND CANNOT BE MADE ANY STRONGER.
  
  if ( allow_wysiwyg )
  {
    var toggler = document.createElement('p');
    toggler.style.marginLeft = '0';
    toggler.style.textAlign = 'right';
    
    var span_wiki = document.createElement('span');
    var span_mce  = document.createElement('span');
    span_wiki.id  = 'enano_edit_btn_pt';
    span_mce.id   = 'enano_edit_btn_mce';
    
    // to-wikitext button
    var a = document.createElement('a');
    a.href = '#';
    a.className = 'abutton image abutton_green';
    a.appendChild(gen_sprite(scriptPath + '/images/editor/sprite.png', 16, 16, 0, 96));
    a.appendChild(document.createTextNode(' ' + $lang.get('editor_btn_wikitext')));
    span_wiki.appendChild(a);
    toggler.appendChild(span_wiki);
    
    // to-HTML button
    var a = document.createElement('a');
    a.href = '#';
    a.className = 'abutton image abutton_blue';
    a.appendChild(gen_sprite(scriptPath + '/images/editor/sprite.png', 16, 16, 0, 112));
    a.appendChild(document.createTextNode(' ' + $lang.get('editor_btn_graphical')));
    span_mce.appendChild(a);
    toggler.appendChild(span_mce);
    
    if ( response.page_format == 'xhtml' )
    {
      // Current selection is TinyMCE - make span_wiki have the link and span_mce be plaintext
      span_mce.style.display = 'none';
    }
    else
    {
      // Current selection is wikitext - set span_wiki to plaintext and span_mce to link
      span_wiki.style.display = 'none';
    }
  }
  
  // Form (to allow submits from MCE to trigger a real save)
  var form = document.createElement('form');
  form.action = 'javascript:void(0);';
  form.onsubmit = function()
  {
    ajaxEditorSave();
    return false;
  }
  
  // Draft notice
  if ( response.have_draft && !readonly )
  {
    var dn = document.createElement('div');
    dn.className = 'warning-box';
    dn.id = 'ajax_edit_draft_notice';
    dn.innerHTML = '<b>' + $lang.get('editor_msg_have_draft_title') + '</b><br />';
    dn.innerHTML += $lang.get('editor_msg_have_draft_body', { author: response.draft_author, time: response.draft_time });
  }
  
  // Old-revision notice
  if ( revid > 0 )
  {
    var oldrev_box = document.createElement('div');
    oldrev_box.className = 'usermessage';
    oldrev_box.appendChild(document.createTextNode($lang.get('editor_msg_editing_old_revision')));
  }
  
  // Preview holder
  var preview_anchor = document.createElement('a');
  preview_anchor.name = 'ajax_preview';
  preview_anchor.id = 'ajax_preview';
  var preview_container = document.createElement('div');
  preview_container.id = 'enano_editor_preview';
  preview_container.style.clear = 'left';
  
  // Textarea containing the content
  var ta_wrapper = document.createElement('div');
  ta_wrapper.style.margin = '10px 0';
  // ta_wrapper.style.clear = 'both';
  var textarea = document.createElement('textarea');
  ta_wrapper.appendChild(textarea);
  
  textarea.id = 'ajaxEditArea';
  textarea.rows = '20';
  textarea.cols = '60';
  textarea.style.width = '98.7%';
  
  // Revision metadata controls
  var tblholder = document.createElement('div');
  tblholder.className = 'tblholder';
  var metatable = document.createElement('table');
  metatable.setAttribute('border', '0');
  metatable.setAttribute('cellspacing', '1');
  metatable.setAttribute('cellpadding', '4');
  
  if ( readonly )
  {
    // Close Viewer button
    var toolbar = '';
    var head = new templateParser(response.toolbar_templates.toolbar_start);
    var button = new templateParser(response.toolbar_templates.toolbar_button);
    var tail = new templateParser(response.toolbar_templates.toolbar_end);
    
    toolbar += head.run();
    
    button.assign_bool({
        show_title: true
      });
    
    // Button: close
    button.assign_vars({
        TITLE: $lang.get('editor_btn_closeviewer'),
        IMAGE: editor_img_path + '/discard.gif',
        SPRITE: gen_sprite_html(editor_img_path + '/sprite.png', 16, 16, 0, 16),
        FLAGS: 'href="#" onclick="ajaxReset(true); return false;"'
      });
    toolbar += button.run();
    toolbar += tail.run();
  }
  else
  {
    // First row: edit summary
    var tr1 = document.createElement('tr');
    var td1_1 = document.createElement('td');
    var td1_2 = document.createElement('td');
    td1_1.className = 'row2';
    td1_2.className = 'row1';
    td1_2.style.width = '70%';
    td1_1.appendChild(document.createTextNode($lang.get('editor_lbl_edit_summary')));
    td1_1.appendChild(document.createElement('br'));
    var small = document.createElement('small');
    small.appendChild(document.createTextNode($lang.get('editor_lbl_edit_summary_explain')));
    td1_1.appendChild(small);
    
    var field_es = document.createElement('input');
    field_es.id = 'enano_editor_field_summary';
    field_es.type = 'text';
    field_es.size = '40';
    field_es.style.width = '96%';
    
    if ( revid > 0 )
    {
      undo_info.last_rev_id = revid;
      field_es.value = $lang.get('editor_reversion_edit_summary', undo_info);
    }
    
    td1_2.appendChild(field_es);
    
    tr1.appendChild(td1_1);
    tr1.appendChild(td1_2);
    
    // Second row: minor edit
    var tr2 = document.createElement('tr');
    var td2_1 = document.createElement('td');
    var td2_2 = document.createElement('td');
    td2_1.className = 'row2';
    td2_2.className = 'row1';
    td2_1.appendChild(document.createTextNode($lang.get('editor_lbl_minor_edit')));
    td2_1.appendChild(document.createElement('br'));
    var small = document.createElement('small');
    small.appendChild(document.createTextNode($lang.get('editor_lbl_minor_edit_explain')));
    td2_1.appendChild(small);
    
    var label = document.createElement('label');
    var field_mi = document.createElement('input');
    field_mi.id = 'enano_editor_field_minor';
    field_mi.type = 'checkbox';
    label.appendChild(field_mi);
    label.appendChild(document.createTextNode(' '));
    label.appendChild(document.createTextNode($lang.get('editor_lbl_minor_edit_field')));
    td2_2.appendChild(label);
    
    tr2.appendChild(td2_1);
    tr2.appendChild(td2_2);
    
    if ( captcha_hash )
    {
      // generate captcha field (effectively third row)
      var tr4 = document.createElement('tr');
      var td4_1 = document.createElement('td');
      var td4_2 = document.createElement('td');
      td4_1.className = 'row2';
      td4_2.className = 'row1';
      
      td4_1.appendChild(document.createTextNode($lang.get('editor_lbl_field_captcha')));
      td4_1.appendChild(document.createElement('br'));
      var small2 = document.createElement('small');
      small2.appendChild(document.createTextNode($lang.get('editor_msg_captcha_pleaseenter')));
      small2.appendChild(document.createElement('br'));
      small2.appendChild(document.createElement('br'));
      small2.appendChild(document.createTextNode($lang.get('editor_msg_captcha_blind')));
      td4_1.appendChild(small2);
      
      var img = document.createElement('img');
      img.src = makeUrlNS('Special', 'Captcha/' + captcha_hash);
      img.setAttribute('enano:captcha_hash', captcha_hash);
      img.id = 'enano_editor_captcha_img';
      img.onclick = function()
      {
        this.src = makeUrlNS('Special', 'Captcha/' + this.getAttribute('enano:captcha_hash') + '/' + Math.floor(Math.random() * 100000));
      }
      img.style.cursor = 'pointer';
      td4_2.appendChild(img);
      td4_2.appendChild(document.createElement('br'));
      td4_2.appendChild(document.createTextNode($lang.get('editor_lbl_field_captcha_code') + ' '));
      var input = document.createElement('input');
      input.type = 'text';
      input.id = 'enano_editor_field_captcha';
      input.setAttribute('enano:captcha_hash', captcha_hash);
      input.size = '9';
      td4_2.appendChild(input);
      
      tr4.appendChild(td4_1);
      tr4.appendChild(td4_2);
    }
    
    // Third row: controls
    
    var toolbar = '';
    var head = new templateParser(response.toolbar_templates.toolbar_start);
    var button = new templateParser(response.toolbar_templates.toolbar_button);
    var label = new templateParser(response.toolbar_templates.toolbar_label);
    var tail = new templateParser(response.toolbar_templates.toolbar_end);
    
    button.assign_bool({
        show_title: true
      });
    
    toolbar += head.run();
    
    // Button: Save
    button.assign_vars({
        TITLE: $lang.get('editor_btn_save'),
        IMAGE: editor_img_path + '/save.gif',
        SPRITE: gen_sprite_html(editor_img_path + '/sprite.png', 16, 16, 0, 64),
        FLAGS: 'href="#" onclick="ajaxEditorSave(); return false;"'
      });
    toolbar += button.run();
    
    // Button: preview
    button.assign_vars({
        TITLE: $lang.get('editor_btn_preview'),
        IMAGE: editor_img_path + '/preview.gif',
        SPRITE: gen_sprite_html(editor_img_path + '/sprite.png', 16, 16, 0, 32),
        FLAGS: 'href="#" onclick="ajaxEditorGenPreview(); return false;"'
      });
    toolbar += button.run();
    
    // Button: revert
    button.assign_vars({
        TITLE: $lang.get('editor_btn_revert'),
          IMAGE: editor_img_path + '/revert.gif',
          SPRITE: gen_sprite_html(editor_img_path + '/sprite.png', 16, 16, 0, 48),
        FLAGS: 'href="#" onclick="ajaxEditorRevertToLatest(); return false;"'
      });
    toolbar += button.run();
    
    // Button: diff
    button.assign_vars({
        TITLE: $lang.get('editor_btn_diff'),
        IMAGE: editor_img_path + '/diff.gif',
        SPRITE: gen_sprite_html(editor_img_path + '/sprite.png', 16, 16, 0, 0),
        FLAGS: 'href="#" onclick="ajaxEditorShowDiffs(); return false;"'
      });
    toolbar += button.run();
    
    // Button: cancel
    button.assign_vars({
        TITLE: $lang.get('editor_btn_cancel'),
        IMAGE: editor_img_path + '/discard.gif',
        SPRITE: gen_sprite_html(editor_img_path + '/sprite.png', 16, 16, 0, 16),
        FLAGS: 'href="#" onclick="ajaxEditorCancel(); return false;"'
      });
    toolbar += button.run();
    
    // Separator
    label.assign_vars({
        TITLE: ' '
      });
    toolbar += label.run();
    
    // Button: Save draft
    button.assign_vars({
        TITLE: $lang.get('editor_btn_savedraft'),
        IMAGE: editor_img_path + '/savedraft.gif',
        SPRITE: false,
        FLAGS: 'href="#" onclick="ajaxPerformAutosave(); return false;" id="ajax_edit_savedraft_btn"'
      });
    toolbar += button.run();
    
    toolbar += tail.run();
    
    metatable.appendChild(tr1);
    metatable.appendChild(tr2);
    if ( captcha_hash )
    {
      metatable.appendChild(tr4);
    }
    // metatable.appendChild(tr3);
  }
  tblholder.appendChild(metatable);
  
  // Edit disclaimer/notice
  if ( response.edit_notice )
  {
    var en_div = document.createElement('div');
    en_div.innerHTML = response.edit_notice;
    en_div.className = 'usermessage';
    en_div.style.margin = '10px 0 0 0';
  }
  
  // Put it all together...
  form.appendChild(heading);
  if ( allow_wysiwyg )
    form.appendChild(toggler);
  
  if ( dn )
    form.appendChild(dn);
  
  if ( oldrev_box )
    form.appendChild(oldrev_box);
  
  form.appendChild(preview_anchor);
  form.appendChild(preview_container);
  form.appendChild(ta_wrapper);
  if ( !readonly )
    form.appendChild(tblholder);
  form.innerHTML += '<div style="margin: 10px 0 0 0;">' + toolbar + '</div>';
  edcon.appendChild(form);
  
  if ( response.edit_notice && !readonly )
  {
    edcon.appendChild(en_div);
  }
  
  // more textarea attribs/init
  var textarea = document.getElementById('ajaxEditArea');
  textarea.as_last_save = 0;
  textarea.content_orig = content;
  textarea.used_draft = false;
  textarea.onkeyup = function()
  {
    if ( this.needReset )
    {
      var img = $dynano('ajax_edit_savedraft_btn').object.getElementsByTagName('img')[0];
      var lbl = $dynano('ajax_edit_savedraft_btn').object.getElementsByTagName('span')[0];
      img.src = editor_img_path + '/savedraft.gif';
      lbl.innerHTML = $lang.get('editor_btn_savedraft');
    }
    if ( window.AutosaveTimeoutObj )
      clearTimeout(window.AutosaveTimeoutObj);
    window.AutosaveTimeoutObj = setTimeout('ajaxAutosaveDraft();', ( AUTOSAVE_TIMEOUT * 1000 ));
  }
  
  if ( readonly )
  {
    textarea.className = 'mce_readonly';
    textarea.setAttribute('readonly', 'readonly');
  }
  
  $dynano('ajaxEditArea').object.focus();
  $dynano('ajaxEditArea').object._edTimestamp = timestamp;
  $dynano('ajaxEditArea').setContent(content);
  
  // If the editor preference is tinymce, switch the editor to TinyMCE now
  if ( response.page_format == 'xhtml' && allow_wysiwyg )
  {
    $dynano('ajaxEditArea').switchToMCE(false);
  }
  
  if ( allow_wysiwyg )
  {
    var a = document.getElementById('enano_edit_btn_pt').getElementsByTagName('a')[0];
    a.onclick = function() {
      ajaxSetEditorPlain();
      return false;
    };
    var a = document.getElementById('enano_edit_btn_mce').getElementsByTagName('a')[0];
    a.onclick = function() {
      ajaxSetEditorMCE();
      return false;
    };
  }
  
  // if we're using the modal window, fade it in
  if ( editor_use_modal_window )
  {
    domOpacity(edcon, 0, 100, 500);
  }
  
  // Autosave every 5 minutes           (m  *  s  *  ms)
  setInterval('ajaxPerformAutosave();', ( 5 * 60 * 1000 ));
}

window.ajaxEditorDestroyModalWindow = function()
{
  if ( editor_use_modal_window )
  {
    var edcon = document.getElementById('ajaxEditContainerModal');
    var body = document.getElementsByTagName('body')[0];
    if ( edcon )
    {
      body.removeChild(edcon);
      enlighten(true, 'enano_editor_darkener');
    }
  }
}

window.ajaxEditorSave = function(is_draft, text_override)
{
  if ( !is_draft )
  {
    ajaxSetEditorLoading();
  }
  if ( is_draft && editor_save_lock )
    return false;
  else
    editor_save_lock = true;
  
  var ta_content = ( text_override ) ? text_override : $dynano('ajaxEditArea').getContent();
  
  if ( !is_draft && ( ta_content == '' || ta_content == '<p></p>' || ta_content == '<p>&nbsp;</p>' ) )
  {
    new MessageBox(MB_OK|MB_ICONSTOP, $lang.get('editor_err_no_text_title'), $lang.get('editor_err_no_text_body'));
    ajaxUnSetEditorLoading();
    return false;
  }
  
  if ( is_draft )
  {
    // ajaxSetEditorLoading();
    var img = $dynano('ajax_edit_savedraft_btn').object.getElementsByTagName('img')[0];
    var lbl = $dynano('ajax_edit_savedraft_btn').object.getElementsByTagName('span')[0];
    img.src = cdnPath + '/images/loading.gif';
    var d = new Date();
    var m = String(d.getMinutes());
    if ( m.length < 2 )
      m = '0' + m;
    var time = d.getHours() + ':' + m;
    lbl.innerHTML = $lang.get('editor_msg_draft_saving');
  }
  
  var edit_summ = $dynano('enano_editor_field_summary').object.value;
  if ( !edit_summ )
    edit_summ = '';
  var is_minor = ( $dynano('enano_editor_field_minor').object.checked ) ? 1 : 0;
  var timestamp = $dynano('ajaxEditArea').object._edTimestamp;
  var used_draft = $dynano('ajaxEditArea').object.used_draft;
  
  var json_packet = {
    src: ta_content,
    summary: edit_summ,
    minor_edit: is_minor,
    time: timestamp,
    draft: ( is_draft == true ),
    format: ( $dynano('ajaxEditArea').isMCE() ) ? 'xhtml' : 'wikitext',
    used_draft: used_draft
  };
  
  // Do we need to add captcha info?
  if ( document.getElementById('enano_editor_field_captcha') && !is_draft )
  {
    var captcha_field = document.getElementById('enano_editor_field_captcha');
    if ( captcha_field.value == '' )
    {
      new MessageBox(MB_OK|MB_ICONSTOP, $lang.get('editor_err_need_captcha_title'), $lang.get('editor_err_need_captcha_body'));
      ajaxUnSetEditorLoading();
      return false;
    }
    json_packet.captcha_code = captcha_field.value;
    json_packet.captcha_id = captcha_field.getAttribute('enano:captcha_hash');
  }
  
  json_packet = ajaxEscape(toJSONString(json_packet));
  ajaxPost(stdAjaxPrefix + '&_mode=savepage_json', 'r=' + json_packet, function(ajax)
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        ajaxUnSetEditorLoading();
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          handle_invalid_json(response);
          return false;
        }
        
        response = parseJSON(response);
        // This will only be used if there was a lower-level error.
        if ( response.mode == 'error' )
        {
          editor_save_lock = false;
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_server'), response.error);
          return false;
        }
        // This will be used if the PageProcessor generated errors (usually security/permissions related)
        if ( response.mode == 'errors' )
        {
          editor_save_lock = false;
          // This will be true if the user entered a captcha code incorrectly, thus
          // invalidating the code and requiring a new image to be generated.
          if ( response.new_captcha )
          {
            // Generate the new captcha field
            var img = document.getElementById('enano_editor_captcha_img');
            var input = document.getElementById('enano_editor_field_captcha');
            if ( img && input )
            {
              img._captchaHash = response.new_captcha;
              input._captchaHash = response.new_captcha;
              img.src = makeUrlNS('Special', 'Captcha/' + response.new_captcha);
              input.value = '';
            }
          }
          var errors = '<ul><li>' + implode('</li><li>', response.errors) + '</li></ul>';
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_save_title'), $lang.get('editor_err_save_body') + errors);
          return false;
        }
        // If someone else got to the page first, warn the user
        if ( response.mode == 'obsolete' )
        {
          editor_save_lock = false;
          // Update the local timestamp to allow override
          $dynano('ajaxEditArea').object._edTimestamp = response.time;
          new MessageBox(MB_OK | MB_ICONEXCLAMATION, $lang.get('editor_err_obsolete_title'), $lang.get('editor_err_obsolete_body', { author: response.author, timestamp: response.date_string, page_url: makeUrl(title, false, true) }));
          return false;
        }
        if ( response.mode == 'success' )
        {
          if ( response.is_draft )
          {
            document.getElementById('ajaxEditArea').used_draft = true;
            document.getElementById('ajaxEditArea').needReset = true;
            var img = $dynano('ajax_edit_savedraft_btn').object.getElementsByTagName('img')[0];
            var lbl = $dynano('ajax_edit_savedraft_btn').object.getElementsByTagName('span')[0];
            if ( response.is_draft == 'delete' )
            {
              img.src = scriptPath + '/images/editor/savedraft.gif';
              lbl.innerHTML = $lang.get('editor_btn_savedraft');
              
              var dn = $dynano('ajax_edit_draft_notice').object;
              if ( dn )
              {
                dn.parentNode.removeChild(dn);
              }
            }
            else
            {
              img.src = scriptPath + '/images/mini-info.png';
              var d = new Date();
              var m = String(d.getMinutes());
              if ( m.length < 2 )
                m = '0' + m;
              var time = d.getHours() + ':' + m;
              lbl.innerHTML = $lang.get('editor_msg_draft_saved', { time: time });
            }
            editor_save_lock = false;
          }
          else
          {
            // The save was successful; reset flags and make another request for the new page content
            setAjaxLoading();
            editor_open = false;
            editor_save_lock = false;
            enableUnload();
            $dynano('ajaxEditArea').destroyMCE(false);
            changeOpac(0, 'ajaxEditContainer');
            ajaxGet(stdAjaxPrefix + '&_mode=getpage&noheaders', function(ajax)
              {
                if ( ajax.readyState == 4 && ajax.status == 200 )
                {
                  unsetAjaxLoading();
                  selectButtonMajor('article');
                  unselectAllButtonsMinor();
                  
                  ajaxEditorDestroyModalWindow();
                  document.getElementById('ajaxEditContainer').innerHTML = '<div class="usermessage">' + $lang.get('editor_msg_saved') + '</div>' + ajax.responseText;
                  // if we're on a userpage, call the onload function to rebuild the tabs
                  if ( typeof(userpage_onload) == 'function' )
                  {
                    window.userpage_blocks = [];
                    userpage_onload();
                  }
                  opacity('ajaxEditContainer', 0, 100, 1000);
                }
              });
          }
        }
      }
    }, true);
}

// Delete the draft (this is a massive server-side hack)
window.ajaxEditorDeleteDraft = function()
{
  miniPromptMessage({
      title: $lang.get('editor_msg_confirm_delete_draft_title'),
      message: $lang.get('editor_msg_confirm_delete_draft_body'),
      buttons: [
          {
            text: $lang.get('editor_btn_delete_draft'),
            color: 'red',
            style: {
              fontWeight: 'bold'
            },
            onclick: function() {
              ajaxEditorDeleteDraftReal();
              miniPromptDestroy(this);
            }
          },
          {
            text: $lang.get('etc_cancel'),
            onclick: function() {
              miniPromptDestroy(this);
            }
          }
        ]
    });
}

window.ajaxEditorDeleteDraftReal = function()
{
  return ajaxEditorSave(true, -1);
}

window.ajaxEditorGenPreview = function()
{
  ajaxSetEditorLoading();
  var ta_content = $dynano('ajaxEditArea').getContent();
  ta_content = ajaxEscape(ta_content);
  if ( $dynano('enano_editor_preview').object.innerHTML != '' )
  {
    opacity('enano_editor_preview', 100, 0, 500);
  }
  ajaxPost(stdAjaxPrefix + '&_mode=preview', 'text=' + ta_content, function(ajax)
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        ajaxUnSetEditorLoading();
        changeOpac(0, 'enano_editor_preview');
        $dynano('enano_editor_preview').object.innerHTML = ajax.responseText;
        window.location.hash = '#ajax_preview';
        opacity('enano_editor_preview', 0, 100, 500);
      }
    }, true);
}

window.ajaxEditorRevertToLatest = function()
{
  miniPromptMessage({
      title: $lang.get('editor_msg_revert_confirm_title'),
      message: $lang.get('editor_msg_revert_confirm_body'),
      buttons: [
        {
          text: $lang.get('editor_btn_revert_confirm'),
          color: 'red',
          sprite: [ editor_img_path + '/sprite.png', 16, 16, 0, 48 ],
          style: {
            fontWeight: 'bold'
          },
          onclick: function()
          {
            ajaxEditorRevertToLatestReal();
            miniPromptDestroy(this);
            return false;
          }
        },
        {
          text: $lang.get('etc_cancel'),
          onclick: function()
          {
            miniPromptDestroy(this);
            return false;
          }
        }
      ]
    });
}

window.ajaxEditorRevertToLatestReal = function()
{
  ajaxSetEditorLoading();
  ajaxGet(stdAjaxPrefix + '&_mode=getsource', function(ajax)
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        ajaxUnSetEditorLoading();
        
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          handle_invalid_json(response);
          return false;
        }
        
        response = parseJSON(response);
        if ( response.mode == 'error' )
        {
          unselectAllButtonsMinor();
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_server'), response.error);
          return false;
        }
        
        if ( !response.auth_view_source )
        {
          unselectAllButtonsMinor();
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_access_denied_title'), $lang.get('editor_err_access_denied_body'));
          return false;
        }
        
        setTimeout(function()
          {
            editor_convert_if_needed(response.page_format);
            $dynano('ajaxEditArea').setContent(response.src);
          }, aclDisableTransitionFX ? 10 : 750);
      }
    }, true);
}

window.ajaxEditorShowDiffs = function()
{
  ajaxSetEditorLoading();
  var ta_content = $dynano('ajaxEditArea').getContent();
  ta_content = ajaxEscape(ta_content);
  if ( $dynano('enano_editor_preview').object.innerHTML != '' )
  {
    opacity('enano_editor_preview', 100, 0, 500);
  }
  ajaxPost(stdAjaxPrefix + '&_mode=diff_cur', 'text=' + ta_content, function(ajax)
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        ajaxUnSetEditorLoading();
        changeOpac(0, 'enano_editor_preview');
        $dynano('enano_editor_preview').object.innerHTML = ajax.responseText;
        window.location.hash = '#ajax_preview';
        opacity('enano_editor_preview', 0, 100, 500);
      }
    }, true);
}

window.ajaxEditorCancel = function()
{
  miniPromptMessage({
      title: $lang.get('editor_msg_cancel_confirm_title'),
      message: $lang.get('editor_msg_cancel_confirm_body'),
      buttons: [
        {
          text: $lang.get('editor_btn_cancel_confirm'),
          color: 'red',
          sprite: [ editor_img_path + '/sprite.png', 16, 16, 0, 16 ],
          style: {
            fontWeight: 'bold'
          },
          onclick: function()
          {
            setAjaxLoading();
            ajaxEditorDestroyModalWindow();
            editor_open = false;
            enableUnload();
            $dynano('ajaxEditArea').destroyMCE(false);
            ajaxReset();
            miniPromptDestroy(this);
            return false;
          }
        },
        {
          text: $lang.get('editor_btn_cancel_cancel'),
          onclick: function()
          {
            miniPromptDestroy(this);
            return false;
          }
        }
      ]
    });
}

window.ajaxSetEditorMCE = function(confirmed)
{
  if ( editor_loading )
    return false;
  
  if ( !confirmed )
  {
    miniPromptMessage({
        title: $lang.get('editor_msg_convert_confirm_title'),
        message: $lang.get('editor_msg_convert_confirm_body'),
        buttons: [
          {
            color: 'blue',
            text: $lang.get('editor_btn_graphical'),
            style: {
              fontWeight: 'bold'
            },
            sprite: [ editor_img_path + '/sprite.png', 16, 16, 0, 112 ],
            onclick: function()
            {
              ajaxSetEditorMCE(true);
              miniPromptDestroy(this);
              return false;
            }
          },
          {
            text: $lang.get('etc_cancel'),
            onclick: function()
            {
              miniPromptDestroy(this);
              return false;
            }
          }
        ]
      });
    return false;
  }
  
  // Clear out existing buttons
  var span_wiki = $dynano('enano_edit_btn_pt').object;
  var span_mce  = $dynano('enano_edit_btn_mce').object;
  span_wiki.style.display = 'inline';
  span_mce.style.display = 'none';
  
  // Swap editor
  $dynano('ajaxEditArea').switchToMCE(true);
}

window.ajaxSetEditorPlain = function(confirmed)
{
  if ( editor_loading )
    return false;
  
  if ( !confirmed )
  {
    miniPromptMessage({
        title: $lang.get('editor_msg_convert_confirm_title'),
        message: $lang.get('editor_msg_convert_confirm_body'),
        buttons: [
          {
            color: 'green',
            text: $lang.get('editor_btn_wikitext'),
            style: {
              fontWeight: 'bold'
            },
            sprite: [ editor_img_path + '/sprite.png', 16, 16, 0, 96 ],
            onclick: function()
            {
              ajaxSetEditorPlain(true);
              miniPromptDestroy(this);
              return false;
            }
          },
          {
            text: $lang.get('etc_cancel'),
            onclick: function()
            {
              miniPromptDestroy(this);
              return false;
            }
          }
        ]
      });
    return false;
  }
  
  // Clear out existing buttons
  var span_wiki = $dynano('enano_edit_btn_pt').object;
  var span_mce  = $dynano('enano_edit_btn_mce').object;
  span_wiki.style.display = 'none';
  span_mce.style.display = 'inline';
  
  // Swap editor
  $dynano('ajaxEditArea').destroyMCE(true);
}

var editor_loading = false;

window.ajaxSetEditorLoading = function()
{
  var ed = false;
  if ( window.tinyMCE )
  {
    ed = tinyMCE.get('ajaxEditArea');
  }
  editor_loading = true;
  if ( ed )
  {
    ed.setProgressState(1);
  }
  else
  {
    ed = document.getElementById('ajaxEditArea');
    var blackout = document.createElement('div');
    blackout.style.position = 'absolute';
    blackout.style.top = $dynano('ajaxEditArea').Top() + 'px';
    blackout.style.left = $dynano('ajaxEditArea').Left() + 'px';
    blackout.style.width = $dynano('ajaxEditArea').Width() + 'px';
    blackout.style.height = $dynano('ajaxEditArea').Height() + 'px';
    blackout.style.backgroundColor = '#FFFFFF';
    domObjChangeOpac(60, blackout);
    blackout.style.backgroundImage = 'url(' + scriptPath + '/includes/clientside/tinymce/themes/advanced/skins/default/img/progress.gif)';
    blackout.style.backgroundPosition = 'center center';
    blackout.style.backgroundRepeat = 'no-repeat';
    blackout.id = 'enano_editor_blackout';
    blackout.style.zIndex = getHighestZ() + 2;
    
    var body = document.getElementsByTagName('body')[0];
    body.appendChild(blackout);
  }
}

window.ajaxUnSetEditorLoading = function()
{
  editor_loading = false;
  var ed = false;
  if ( window.tinyMCE )
  {
    ed = tinyMCE.get('ajaxEditArea');
  }
  if ( ed )
  {
    ed.setProgressState(0);
  }
  else
  {
    var blackout = document.getElementById('enano_editor_blackout');
    var body = document.getElementsByTagName('body')[0];
    if ( !blackout )
      return false;
    body.removeChild(blackout);
  }
}

window.ajaxAutosaveDraft = function()
{
  var aed = document.getElementById('ajaxEditArea');
  if ( !aed )
    return false;
  var last_save = aed.as_last_save;
  var now = unix_time();
  if ( ( last_save + 120 ) < now && aed.value != aed.content_orig )
  {
    ajaxPerformAutosave();
  }
}

window.ajaxPerformAutosave = function()
{
  var aed = document.getElementById('ajaxEditArea');
  if ( !aed )
    return false;
  var now = unix_time();
  aed.as_last_save = now;
  
  var ta_content = $dynano('ajaxEditArea').getContent();
  
  if ( ta_content == '' || ta_content == '<p></p>' || ta_content == '<p>&nbsp;</p>' )
  {
    return false;
  }
  
  ajaxEditorSave(true);
}

window.ajaxEditorUseDraft = function()
{
  var aed = document.getElementById('ajaxEditArea');
  if ( !aed )
    return false;
  ajaxSetEditorLoading();
  ajaxGet(stdAjaxPrefix + '&_mode=getsource&get_draft=1', function(ajax)
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        ajaxUnSetEditorLoading();
        
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          handle_invalid_json(response);
          return false;
        }
        
        response = parseJSON(response);
        if ( response.mode == 'error' )
        {
          unselectAllButtonsMinor();
          new MessageBox(MB_OK | MB_ICONSTOP, $lang.get('editor_err_server'), response.error);
          return false;
        }
        
        editor_convert_if_needed(response.page_format);
        
        $dynano('ajaxEditArea').setContent(response.src);
        $dynano('ajaxEditArea').object.used_draft = true;
        
        var es = document.getElementById('enano_editor_field_summary');
        if ( es.value == '' )
        {
          es.value = response.edit_summary;
        }
        
        var dn = $dynano('ajax_edit_draft_notice').object;
        dn.parentNode.removeChild(dn);
      }
    }, true);
}

window.editor_convert_if_needed = function(targetformat, noticetitle, noticebody)
{
  // Do we need to change the format?
  var need_to_mce = ( targetformat == 'xhtml' && !$dynano('ajaxEditArea').isMCE() );
  var need_to_wkt = ( targetformat == 'wikitext' && $dynano('ajaxEditArea').isMCE() );
  if ( need_to_mce )
  {
    $dynano('ajaxEditArea').setContent('');
    $dynano('ajaxEditArea').switchToMCE(false);
    
    // Clear out existing buttons
    var span_wiki = $dynano('enano_edit_btn_pt').object;
    var span_mce  = $dynano('enano_edit_btn_mce').object;
    span_wiki.style.display = 'inline';
    span_mce.style.display = 'none';
  }
  else if ( need_to_wkt )
  {
    $dynano('ajaxEditArea').setContent('');
    $dynano('ajaxEditArea').destroyMCE(false);
    
    // Clear out existing buttons
    var span_wiki = $dynano('enano_edit_btn_pt').object;
    var span_mce  = $dynano('enano_edit_btn_mce').object;
    span_wiki.style.display = 'none';
    span_mce.style.display = 'inline';
  }
  if ( need_to_mce || need_to_wkt )
  {
    // explain the conversion
    if ( !noticetitle )
      noticetitle = 'editor_msg_convert_draft_load_title';
    if ( !noticebody )
      noticebody = 'editor_msg_convert_draft_load_body';
    
    miniPromptMessage({
        title: $lang.get(noticetitle),
        message: $lang.get(noticebody),
        buttons: [
          {
            text: $lang.get('etc_ok'),
            onclick: function()
            {
              miniPromptDestroy(this);
              return false;
            }
          }
        ]
      });
  }
}