
  /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:--
    --  FormOperations Plugin
    --
    --  $HeadURL: http://svn.xinha.org/trunk/plugins/FormOperations/FormOperations.js $
    --  $LastChangedDate: 2008-10-13 06:42:42 +1300 (Mon, 13 Oct 2008) $
    --  $LastChangedRevision: 1084 $
    --  $LastChangedBy: ray $
    --------------------------------------------------------------------------*/

Xinha.Config.prototype.FormOperations =
{
  // format for fields where multiple values may be selected
  //    'php'          => FieldName[]
  //    'unmodified'   => FieldName
  'multiple_field_format': 'php',
  'allow_edit_form'      : false,
  'default_form_action'  : Xinha.getPluginDir('FormOperations') + '/formmail.php',
  'default_form_html'    : Xinha._geturlcontent(Xinha.getPluginDir('FormOperations') + '/default_form.html')
};

FormOperations._pluginInfo =
{
  name     : "FormOperations",
  version  : "1.0",
  developer: "James Sleeman",
  developer_url: "http://www.gogo.co.nz/",
  c_owner      : "Gogo Internet Services",
  license      : "htmlArea",
  sponsor      : "Gogo Internet Services",
  sponsor_url  : "http://www.gogo.co.nz/"
};

function FormOperations(editor)
{
  this.editor = editor;
  this.panel  = false;
  this.html   = false;
  this.ready  = false;
  this.activeElement = null;
  this._preparePanel();


  editor.config.pageStyleSheets.push(Xinha.getPluginDir('FormOperations') + '/iframe.css');

  var toolbar =
  [
    'separator',
    'insert_form',
    'insert_text_field',
    'insert_textarea_field',
    'insert_select_field',
    'insert_cb_field',
    'insert_rb_field',
    'insert_button'
  ];

  this.editor.config.toolbar.push(toolbar);

  function pasteAndSelect(htmlTag)
  {
    var id = Xinha.uniq('fo');
    htmlTag = htmlTag.replace(/^<([^ \/>]+)/i, '<$1 id="'+id+'"');
    editor.insertHTML(htmlTag);
    var el = editor._doc.getElementById(id);
    el.setAttribute('id', '');
    editor.selectNodeContents(el);
    editor.updateToolbar();
    return el;
  }

  var buttonsImage = editor.imgURL('buttons.gif', 'FormOperations');

  FormOperations.prototype._lc = function(string) {
    return Xinha._lc(string, 'FormOperations');
  };

  this.editor.config.btnList.insert_form =
  [ this._lc("Insert a Form."),
    [buttonsImage, 0, 0],
    false,
    function()
    {
      var form = null;
      if(editor.config.FormOperations.default_form_html)
      {
        form = pasteAndSelect(editor.config.FormOperations.default_form_html);
      }
      else
      {
        form = pasteAndSelect('<form>&nbsp;</form>');
      }

      if(editor.config.FormOperations.default_form_action && !form.action)
      {
        form.action = editor.config.FormOperations.default_form_action;
      }
    }
  ];

  this.editor.config.btnList.insert_text_field =
  [ this._lc("Insert a text, password or hidden field."),
    [buttonsImage, 1, 0],
    false,
    function()
    {
      pasteAndSelect('<input type="text" />');
    },
    'form'
  ];

  this.editor.config.btnList.insert_textarea_field =
  [ this._lc("Insert a multi-line text field."),
    [buttonsImage, 2, 0],
    false,
    function()
    {
      pasteAndSelect('<textarea> </textarea>');
    },
    'form'
  ];

  this.editor.config.btnList.insert_select_field =
  [ this._lc("Insert a select field."),
    [buttonsImage, 3, 0],
    false,
    function()
    {
      pasteAndSelect('<select> <option value="">Please Select...</option> </select>');
    },
    'form'
  ];

  this.editor.config.btnList.insert_cb_field =
  [ this._lc("Insert a check box."),
    [buttonsImage, 4, 0],
    false,
    function()
    {
      pasteAndSelect('<input type="checkbox" />');
    },
    'form'
  ];

  this.editor.config.btnList.insert_rb_field =
  [ this._lc("Insert a radio button."),
    [buttonsImage, 5, 0],
    false,
    function()
    {
      pasteAndSelect('<input type="radio" />');
    },
    'form'
  ];

  this.editor.config.btnList.insert_button =
  [ this._lc("Insert a submit/reset button."),
    [buttonsImage, 6, 0],
    false,
    function()
    {
      pasteAndSelect('<input type="submit" value="Send" />');
    },
    'form'
  ];
}

