source: trunk/plugins/FormOperations/form-operations.js @ 715

Last change on this file since 715 was 715, checked in by htanaka, 12 years ago

Ticket #939 Japanese translation finished.
fix translation capability of Forms,FormOperations?,InsertMarquee? and NoteServer?.
append Japanese to language option in ext_example page.
(Forms became silent in updating properties, and fixed <FORM> tag update problem.)

  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
File size: 21.0 KB
Line 
1
2  /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:--
3    --  FormOperations Plugin
4    --
5    --  $HeadURL$
6    --  $LastChangedDate$
7    --  $LastChangedRevision$
8    --  $LastChangedBy$
9    --------------------------------------------------------------------------*/
10
11Xinha.Config.prototype.FormOperations =
12{
13  // format for fields where multiple values may be selected
14  //    'php'          => FieldName[]
15  //    'unmodified'   => FieldName
16  'multiple_field_format': 'php',
17  'allow_edit_form'      : false,
18  'default_form_action'  : _editor_url + 'plugins/FormOperations/formmail.php',
19  'default_form_html'    : Xinha._geturlcontent(_editor_url + 'plugins/FormOperations/default_form.html')
20};
21
22FormOperations._pluginInfo =
23{
24  name     : "FormOperations",
25  version  : "1.0",
26  developer: "James Sleeman",
27  developer_url: "http://www.gogo.co.nz/",
28  c_owner      : "Gogo Internet Services",
29  license      : "htmlArea",
30  sponsor      : "Gogo Internet Services",
31  sponsor_url  : "http://www.gogo.co.nz/"
32};
33
34function FormOperations(editor)
35{
36  this.editor = editor;
37  this.panel  = false;
38  this.html   = false;
39  this.ready  = false;
40  this.activeElement = null;
41  this._preparePanel();
42
43
44  editor.config.pageStyleSheets.push(_editor_url + 'plugins/FormOperations/iframe.css');
45
46  var toolbar =
47  [
48    'separator',
49    'insert_form',
50    'insert_text_field',
51    'insert_textarea_field',
52    'insert_select_field',
53    'insert_cb_field',
54    'insert_rb_field',
55    'insert_button'
56  ];
57
58  this.editor.config.toolbar.push(toolbar);
59
60  function pasteAndSelect(htmlTag)
61  {
62    var id = Xinha.uniq('fo');
63    htmlTag = htmlTag.replace(/^<([^ \/>]+)/i, '<$1 id="'+id+'"');
64    editor.insertHTML(htmlTag);
65    var el = editor._doc.getElementById(id);
66    el.setAttribute('id', '');
67    editor.selectNodeContents(el);
68    editor.updateToolbar();
69    return el;
70  }
71
72  var buttonsImage = editor.imgURL('buttons.gif', 'FormOperations');
73
74  FormOperations.prototype._lc = function(string) {
75    return Xinha._lc(string, 'FormOperations');
76  };
77
78  this.editor.config.btnList.insert_form =
79  [ this._lc("Insert a Form."),
80    [buttonsImage, 0, 0],
81    false,
82    function()
83    {
84      var form = null;
85      if(editor.config.FormOperations.default_form_html)
86      {
87        form = pasteAndSelect(editor.config.FormOperations.default_form_html);
88      }
89      else
90      {
91        form = pasteAndSelect('<form>&nbsp;</form>');
92      }
93
94      if(editor.config.FormOperations.default_form_action && !form.action)
95      {
96        form.action = editor.config.FormOperations.default_form_action;
97      }
98    }
99  ];
100
101  this.editor.config.btnList.insert_text_field =
102  [ this._lc("Insert a text, password or hidden field."),
103    [buttonsImage, 1, 0],
104    false,
105    function()
106    {
107      pasteAndSelect('<input type="text" />');
108    },
109    'form'
110  ];
111
112  this.editor.config.btnList.insert_textarea_field =
113  [ this._lc("Insert a multi-line text field."),
114    [buttonsImage, 2, 0],
115    false,
116    function()
117    {
118      pasteAndSelect('<textarea> </textarea>');
119    },
120    'form'
121  ];
122
123  this.editor.config.btnList.insert_select_field =
124  [ this._lc("Insert a select field."),
125    [buttonsImage, 3, 0],
126    false,
127    function()
128    {
129      pasteAndSelect('<select> <option value="">Please Select...</option> </select>');
130    },
131    'form'
132  ];
133
134  this.editor.config.btnList.insert_cb_field =
135  [ this._lc("Insert a check box."),
136    [buttonsImage, 4, 0],
137    false,
138    function()
139    {
140      pasteAndSelect('<input type="checkbox" />');
141    },
142    'form'
143  ];
144
145  this.editor.config.btnList.insert_rb_field =
146  [ this._lc("Insert a radio button."),
147    [buttonsImage, 5, 0],
148    false,
149    function()
150    {
151      pasteAndSelect('<input type="radio" />');
152    },
153    'form'
154  ];
155
156  this.editor.config.btnList.insert_button =
157  [ this._lc("Insert a submit/reset button."),
158    [buttonsImage, 6, 0],
159    false,
160    function()
161    {
162      pasteAndSelect('<input type="submit" value="Send" />');
163    },
164    'form'
165  ];
166}
167
168FormOperations.prototype.onGenerate = function()
169{
170  // Gecko does not register click events on select lists inside the iframe
171  // so the only way of detecting that is to do an event on mouse move.
172  if( Xinha.is_gecko)
173  {
174    var editor = this.editor;
175    var doc    = this.editor._doc;
176    Xinha._addEvents
177    (doc, ["mousemove"],
178     function (event) {
179       return editor._editorEvent(event);
180     });
181  }
182};
183
184FormOperations.prototype._preparePanel = function ()
185{
186  var fo = this;
187  if(this.html == false)
188  {
189
190    Xinha._getback(_editor_url + 'plugins/FormOperations/panel.html',
191      function(txt)
192      {
193        fo.html = txt;
194        fo._preparePanel();
195      }
196    );
197    return false;
198  }
199
200  if(typeof Xinha.Dialog == 'undefined')
201  {
202    Xinha._loadback
203      (_editor_url + 'modules/Dialogs/inline-dialog.js', function() { fo._preparePanel(); } );
204      return false;
205  }
206
207  if(typeof Xinha.PanelDialog == 'undefined')
208  {
209    Xinha._loadback
210      (_editor_url + 'modules/Dialogs/panel-dialog.js', function() { fo._preparePanel(); } );
211      return false;
212  }
213
214
215
216  this.panel = new Xinha.PanelDialog(this.editor,'bottom',this.html,'FormOperations');
217  this.panel.hide();
218  this.ready = true;
219};
220
221FormOperations.prototype.onUpdateToolbar = function()
222{
223  if(!this.ready) return true;
224  var activeElement = this.editor._activeElement(this.editor._getSelection());
225  if(activeElement != null)
226  {
227    if(activeElement == this.activeElement) return true;
228
229    var tag = activeElement.tagName.toLowerCase();
230   
231    this.hideAll();
232    if(tag === 'form')
233    {
234      if(this.editor.config.FormOperations.allow_edit_form)
235      {
236        this.showForm(activeElement);
237      }
238      else
239      {
240        this.panel.hide();
241        this.activeElement = null;
242        this.panel.hide();
243        return true;
244      }
245    }
246    else
247    {
248
249      if(this.editor.config.FormOperations.allow_edit_form && typeof activeElement.form != 'undefined' && activeElement.form)
250      {
251        this.showForm(activeElement.form);
252      }
253
254      switch(tag)
255      {
256        case 'form':
257        {
258          this.showForm(activeElement);
259        }
260        break;
261
262        case 'input':
263        {
264          switch(activeElement.getAttribute('type').toLowerCase())
265          {
266            case 'text'    :
267            case 'password':
268            case 'hidden'  :
269            {
270              this.showText(activeElement);
271            }
272            break;
273
274            case 'radio'   :
275            case 'checkbox':
276            {
277              this.showCbRd(activeElement);
278            }
279            break;
280
281            case 'submit'  :
282            case 'reset'   :
283            case 'button'  :
284            {
285              this.showButton(activeElement);
286            }
287            break;
288          }
289        }
290        break;
291
292        case 'textarea':
293        {
294          this.showTextarea(activeElement);
295        }
296        break;
297
298        case 'select':
299        {
300          this.showSelect(activeElement);
301        }
302        break;
303
304        default:
305        {
306          this.activeElement = null;
307          this.panel.hide();
308          return true;
309        }
310      }
311    }
312   
313    this.panel.show();
314   
315    //this.editor.scrollToElement(activeElement);
316    this.activeElement = activeElement;
317    return true;
318  }
319  else
320  {
321    this.activeElement = null;
322    this.panel.hide();
323    return true;
324  }
325};
326
327
328FormOperations.prototype.hideAll = function()
329{
330  this.panel.getElementById('fs_form').style.display = 'none';
331  this.panel.getElementById('fs_text').style.display = 'none';
332  this.panel.getElementById('fs_textarea').style.display = 'none';
333  this.panel.getElementById('fs_select').style.display = 'none';
334  this.panel.getElementById('fs_cbrd').style.display = 'none';
335  this.panel.getElementById('fs_button').style.display = 'none';
336};
337
338FormOperations.prototype.showForm = function(form)
339{
340  this.panel.getElementById('fs_form').style.display = '';
341  var vals =
342  {
343    'action' : form.action,
344    'method' : form.method.toUpperCase()
345  }
346  this.panel.setValues(vals);
347  var f = form;
348  this.panel.getElementById('action').onkeyup = function () { f.action = this.value; };
349  this.panel.getElementById('method').onchange   = function () { f.method = this.options[this.selectedIndex].value; };
350};
351
352FormOperations.prototype.showText = function (input)
353{
354  this.panel.getElementById('fs_text').style.display = '';
355
356  var vals =
357  {
358    'text_name'  : this.deformatName(input, input.name),
359    'text_value' : input.value,
360    'text_type'  : input.type.toLowerCase(),
361    'text_width' : input.style.width ? parseFloat(input.style.width.replace(/[^0-9.]/, '')) : '',
362    'text_width_units': input.style.width ? input.style.width.replace(/[0-9.]/, '').toLowerCase() : 'ex',
363    'text_maxlength'  : input.maxlength   ? input.maxlength : ''
364  }
365  this.panel.setValues(vals);
366
367  var i = input;
368  var fo = this;
369
370  this.panel.getElementById('text_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); }
371  this.panel.getElementById('text_value').onkeyup  = function () { i.value = this.value; }
372  this.panel.getElementById('text_type').onchange   = function ()
373    {
374      if(!Xinha.is_ie)
375      {
376        i.type = this.options[this.selectedIndex].value;
377      }
378      else
379      {
380        // IE does not permit modifications of the type of a form field once it is set
381        // We therefor have to destroy and recreate it.  I swear, if I ever
382        // meet any of the Internet Explorer development team I'm gonna
383        // kick them in the nuts!
384        var tmpContainer = fo.editor._doc.createElement('div');
385        if(!/type=/.test(i.outerHTML))
386        {
387          tmpContainer.innerHTML = i.outerHTML.replace(/<INPUT/i, '<input type="'+ this.options[this.selectedIndex].value + '"');
388        }
389        else
390        {
391          tmpContainer.innerHTML = i.outerHTML.replace(/type="?[a-z]+"?/i, 'type="' + this.options[this.selectedIndex].value + '"');
392        }
393        var newElement = Xinha.removeFromParent(tmpContainer.childNodes[0]);
394        i.parentNode.insertBefore(newElement, i);
395        Xinha.removeFromParent(i);
396        input = i = newElement;
397      }
398    }
399
400  var w  = this.panel.getElementById('text_width');
401  var wu = this.panel.getElementById('text_width_units');
402
403  this.panel.getElementById('text_width').onkeyup     =
404  this.panel.getElementById('text_width_units').onchange =
405    function ()
406    {
407      if(!w.value || isNaN(parseFloat(w.value)))
408      {
409        i.style.width = '';
410      }
411      i.style.width = parseFloat(w.value) + wu.options[wu.selectedIndex].value;
412    }
413
414  this.panel.getElementById('text_maxlength').onkeyup = function () { i.maxlength = this.value; }
415};
416
417FormOperations.prototype.showCbRd = function (input)
418{
419  this.panel.getElementById('fs_cbrd').style.display = '';
420  var vals =
421  {
422    'cbrd_name'    : this.deformatName(input, input.name),
423    'cbrd_value'   : input.value,
424    'cbrd_checked' : input.checked ? 1 : 0,
425    'cbrd_type'    : input.type.toLowerCase()
426  };
427  this.panel.setValues(vals);
428
429  var i = input;
430  var fo = this;
431  this.panel.getElementById('cbrd_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); }
432  this.panel.getElementById('cbrd_value').onkeyup  = function () { i.value = this.value; }
433  this.panel.getElementById('cbrd_type').onchange   = function ()
434    {
435      if(!Xinha.is_ie)
436      {
437        i.type = this.options[this.selectedIndex].value;
438      }
439      else
440      {
441        // IE does not permit modifications of the type of a form field once it is set
442        // We therefor have to destroy and recreate it.  I swear, if I ever
443        // meet any of the Internet Explorer development team I'm gonna
444        // kick them in the nuts!
445        var tmpContainer = fo.editor._doc.createElement('div');
446        if(!/type=/.test(i.outerHTML))
447        {
448          tmpContainer.innerHTML = i.outerHTML.replace(/<INPUT/i, '<input type="'+ this.options[this.selectedIndex].value + '"');
449        }
450        else
451        {
452          tmpContainer.innerHTML = i.outerHTML.replace(/type="?[a-z]+"?/i, 'type="' + this.options[this.selectedIndex].value + '"');
453        }
454        var newElement = Xinha.removeFromParent(tmpContainer.childNodes[0]);
455        i.parentNode.insertBefore(newElement, i);
456        Xinha.removeFromParent(i);
457        input = i = newElement;
458      }
459    }
460  this.panel.getElementById('cbrd_checked').onclick   = function () { i.checked = this.checked; }
461};
462
463FormOperations.prototype.showButton = function (input)
464{
465  this.panel.getElementById('fs_button').style.display = '';
466  var vals =
467  {
468    'button_name'    : this.deformatName(input, input.name),
469    'button_value'   : input.value,
470    'button_type'    : input.type.toLowerCase()
471  };
472  this.panel.setValues(vals);
473
474  var i = input;
475  var fo = this;
476  this.panel.getElementById('button_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); };
477  this.panel.getElementById('button_value').onkeyup  = function () { i.value = this.value; };
478  this.panel.getElementById('button_type').onchange   = function ()
479    {
480      if(!Xinha.is_ie)
481      {
482        i.type = this.options[this.selectedIndex].value;
483      }
484      else
485      {
486        // IE does not permit modifications of the type of a form field once it is set
487        // We therefor have to destroy and recreate it.  I swear, if I ever
488        // meet any of the Internet Explorer development team I'm gonna
489        // kick them in the nuts!
490        var tmpContainer = fo.editor._doc.createElement('div');
491        if(!/type=/.test(i.outerHTML))
492        {
493          tmpContainer.innerHTML = i.outerHTML.replace(/<INPUT/i, '<input type="'+ this.options[this.selectedIndex].value + '"');
494        }
495        else
496        {
497          tmpContainer.innerHTML = i.outerHTML.replace(/type="?[a-z]+"?/i, 'type="' + this.options[this.selectedIndex].value + '"');
498        }
499        var newElement = Xinha.removeFromParent(tmpContainer.childNodes[0]);
500        i.parentNode.insertBefore(newElement, i);
501        Xinha.removeFromParent(i);
502        input = i = newElement;
503      }
504    };
505};
506
507FormOperations.prototype.showTextarea = function (input)
508{
509  this.panel.getElementById('fs_textarea').style.display = '';
510  var vals =
511  {
512    'textarea_name'  : this.deformatName(input, input.name),
513    'textarea_value' : input.value,
514    'textarea_width' : input.style.width ? parseFloat(input.style.width.replace(/[^0-9.]/, '')) : '',
515    'textarea_width_units' : input.style.width ? input.style.width.replace(/[0-9.]/, '').toLowerCase() : 'ex',
516    'textarea_height'      : input.style.height ? parseFloat(input.style.height.replace(/[^0-9.]/, '')) : '',
517    'textarea_height_units': input.style.height ? input.style.height.replace(/[0-9.]/, '').toLowerCase() : 'ex'
518  };
519
520  this.panel.setValues(vals);
521
522  var i = input;
523  var fo = this;
524  this.panel.getElementById('textarea_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); };
525  this.panel.getElementById('textarea_value').onkeyup  = function () { i.value = i.innerHTML = this.value; };
526
527  var w  = this.panel.getElementById('textarea_width');
528  var wu = this.panel.getElementById('textarea_width_units');
529
530  this.panel.getElementById('textarea_width').onkeyup     =
531  this.panel.getElementById('textarea_width_units').onchange =
532    function ()
533    {
534      if(!w.value || isNaN(parseFloat(w.value)))
535      {
536        i.style.width = '';
537      }
538      i.style.width = parseFloat(w.value) + wu.options[wu.selectedIndex].value;
539    };
540
541  var h  = this.panel.getElementById('textarea_height');
542  var hu = this.panel.getElementById('textarea_height_units');
543
544  this.panel.getElementById('textarea_height').onkeyup     =
545  this.panel.getElementById('textarea_height_units').onchange =
546    function ()
547    {
548      if(!h.value || isNaN(parseFloat(h.value)))
549      {
550        i.style.height = '';
551      }
552      i.style.height = parseFloat(h.value) + hu.options[hu.selectedIndex].value;
553    };
554
555};
556
557FormOperations.prototype.showSelect = function (input)
558{
559  this.panel.getElementById('fs_select').style.display = '';
560  var vals =
561  {
562    'select_name'  : this.deformatName(input, input.name),
563    'select_multiple' : input.multiple ? 1 : 0,
564    'select_width' : input.style.width ? parseFloat(input.style.width.replace(/[^0-9.]/, '')) : '',
565    'select_width_units' : input.style.width ? input.style.width.replace(/[0-9.]/, '').toLowerCase() : 'ex',
566      'select_height'      : input.style.height ? parseFloat(input.style.height.replace(/[^0-9.]/, '')) : (input.size && input.size > 0 ? input.size : 1),
567    'select_height_units': input.style.height ? input.style.height.replace(/[0-9.]/, '').toLowerCase() : 'items'
568  };
569
570  this.panel.setValues(vals);
571
572  var i = input;
573  var fo = this;
574  this.panel.getElementById('select_name').onkeyup   = function () { i.name = fo.formatName(i, this.value); };
575  this.panel.getElementById('select_multiple').onclick   = function () { i.multiple = this.checked; };
576
577  var w  = this.panel.getElementById('select_width');
578  var wu = this.panel.getElementById('select_width_units');
579
580  this.panel.getElementById('select_width').onkeyup     =
581  this.panel.getElementById('select_width_units').onchange =
582    function ()
583    {
584      if(!w.value || isNaN(parseFloat(w.value)))
585      {
586        i.style.width = '';
587      }
588      i.style.width = parseFloat(w.value) + wu.options[wu.selectedIndex].value;
589    };
590
591  var h  = this.panel.getElementById('select_height');
592  var hu = this.panel.getElementById('select_height_units');
593
594  this.panel.getElementById('select_height').onkeyup     =
595  this.panel.getElementById('select_height_units').onchange =
596    function ()
597    {
598      if(!h.value || isNaN(parseFloat(h.value)))
599      {
600        i.style.height = '';
601        return;
602      }
603
604      if(hu.selectedIndex == 0)
605      {
606        i.style.height = '';
607        i.size = parseInt(h.value);
608      }
609      else
610      {
611        i.style.height = parseFloat(h.value) + hu.options[hu.selectedIndex].value;
612      }
613    };
614
615
616  var fo_sel = this.panel.getElementById('select_options');
617  this.arrayToOpts(this.optsToArray(input.options), fo_sel.options);
618
619  this.panel.getElementById('add_option').onclick =
620    function()
621    {
622      var txt = prompt(Xinha._lc("Enter the name for new option.", 'FormOperations'));
623      if(txt == null) return;
624      var newOpt = new Option(txt);
625      var opts   = fo.optsToArray(fo_sel.options);
626      if(fo_sel.selectedIndex >= 0)
627      {
628        opts.splice(fo_sel.selectedIndex, 0, newOpt);
629      }
630      else
631      {
632        opts.push(newOpt);
633      }
634      fo.arrayToOpts(opts, input.options);
635      fo.arrayToOpts(opts, fo_sel.options);
636    };
637
638  this.panel.getElementById('del_option').onclick =
639    function()
640    {
641      var opts    = fo.optsToArray(fo_sel.options);
642      var newOpts = [ ];
643      for(var i = 0; i < opts.length; i++)
644      {
645        if(opts[i].selected) continue;
646        newOpts.push(opts[i]);
647      }
648      fo.arrayToOpts(newOpts, input.options);
649      fo.arrayToOpts(newOpts, fo_sel.options);
650    };
651
652  this.panel.getElementById('up_option').onclick =
653    function()
654    {
655      if(!(fo_sel.selectedIndex > 0)) return;
656      var opts    = fo.optsToArray(fo_sel.options);
657      var move    = opts.splice(fo_sel.selectedIndex, 1).pop();
658      opts.splice(fo_sel.selectedIndex - 1, 0, move);
659      fo.arrayToOpts(opts, input.options);
660      fo.arrayToOpts(opts, fo_sel.options);
661    };
662
663  this.panel.getElementById('down_option').onclick =
664    function()
665    {
666      if(fo_sel.selectedIndex == fo_sel.options.length - 1) return;
667      var opts    = fo.optsToArray(fo_sel.options);
668      var move    = opts.splice(fo_sel.selectedIndex, 1).pop();
669      opts.splice(fo_sel.selectedIndex+1, 0, move);
670      fo.arrayToOpts(opts, input.options);
671      fo.arrayToOpts(opts, fo_sel.options);
672    };
673
674  this.panel.getElementById('select_options').onchange =
675    function()
676    {
677      fo.arrayToOpts(fo.optsToArray(fo_sel.options), input.options);
678    };
679};
680
681FormOperations.prototype.optsToArray = function(o)
682{
683  var a = [ ];
684  for(var i = 0; i < o.length; i++)
685  {
686    a.push(
687      {
688        'text'            : o[i].text,
689        'value'           : o[i].value,
690        'defaultSelected' : o[i].defaultSelected,
691        'selected'        : o[i].selected
692      }
693    );
694  }
695  return a;
696};
697
698FormOperations.prototype.arrayToOpts = function(a, o)
699{
700  for(var i = o.length -1; i >= 0; i--)
701  {
702    o[i] = null;
703  }
704
705  for(var i = 0; i < a.length; i++)
706  {
707    o[i] = new Option(a[i].text, a[i].value, a[i].defaultSelected, a[i].selected);
708  }
709};
710
711FormOperations.prototype.formatName = function(input, name)
712{
713
714  // Multiple name
715  var mname = name;
716  switch(this.editor.config.FormOperations.multiple_field_format)
717  {
718    case 'php':
719    {
720      mname += '[]';
721    }
722    break;
723
724    case 'unmodified':
725    {
726      // Leave as is.
727    }
728    break;
729
730    default:
731    {
732      throw("Unknown multiple field format " + this.editor.config.FormOperations.multiple_field_format);
733    }
734  }
735
736  if
737  (
738       (input.tagName.toLowerCase() == 'select' && input.multiple)
739    || (input.tagName.toLowerCase() == 'input'  && input.type.toLowerCase() == 'checkbox')
740  )
741  {
742    name = mname;
743  }
744
745  return name;
746};
747
748FormOperations.prototype.deformatName = function(input, name)
749{
750  if(this.editor.config.FormOperations.multiple_field_format == 'php')
751  {
752    name = name.replace(/\[\]$/, '');
753  }
754
755  return name;
756};
Note: See TracBrowser for help on using the repository browser.