FormOperations.prototype.onGenerate = function()
{
  // Gecko does not register click events on select lists inside the iframe
  // so the only way of detecting that is to do an event on mouse move.
  if( Xinha.is_gecko)
  {
    var editor = this.editor;
    var doc    = this.editor._doc;
    Xinha._addEvents
    (doc, ["mousemove"],
     function (event) {
       return editor._editorEvent(event);
     });
  }
};

FormOperations.prototype._preparePanel = function ()
{
  var fo = this;
  if(this.html == false)
  {

    Xinha._getback(Xinha.getPluginDir('FormOperations') + '/panel.html',
      function(txt)
      {
        fo.html = txt;
        fo._preparePanel();
      }
    );
    return false;
  }

  if(typeof Xinha.Dialog == 'undefined')
  {
    Xinha._loadback
      (_editor_url + 'modules/Dialogs/XinhaDialog.js', function() { fo._preparePanel(); } );
      return false;
  }

  if(typeof Xinha.PanelDialog == 'undefined')
  {
    Xinha._loadback
      (_editor_url + 'modules/Dialogs/panel-dialog.js', function() { fo._preparePanel(); } );
      return false;
  }



  this.panel = new Xinha.PanelDialog(this.editor,'bottom',this.html,'FormOperations');
  this.panel.hide();
  this.ready = true;
};

FormOperations.prototype.onUpdateToolbar = function()
{
  if(!this.ready) return true;
  var activeElement = this.editor._activeElement(this.editor._getSelection());
  if(activeElement != null)
  {
    if(activeElement == this.activeElement) return true;

    var tag = activeElement.tagName.toLowerCase();
    
    this.hideAll();
    if(tag === 'form')
    {
      if(this.editor.config.FormOperations.allow_edit_form)
      {
        this.showForm(activeElement);
      }
      else
      {
        this.panel.hide();
        this.activeElement = null;
        this.panel.hide();
        return true;
      }
    }
    else
    {

      if(this.editor.config.FormOperations.allow_edit_form && typeof activeElement.form != 'undefined' && activeElement.form)
      {
        this.showForm(activeElement.form);
      }

      switch(tag)
      {
        case 'form':
        {
          this.showForm(activeElement);
        }
        break;

        case 'input':
        {
          switch(activeElement.getAttribute('type').toLowerCase())
          {
            case 'text'    :
            case 'password':
            case 'hidden'  :
            {
              this.showText(activeElement);
            }
            break;

            case 'radio'   :
            case 'checkbox':
            {
              this.showCbRd(activeElement);
            }
            break;

            case 'submit'  :
            case 'reset'   :
            case 'button'  :
            {
              this.showButton(activeElement);
            }
            break;
          }
        }
        break;

        case 'textarea':
        {
          this.showTextarea(activeElement);
        }
        break;

        case 'select':
        {
          this.showSelect(activeElement);
        }
        break;

        default:
        {
          this.activeElement = null;
          this.panel.hide();
          return true;
        }
      }
    }
    
    this.panel.show();
    
    //this.editor.scrollToElement(activeElement);
    this.activeElement = activeElement;
    return true;
  }
  else
  {
    this.activeElement = null;
    this.panel.hide();
    return true;
  }
};


FormOperations.prototype.hideAll = function()
{
  this.panel.getElementById('fs_form').style.display = 'none';
  this.panel.getElementById('fs_text').style.display = 'none';
  this.panel.getElementById('fs_textarea').style.display = 'none';
  this.panel.getElementById('fs_select').style.display = 'none';
  this.panel.getElementById('fs_cbrd').style.display = 'none';
  this.panel.getElementById('fs_button').style.display = 'none';
};

FormOperations.prototype.showForm = function(form)
{
  this.panel.getElementById('fs_form').style.display = '';
  var vals =
  {
    'action' : form.action,
    'method' : form.method.toUpperCase()
  }
  this.panel.setValues(vals);
  var f = form;
  this.panel.getElementById('action').onkeyup = function () { f.action = this.value; };
  this.panel.getElementById('method').onchange   = function () { f.method = this.options[this.selectedIndex].value; };
};

FormOperations.prototype.showText = function (input)
{
  this.panel.getElementById('fs_text').style.display = '';

  var vals =
  {
    'text_name'  : this.deformatName(input, input.name),
    'text_value' : input.value,
    'text_type'  : input.type.toLowerCase(),
    'text_width' : input.style.width ? parseFloat(input.style.width.replace(/[^0-9.]/, '')) : '',
    'text_width_units': input.style.width ? input.style.width.replace(/[0-9.]/, '').toLowerCase() : 'ex',
    'text_maxlength'  : input.maxlength   ? input.maxlength : ''
  }
  this.panel.setValues(vals);

  var i = input;
  var fo = this;

  this.panel.getElementById('text_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); }
  this.panel.getElementById('text_value').onkeyup  = function () { i.value = this.value; }
  this.panel.getElementById('text_type').onchange   = function ()
    {
      if(!Xinha.is_ie)
      {
        i.type = this.options[this.selectedIndex].value;
      }
      else
      {
        // IE does not permit modifications of the type of a form field once it is set
        // We therefor have to destroy and recreate it.  I swear, if I ever
        // meet any of the Internet Explorer development team I'm gonna
        // kick them in the nuts!
        var tmpContainer = fo.editor._doc.createElement('div');
        if(!/type=/.test(i.outerHTML))
        {
          tmpContainer.innerHTML = i.outerHTML.replace(/<INPUT/i, '<input type="'+ this.options[this.selectedIndex].value + '"');
        }
        else
        {
          tmpContainer.innerHTML = i.outerHTML.replace(/type="?[a-z]+"?/i, 'type="' + this.options[this.selectedIndex].value + '"');
        }
        var newElement = Xinha.removeFromParent(tmpContainer.childNodes[0]);
        i.parentNode.insertBefore(newElement, i);
        Xinha.removeFromParent(i);
        input = i = newElement;
      }
    }

  var w  = this.panel.getElementById('text_width');
  var wu = this.panel.getElementById('text_width_units');

  this.panel.getElementById('text_width').onkeyup     =
  this.panel.getElementById('text_width_units').onchange =
    function ()
    {
      if(!w.value || isNaN(parseFloat(w.value)))
      {
        i.style.width = '';
      }
      i.style.width = parseFloat(w.value) + wu.options[wu.selectedIndex].value;
    }

  this.panel.getElementById('text_maxlength').onkeyup = function () { i.maxlength = this.value; }
};

FormOperations.prototype.showCbRd = function (input)
{
  this.panel.getElementById('fs_cbrd').style.display = '';
  var vals =
  {
    'cbrd_name'    : this.deformatName(input, input.name),
    'cbrd_value'   : input.value,
    'cbrd_checked' : input.checked ? 1 : 0,
    'cbrd_type'    : input.type.toLowerCase()
  };
  this.panel.setValues(vals);

  var i = input;
  var fo = this;
  this.panel.getElementById('cbrd_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); }
  this.panel.getElementById('cbrd_value').onkeyup  = function () { i.value = this.value; }
  this.panel.getElementById('cbrd_type').onchange   = function ()
    {
      if(!Xinha.is_ie)
      {
        i.type = this.options[this.selectedIndex].value;
      }
      else
      {
        // IE does not permit modifications of the type of a form field once it is set
        // We therefor have to destroy and recreate it.  I swear, if I ever
        // meet any of the Internet Explorer development team I'm gonna
        // kick them in the nuts!
        var tmpContainer = fo.editor._doc.createElement('div');
        if(!/type=/.test(i.outerHTML))
        {
          tmpContainer.innerHTML = i.outerHTML.replace(/<INPUT/i, '<input type="'+ this.options[this.selectedIndex].value + '"');
        }
        else
        {
          tmpContainer.innerHTML = i.outerHTML.replace(/type="?[a-z]+"?/i, 'type="' + this.options[this.selectedIndex].value + '"');
        }
        var newElement = Xinha.removeFromParent(tmpContainer.childNodes[0]);
        i.parentNode.insertBefore(newElement, i);
        Xinha.removeFromParent(i);
        input = i = newElement;
      }
    }
  this.panel.getElementById('cbrd_checked').onclick   = function () { i.checked = this.checked; }
};

FormOperations.prototype.showButton = function (input)
{
  this.panel.getElementById('fs_button').style.display = '';
  var vals =
  {
    'button_name'    : this.deformatName(input, input.name),
    'button_value'   : input.value,
    'button_type'    : input.type.toLowerCase()
  };
  this.panel.setValues(vals);

  var i = input;
  var fo = this;
  this.panel.getElementById('button_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); };
  this.panel.getElementById('button_value').onkeyup  = function () { i.value = this.value; };
  this.panel.getElementById('button_type').onchange   = function ()
    {
      if(!Xinha.is_ie)
      {
        i.type = this.options[this.selectedIndex].value;
      }
      else
      {
        // IE does not permit modifications of the type of a form field once it is set
        // We therefor have to destroy and recreate it.  I swear, if I ever
        // meet any of the Internet Explorer development team I'm gonna
        // kick them in the nuts!
        var tmpContainer = fo.editor._doc.createElement('div');
        if(!/type=/.test(i.outerHTML))
        {
          tmpContainer.innerHTML = i.outerHTML.replace(/<INPUT/i, '<input type="'+ this.options[this.selectedIndex].value + '"');
        }
        else
        {
          tmpContainer.innerHTML = i.outerHTML.replace(/type="?[a-z]+"?/i, 'type="' + this.options[this.selectedIndex].value + '"');
        }
        var newElement = Xinha.removeFromParent(tmpContainer.childNodes[0]);
        i.parentNode.insertBefore(newElement, i);
        Xinha.removeFromParent(i);
        input = i = newElement;
      }
    };
};

FormOperations.prototype.showTextarea = function (input)
{
  this.panel.getElementById('fs_textarea').style.display = '';
  var vals =
  {
    'textarea_name'  : this.deformatName(input, input.name),
    'textarea_value' : input.value,
    'textarea_width' : input.style.width ? parseFloat(input.style.width.replace(/[^0-9.]/, '')) : '',
    'textarea_width_units' : input.style.width ? input.style.width.replace(/[0-9.]/, '').toLowerCase() : 'ex',
    'textarea_height'      : input.style.height ? parseFloat(input.style.height.replace(/[^0-9.]/, '')) : '',
    'textarea_height_units': input.style.height ? input.style.height.replace(/[0-9.]/, '').toLowerCase() : 'ex'
  };

  this.panel.setValues(vals);

  var i = input;
  var fo = this;
  this.panel.getElementById('textarea_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); };
  this.panel.getElementById('textarea_value').onkeyup  = function () { i.value = i.innerHTML = this.value; };

  var w  = this.panel.getElementById('textarea_width');
  var wu = this.panel.getElementById('textarea_width_units');

  this.panel.getElementById('textarea_width').onkeyup     =
  this.panel.getElementById('textarea_width_units').onchange =
    function ()
    {
      if(!w.value || isNaN(parseFloat(w.value)))
      {
        i.style.width = '';
      }
      i.style.width = parseFloat(w.value) + wu.options[wu.selectedIndex].value;
    };

  var h  = this.panel.getElementById('textarea_height');
  var hu = this.panel.getElementById('textarea_height_units');

  this.panel.getElementById('textarea_height').onkeyup     =
  this.panel.getElementById('textarea_height_units').onchange =
    function ()
    {
      if(!h.value || isNaN(parseFloat(h.value)))
      {
        i.style.height = '';
      }
      i.style.height = parseFloat(h.value) + hu.options[hu.selectedIndex].value;
    };

};

FormOperations.prototype.showSelect = function (input)
{
  this.panel.getElementById('fs_select').style.display = '';
  var vals =
  {
    'select_name'  : this.deformatName(input, input.name),
    'select_multiple' : input.multiple ? 1 : 0,
    'select_width' : input.style.width ? parseFloat(input.style.width.replace(/[^0-9.]/, '')) : '',
    'select_width_units' : input.style.width ? input.style.width.replace(/[0-9.]/, '').toLowerCase() : 'ex',
      'select_height'      : input.style.height ? parseFloat(input.style.height.replace(/[^0-9.]/, '')) : (input.size && input.size > 0 ? input.size : 1),
    'select_height_units': input.style.height ? input.style.height.replace(/[0-9.]/, '').toLowerCase() : 'items'
  };

  this.panel.setValues(vals);

  var i = input;
  var fo = this;
  this.panel.getElementById('select_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); };
  this.panel.getElementById('select_multiple').onclick   = function () { i.multiple = this.checked; };

  var w  = this.panel.getElementById('select_width');
  var wu = this.panel.getElementById('select_width_units');

  this.panel.getElementById('select_width').onkeyup     =
  this.panel.getElementById('select_width_units').onchange =
    function ()
    {
      if(!w.value || isNaN(parseFloat(w.value)))
      {
        i.style.width = '';
      }
      i.style.width = parseFloat(w.value) + wu.options[wu.selectedIndex].value;
    };

  var h  = this.panel.getElementById('select_height');
  var hu = this.panel.getElementById('select_height_units');

  this.panel.getElementById('select_height').onkeyup     =
  this.panel.getElementById('select_height_units').onchange =
    function ()
    {
      if(!h.value || isNaN(parseFloat(h.value)))
      {
        i.style.height = '';
        return;
      }

      if(hu.selectedIndex == 0)
      {
        i.style.height = '';
        i.size = parseInt(h.value);
      }
      else
      {
        i.style.height = parseFloat(h.value) + hu.options[hu.selectedIndex].value;
      }
    };


  var fo_sel = this.panel.getElementById('select_options');
  this.arrayToOpts(this.optsToArray(input.options), fo_sel.options);

  this.panel.getElementById('add_option').onclick =
    function()
    {
      var txt = prompt(Xinha._lc("Enter the name for new option.", 'FormOperations'));
      if(txt == null) return;
      var newOpt = new Option(txt);
      var opts   = fo.optsToArray(fo_sel.options);
      if(fo_sel.selectedIndex >= 0)
      {
        opts.splice(fo_sel.selectedIndex, 0, newOpt);
      }
      else
      {
        opts.push(newOpt);
      }
      fo.arrayToOpts(opts, input.options);
      fo.arrayToOpts(opts, fo_sel.options);
    };

  this.panel.getElementById('del_option').onclick =
    function()
    {
      var opts    = fo.optsToArray(fo_sel.options);
      var newOpts = [ ];
      for(var i = 0; i < opts.length; i++)
      {
        if(opts[i].selected) continue;
        newOpts.push(opts[i]);
      }
      fo.arrayToOpts(newOpts, input.options);
      fo.arrayToOpts(newOpts, fo_sel.options);
    };

  this.panel.getElementById('up_option').onclick =
    function()
    {
      if(!(fo_sel.selectedIndex > 0)) return;
      var opts    = fo.optsToArray(fo_sel.options);
      var move    = opts.splice(fo_sel.selectedIndex, 1).pop();
      opts.splice(fo_sel.selectedIndex - 1, 0, move);
      fo.arrayToOpts(opts, input.options);
      fo.arrayToOpts(opts, fo_sel.options);
    };

  this.panel.getElementById('down_option').onclick =
    function()
    {
      if(fo_sel.selectedIndex == fo_sel.options.length - 1) return;
      var opts    = fo.optsToArray(fo_sel.options);
      var move    = opts.splice(fo_sel.selectedIndex, 1).pop();
      opts.splice(fo_sel.selectedIndex+1, 0, move);
      fo.arrayToOpts(opts, input.options);
      fo.arrayToOpts(opts, fo_sel.options);
    };

  this.panel.getElementById('select_options').onchange =
    function()
    {
      fo.arrayToOpts(fo.optsToArray(fo_sel.options), input.options);
    };
};

FormOperations.prototype.optsToArray = function(o)
{
  var a = [ ];
  for(var i = 0; i < o.length; i++)
  {
    a.push(
      {
        'text'            : o[i].text,
        'value'           : o[i].value,
        'defaultSelected' : o[i].defaultSelected,
        'selected'        : o[i].selected
      }
    );
  }
  return a;
};

FormOperations.prototype.arrayToOpts = function(a, o)
{
  for(var i = o.length -1; i >= 0; i--)
  {
    o[i] = null;
  }

  for(var i = 0; i < a.length; i++)
  {
    o[i] = new Option(a[i].text, a[i].value, a[i].defaultSelected, a[i].selected);
  }
};

FormOperations.prototype.formatName = function(input, name)
{

  // Multiple name
  var mname = name;
  switch(this.editor.config.FormOperations.multiple_field_format)
  {
    case 'php':
    {
      mname += '[]';
    }
    break;

    case 'unmodified':
    {
      // Leave as is.
    }
    break;

    default:
    {
      throw("Unknown multiple field format " + this.editor.config.FormOperations.multiple_field_format);
    }
  }

  if
  (
       (input.tagName.toLowerCase() == 'select' && input.multiple)
    || (input.tagName.toLowerCase() == 'input'  && input.type.toLowerCase() == 'checkbox')
  )
  {
    name = mname;
  }

  return name;
};

FormOperations.prototype.deformatName = function(input, name)
{
  if(this.editor.config.FormOperations.multiple_field_format == 'php')
  {
    name = name.replace(/\[\]$/, '');
  }

  return name;
};