[LON-CAPA-cvs] cvs: loncom /html/htmlarea dialog.js example-fully-loaded.html example-spell-checker.html example-table-operations.html example.html htmlarea.css htmlarea.js index.html license.txt popupdiv.js popupwin.js reference.html release-notes.html test.cgi /html/htmlarea/images ed_about.gif ed_align_center.gif ed_align_justify.gif ed_align_left.gif ed_align_right.gif ed_blank.gif ed_charmap.gif ed_color_bg.gif ed_color_fg.gif ed_copy.gif ed_custom.gif ed_cut.gif ed_delete.gif ed_format_bold.gif ed_format_italic.gif ed_format_strike.gif ed_format_sub.gif ed_format_sup.gif ed_format_underline.gif ed_help.gif ed_hr.gif ed_html.gif ed_image.gif ed_indent_less.gif ed_indent_more.gif ed_link.gif ed_list_bullet.gif ed_list_num.gif ed_paste.gif ed_redo.gif ed_show_border.gif ed_splitcel.gif ed_undo.gif fullscreen_maximize.gif fullscreen_minimize.gif insert_table.gif /html/htmlarea/lang b5.js da.js de.js en.js es.js fi.js fr.js gb.js it.js ja-euc.js ja-jis.js ja-sjis.js ja-utf8.js nb.js nl.js pl.js pt_br.js ro.js ru.js se.js vn.js /html/htmlarea/plugins/SpellChecker readme-tech.html spell-check-logic.cgi spell-check-style.css spell-check-ui.html spell-check-ui.js spell-checker.js /html/htmlarea/plugins/SpellChecker/img spell-check.gif /html/htmlarea/plugins/SpellChecker/lang en.js ro.js /html/htmlarea/plugins/TableOperations table-operations.js /html/htmlarea/plugins/TableOperations/img cell-delete.gif cell-insert-after.gif cell-insert-before.gif cell-merge.gif cell-prop.gif cell-split.gif col-delete.gif col-insert-after.gif col-insert-before.gif col-split.gif row-delete.gif row-insert-above.gif row-insert-under.gif row-prop.gif row-split.gif table-prop.gif /html/htmlarea/plugins/TableOperations/lang en.js fi.js ro.js /html/htmlarea/popups about.html blank.html custom2.html editor_help.html fullscreen.html insert_image.html insert_table.html old-fullscreen.html old_insert_image.html popup.js select_color.html /interface lonhtmlcommon.pm doc/loncapafiles loncapafiles.lpml

www lon-capa-cvs@mail.lon-capa.org
Wed, 18 Feb 2004 08:07:16 -0000


This is a MIME encoded message

--www1077091636
Content-Type: text/plain

www		Wed Feb 18 03:07:16 2004 EDT

  Added files:                 
    /loncom/html/htmlarea	dialog.js example-fully-loaded.html 
                         	example-spell-checker.html 
                         	example-table-operations.html example.html 
                         	htmlarea.css htmlarea.js index.html 
                         	license.txt popupdiv.js popupwin.js 
                         	reference.html release-notes.html test.cgi 
    /loncom/html/htmlarea/images	ed_about.gif ed_align_center.gif 
                                	ed_align_justify.gif ed_align_left.gif 
                                	ed_align_right.gif ed_blank.gif 
                                	ed_charmap.gif ed_color_bg.gif 
                                	ed_color_fg.gif ed_copy.gif 
                                	ed_custom.gif ed_cut.gif ed_delete.gif 
                                	ed_format_bold.gif 
                                	ed_format_italic.gif 
                                	ed_format_strike.gif ed_format_sub.gif 
                                	ed_format_sup.gif 
                                	ed_format_underline.gif ed_help.gif 
                                	ed_hr.gif ed_html.gif ed_image.gif 
                                	ed_indent_less.gif ed_indent_more.gif 
                                	ed_link.gif ed_list_bullet.gif 
                                	ed_list_num.gif ed_paste.gif 
                                	ed_redo.gif ed_show_border.gif 
                                	ed_splitcel.gif ed_undo.gif 
                                	fullscreen_maximize.gif 
                                	fullscreen_minimize.gif 
                                	insert_table.gif 
    /loncom/html/htmlarea/lang	b5.js da.js de.js en.js es.js fi.js 
                              	fr.js gb.js it.js ja-euc.js ja-jis.js 
                              	ja-sjis.js ja-utf8.js nb.js nl.js pl.js 
                              	pt_br.js ro.js ru.js se.js vn.js 
    /loncom/html/htmlarea/plugins/SpellChecker	readme-tech.html 
                                              	spell-check-logic.cgi 
                                              	spell-check-style.css 
                                              	spell-check-ui.html 
                                              	spell-check-ui.js 
                                              	spell-checker.js 
    /loncom/html/htmlarea/plugins/SpellChecker/img	spell-check.gif 
    /loncom/html/htmlarea/plugins/SpellChecker/lang	en.js ro.js 
    /loncom/html/htmlarea/plugins/TableOperations	table-operations.js 
    /loncom/html/htmlarea/plugins/TableOperations/img	cell-delete.gif 
                                                     	cell-insert-after.gif 
                                                     	cell-insert-before.gif 
                                                     	cell-merge.gif 
                                                     	cell-prop.gif 
                                                     	cell-split.gif 
                                                     	col-delete.gif 
                                                     	col-insert-after.gif 
                                                     	col-insert-before.gif 
                                                     	col-split.gif 
                                                     	row-delete.gif 
                                                     	row-insert-above.gif 
                                                     	row-insert-under.gif 
                                                     	row-prop.gif 
                                                     	row-split.gif 
                                                     	table-prop.gif 
    /loncom/html/htmlarea/plugins/TableOperations/lang	en.js fi.js 
                                                      	ro.js 
    /loncom/html/htmlarea/popups	about.html blank.html custom2.html 
                                	editor_help.html fullscreen.html 
                                	insert_image.html insert_table.html 
                                	old-fullscreen.html 
                                	old_insert_image.html popup.js 
                                	select_color.html 

  Modified files:              
    /doc/loncapafiles	loncapafiles.lpml 
    /loncom/interface	lonhtmlcommon.pm 
  Log:
  Install HTMLArea
  
  
--www1077091636
Content-Type: text/plain
Content-Disposition: attachment; filename="www-20040218030716.txt"

Index: doc/loncapafiles/loncapafiles.lpml
diff -u doc/loncapafiles/loncapafiles.lpml:1.336 doc/loncapafiles/loncapafiles.lpml:1.337
--- doc/loncapafiles/loncapafiles.lpml:1.336	Tue Feb 17 21:12:06 2004
+++ doc/loncapafiles/loncapafiles.lpml	Wed Feb 18 03:07:15 2004
@@ -2,7 +2,7 @@
  "http://lpml.sourceforge.net/DTD/lpml.dtd">
 <!-- loncapafiles.lpml -->
 
-<!-- $Id: loncapafiles.lpml,v 1.336 2004/02/18 02:12:06 www Exp $ -->
+<!-- $Id: loncapafiles.lpml,v 1.337 2004/02/18 08:07:15 www Exp $ -->
 
 <!--
 
@@ -461,6 +461,30 @@
 </directory>
 <directory dist='default'>
   <protectionlevel>modest_delete</protectionlevel>
+  <targetdir dist='default'>home/httpd/html/htmlarea</targetdir>
+  <categoryname>server readonly</categoryname>
+  <description>Web directory for HTMLArea</description>
+</directory>
+<directory dist='default'>
+  <protectionlevel>modest_delete</protectionlevel>
+  <targetdir dist='default'>home/httpd/html/htmlarea/images</targetdir>
+  <categoryname>server readonly</categoryname>
+  <description>Images for HTMLArea</description>
+</directory>
+<directory dist='default'>
+  <protectionlevel>modest_delete</protectionlevel>
+  <targetdir dist='default'>home/httpd/html/htmlarea/lang</targetdir>
+  <categoryname>server readonly</categoryname>
+  <description>Language files for HTMLArea</description>
+</directory>
+<directory dist='default'>
+  <protectionlevel>modest_delete</protectionlevel>
+  <targetdir dist='default'>home/httpd/html/htmlarea/popups</targetdir>
+  <categoryname>server readonly</categoryname>
+  <description>Popup windows for HTMLArea</description>
+</directory>
+<directory dist='default'>
+  <protectionlevel>modest_delete</protectionlevel>
   <targetdir dist='default'>home/httpd/html/adm/rat</targetdir>
   <categoryname>server readonly</categoryname>
   <description>home of the rat</description>
@@ -1058,6 +1082,131 @@
 Meta file for generic resource for score upload
 </description>
 </file>
+<fileglob>
+<glob>*.js</glob>
+<sourcedir>loncom/html/htmlarea/</sourcedir>
+<targetdir dist='default'>
+home/httpd/html/htmlarea/</targetdir>
+<categoryname>interface file</categoryname>
+<description>
+Files belonging to HTMLArea.
+</description>
+<filenames>
+dialog.js;
+htmlarea.js;
+popupdiv.js;
+popupwin.js;
+</filenames>
+</fileglob>
+<file>
+<source>loncom/html/htmlarea/htmlarea.css</source>
+<target dist='default'>home/httpd/html/htmlarea/htmlarea.css</target>
+<categoryname>interface file</categoryname>
+<description>
+Stylesheet for HTMLArea
+</description>
+</file>
+<fileglob>
+<glob>*.js</glob>
+<sourcedir>loncom/html/htmlarea/lang/</sourcedir>
+<targetdir dist='default'>
+home/httpd/html/htmlarea/lang/</targetdir>
+<categoryname>interface file</categoryname>
+<description>
+Files belonging to HTMLArea.
+</description>
+<filenames>
+b5.js;
+de.js;
+fi.js;
+it.js;
+nl.js;
+ro.js;
+vn.js;
+en.js;
+fr.js;
+ja-utf8.js;
+pl.js;
+ru.js;
+da.js;
+es.js;
+gb.js;
+nb.js;
+pt_br.js;
+se.js;
+</filenames>
+</fileglob>
+<fileglob>
+<glob>*.*</glob>
+<sourcedir>loncom/html/htmlarea/popups/</sourcedir>
+<targetdir dist='default'>
+home/httpd/html/htmlarea/popups/</targetdir>
+<categoryname>interface file</categoryname>
+<description>
+Files belonging to HTMLArea.
+</description>
+<filenames>
+about.html;
+insert_image.html;
+old_insert_image.html;
+blank.html;
+editor_help.html;
+insert_table.html;
+custom2.html;
+fullscreen.html;
+old-fullscreen.html;
+select_color.html;
+popup.js;
+</filenames>
+</fileglob>
+<fileglob>
+<glob>*.gif</glob>
+<sourcedir>loncom/html/htmlarea/images/</sourcedir>
+<targetdir dist='default'>
+home/httpd/html/htmlarea/images/</targetdir>
+<categoryname>interface file</categoryname>
+<description>
+Files belonging to HTMLArea.
+</description>
+<filenames>
+ed_delete.gif;
+ed_link.gif;
+ed_about.gif;
+ed_format_bold.gif;
+ed_list_bullet.gif;
+ed_align_center.gif;
+ed_format_italic.gif;
+ed_list_num.gif;
+ed_align_justify.gif;
+ed_format_strike.gif;
+ed_paste.gif;
+ed_align_left.gif;
+ed_format_sub.gif;
+ed_redo.gif;
+ed_align_right.gif;
+ed_format_sup.gif;
+ed_show_border.gif;
+ed_blank.gif;
+ed_format_underline.gif;
+ed_splitcel.gif;
+ed_charmap.gif;
+ed_help.gif;
+ed_undo.gif;
+ed_color_bg.gif;
+ed_hr.gif;
+fullscreen_maximize.gif;
+ed_color_fg.gif;
+ed_html.gif;
+fullscreen_minimize.gif;
+ed_copy.gif;
+ed_image.gif;
+insert_table.gif;
+ed_custom.gif;
+ed_indent_less.gif;
+ed_cut.gif;
+ed_indent_more.gif;
+</filenames>
+</fileglob>
 <fileglob>
 <glob>*.*</glob>
 <sourcedir>loncom/homework/templates/</sourcedir>
Index: loncom/interface/lonhtmlcommon.pm
diff -u loncom/interface/lonhtmlcommon.pm:1.51 loncom/interface/lonhtmlcommon.pm:1.52
--- loncom/interface/lonhtmlcommon.pm:1.51	Mon Feb 16 18:27:03 2004
+++ loncom/interface/lonhtmlcommon.pm	Wed Feb 18 03:07:16 2004
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common html routines
 #
-# $Id: lonhtmlcommon.pm,v 1.51 2004/02/16 23:27:03 albertel Exp $
+# $Id: lonhtmlcommon.pm,v 1.52 2004/02/18 08:07:16 www Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -803,6 +803,37 @@
     return $output.'</font></b></tt><br />';
 }
 
+# ------------------------------------------------- Output headers for HTMLArea
+
+sub htmlareaheaders {
+    unless (&htmlareabrowser()) { return ''; }
+    my $lang='en';
+    return (<<ENDHEADERS);
+<script type="text/javascript" src="/htmlarea/htmlarea.js"></script>
+<script type="text/javascript" src="/htmlarea/lang/$lang.js"></script>
+<script type="text/javascript" src="/htmlarea/dialog.js"></script>
+<style type="text/css">
+\@import url(/htmlarea/htmlarea.css);
+</style>
+ENDHEADERS
+}
+
+# ---------------------------------------------------------- Script to activate
+
+sub htmlareaactive {
+    unless (&htmlareabrowser()) { return ''; }
+    return (<<ENDSCRIPT);
+<script type="text/javascript" defer="1">
+    HTMLArea.replaceAll();
+</script>
+ENDSCRIPT
+}
+
+# ---------------------------------------- Browser capable of running HTMLArea?
+
+sub htmlareabrowser {
+    return 1;
+}
 
 1;
 

Index: loncom/html/htmlarea/dialog.js
+++ loncom/html/htmlarea/dialog.js
// Though "Dialog" looks like an object, it isn't really an object.  Instead
// it's just namespace for protecting global symbols.

function Dialog(url, action, init) {
	if (typeof init == "undefined") {
		init = window;	// pass this window object by default
	}
	if (document.all) {	// here we hope that Mozilla will never support document.all
		var value =
			showModalDialog(url, init,
//			window.open(url, '_blank',
					"resizable: no; help: no; status: no; scroll: no");
		if (action) {
			action(value);
		}
	} else {
		return Dialog._geckoOpenModal(url, action, init);
	}
};

Dialog._parentEvent = function(ev) {
	if (Dialog._modal && !Dialog._modal.closed) {
		Dialog._modal.focus();
		// we get here in Mozilla only, anyway, so we can safely use
		// the DOM version.
		ev.preventDefault();
		ev.stopPropagation();
	}
};

// should be a function, the return handler of the currently opened dialog.
Dialog._return = null;

// constant, the currently opened dialog
Dialog._modal = null;

// the dialog will read it's args from this variable
Dialog._arguments = null;

Dialog._geckoOpenModal = function(url, action, init) {
	var dlg = window.open(url, "ha_dialog",
			      "toolbar=no,menubar=no,personalbar=no,width=10,height=10," +
			      "scrollbars=no,resizable=no");
	Dialog._modal = dlg;
	Dialog._arguments = init;

	// capture some window's events
	function capwin(w) {
		w.addEventListener("click", Dialog._parentEvent, true);
		w.addEventListener("mousedown", Dialog._parentEvent, true);
		w.addEventListener("focus", Dialog._parentEvent, true);
	};
	// release the captured events
	function relwin(w) {
		w.removeEventListener("focus", Dialog._parentEvent, true);
		w.removeEventListener("mousedown", Dialog._parentEvent, true);
		w.removeEventListener("click", Dialog._parentEvent, true);
	};
	capwin(window);
	// capture other frames
	for (var i = 0; i < window.frames.length; capwin(window.frames[i++]));
	// make up a function to be called when the Dialog ends.
	Dialog._return = function (val) {
		if (val && action) {
			action(val);
		}
		relwin(window);
		// capture other frames
		for (var i = 0; i < window.frames.length; relwin(window.frames[i++]));
		Dialog._modal = null;
	};
};

Index: loncom/html/htmlarea/example-fully-loaded.html
+++ loncom/html/htmlarea/example-fully-loaded.html
<html>
<head>
<title>Example of HTMLArea 3.0</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<!-- load the main HTMLArea files -->
<script type="text/javascript" src="htmlarea.js"></script>
<script type="text/javascript" src="lang/en.js"></script>
<script type="text/javascript" src="dialog.js"></script>
<!-- <script type="text/javascript" src="popupdiv.js"></script> -->
<script type="text/javascript" src="popupwin.js"></script>

<!-- load the plugins -->
<script type="text/javascript">
      // WARNING: using this interface to load plugin
      // will _NOT_ work if plugins do not have the language
      // loaded by HTMLArea.

      // In other words, this function generates SCRIPT tags
      // that load the plugin and the language file, based on the
      // global variable HTMLArea.I18N.lang (defined in the lang file,
      // in our case "lang/en.js" loaded above).

      // If this lang file is not found the plugin will fail to
      // load correctly and nothing will work.

      HTMLArea.loadPlugin("TableOperations");
      HTMLArea.loadPlugin("SpellChecker");
</script>

<style type="text/css">
@import url(htmlarea.css);

html, body {
  font-family: Verdana,sans-serif;
  background-color: #fea;
  color: #000;
}
a:link, a:visited { color: #00f; }
a:hover { color: #048; }
a:active { color: #f00; }

textarea { background-color: #fff; border: 1px solid 00f; }
</style>

<script type="text/javascript">
var editor = null;
function initEditor() {
  // create an editor for the "ta" textbox
  editor = new HTMLArea("ta");

  // register the SpellChecker plugin
  editor.registerPlugin("TableOperations");

  // register the SpellChecker plugin
  editor.registerPlugin("SpellChecker");

  editor.generate();
  return false;
}

function insertHTML() {
  var html = prompt("Enter some HTML code here");
  if (html) {
    editor.insertHTML(html);
  }
}
function highlight() {
  editor.surroundHTML('<span style="background-color: yellow">', '</span>');
}
</script>

</head>

<!-- use <body onload="HTMLArea.replaceAll()" if you don't care about
     customizing the editor.  It's the easiest way! :) -->
<body onload="initEditor()">

<h1>HTMLArea 3.0</h1>

<p>A replacement for <code>TEXTAREA</code> elements.  &copy; <a
href="http://interactivetools.com">InteractiveTools.com</a>, 2003.</p>

<p>Plugins:
      <tt>TableOperations<tt> |
      <tt>SpellChecker</tt>
</p>

<form action="test.cgi" method="post" id="edit" name="edit">

<textarea id="ta" name="ta" style="width:100%" rows="24" cols="80">

      <h1>This is the fully loaded HTMLArea ;-)</h1>

      <p>It loads all the plugins that have been developed so far.</p>

      <table style="background-color: #99f; border: 1px dashed #08f; width:
        60%; border-collapse: collapse;" align="center">
        <tr style="background-color: #fdd">
          <td style="font-weight: bold; border: 1px solid #000;">Plugin</td>
          <td style="font-weight: bold; border: 1px solid #000;">Sponsor</td>
        </tr>

        <tr>
          <td style="font-family: monospace">TableOperations</td>
          <td><a href="http://bloki.com">Zapatec, Inc.</a></td>
        </tr>

        <tr>
          <td style="font-family: monospace">SpellChecker</td>
          <td><a href="http://americanbible.org">Amerian Bible Society</a></td>
        </tr>
      </table>

</textarea>

<p />

<input type="submit" name="ok" value="  submit  " />
<input type="button" name="ins" value="  insert html  " onclick="return insertHTML();" />
<input type="button" name="hil" value="  highlight text  " onclick="return highlight();" />

<a href="javascript:mySubmit()">submit</a>

<script type="text/javascript">
function mySubmit() {
// document.edit.save.value = "yes";
document.edit.onsubmit(); // workaround browser bugs.
document.edit.submit();
};
</script>

</form>

</body>
</html>

Index: loncom/html/htmlarea/example-spell-checker.html
+++ loncom/html/htmlarea/example-spell-checker.html
<html>
<head>
<title>Example of HTMLArea 3.0</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<!-- load the main HTMLArea files -->
<script type="text/javascript" src="htmlarea.js"></script>
<script type="text/javascript" src="lang/en.js"></script>
<script type="text/javascript" src="dialog.js"></script>
<!-- <script type="text/javascript" src="popupdiv.js"></script> -->
<script type="text/javascript" src="popupwin.js"></script>

<!-- load the SpellChecker plugin files -->
<script type="text/javascript" src="plugins/SpellChecker/spell-checker.js"></script>
<script type="text/javascript" src="plugins/SpellChecker/lang/en.js"></script>

<style type="text/css">
@import url(htmlarea.css);

html, body {
  font-family: Verdana,sans-serif;
  background-color: #fea;
  color: #000;
}
a:link, a:visited { color: #00f; }
a:hover { color: #048; }
a:active { color: #f00; }

textarea { background-color: #fff; border: 1px solid 00f; }
</style>

<script type="text/javascript">
var editor = null;
function initEditor() {
  // create an editor for the "ta" textbox
  editor = new HTMLArea("ta");

  // register the SpellChecker plugin
  editor.registerPlugin("SpellChecker");

  editor.generate();
  return false;
}

function insertHTML() {
  var html = prompt("Enter some HTML code here");
  if (html) {
    editor.insertHTML(html);
  }
}
function highlight() {
  editor.surroundHTML('<span style="background-color: yellow">', '</span>');
}
</script>

</head>

<!-- use <body onload="HTMLArea.replaceAll()" if you don't care about
     customizing the editor.  It's the easiest way! :) -->
<body onload="initEditor()">

<h1>HTMLArea 3.0</h1>

<p>A replacement for <code>TEXTAREA</code> elements.  &copy; <a
href="http://interactivetools.com">InteractiveTools.com</a>, 2003.</p>

<p>Plugins:
      <tt>SpellChecker</tt> (sponsored by <a
        href="http://americanbible.org">American Bible Society</a>).
</p>

<form action="test.cgi" method="post" id="edit" name="edit">

<textarea id="ta" name="ta" style="width:100%" rows="24" cols="80">

<h1>The <tt>SpellChecker</tt> plugin</h1>

      <p>This file deminstrates the <tt>SpellChecker</tt> plugin of
      HTMLArea.  To inwoke the spell checkert you need to press the
      <em>spell-check</em> buton in the toolbar.</p>

      <p>The spell-checker uses a serverside script written in Perl.  The
        Perl script calls <a href="http://aspell.net">aspell</a> for any
        word in the text and reports wordz that aren't found in the
        dyctionari.</p>

      <p>The document that yu are reading now <b>intentionaly</b> containes
        some errorz, so that you have something to corect ;-)</p>

      <p>Credits for the <tt>SpellChecker</tt> plugin go to:</p>

      <ul>

        <li><a href="http://aspell.net">Aspell</a> -- spell
          checker</li>

        <li>The <a href="http://perl.org">Perl</a> programming language</li>

        <li><tt><a
              href="http://cpan.org/modules/by-module/Text/Text-Aspell-0.02.readme">Text::Aspell</a></tt>
          -- Perl interface to Aspell</li>

        <li><a href="http://americanbible.org">American Bible Society</a> --
          for sponsoring the <tt>SpellChecker</tt> plugin for
          <tt>HTMLArea</tt></li>

        <li><a href="http://students.infoiasi.ro/~mishoo/">Your humble servant</a> for
          implementing it ;-)</li>

      </ul>

</textarea>

<p />

<input type="submit" name="ok" value="  submit  " />
<input type="button" name="ins" value="  insert html  " onclick="return insertHTML();" />
<input type="button" name="hil" value="  highlight text  " onclick="return highlight();" />

<a href="javascript:mySubmit()">submit</a>

<script type="text/javascript">
function mySubmit() {
// document.edit.save.value = "yes";
document.edit.onsubmit(); // workaround browser bugs.
document.edit.submit();
};
</script>

</form>

</body>
</html>

Index: loncom/html/htmlarea/example-table-operations.html
+++ loncom/html/htmlarea/example-table-operations.html
<html>
<head>
<title>Example of HTMLArea 3.0</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<!-- load the main HTMLArea files -->
<script type="text/javascript" src="htmlarea.js"></script>
<script type="text/javascript" src="lang/en.js"></script>
<script type="text/javascript" src="dialog.js"></script>
<!-- <script type="text/javascript" src="popupdiv.js"></script> -->
<script type="text/javascript" src="popupwin.js"></script>

<!-- load the TableOperations plugin files -->
<script type="text/javascript" src="plugins/TableOperations/table-operations.js"></script>
<script type="text/javascript" src="plugins/TableOperations/lang/en.js"></script>

<style type="text/css">
@import url(htmlarea.css);

html, body {
  font-family: Verdana,sans-serif;
  background-color: #fea;
  color: #000;
}
a:link, a:visited { color: #00f; }
a:hover { color: #048; }
a:active { color: #f00; }

textarea { background-color: #fff; border: 1px solid 00f; }
</style>

<script type="text/javascript">
var editor = null;
function initEditor() {
  // create an editor for the "ta" textbox
  editor = new HTMLArea("ta");

  // register the TableOperations plugin with our editor
  editor.registerPlugin("TableOperations");

  editor.generate();
  return false;
}

function insertHTML() {
  var html = prompt("Enter some HTML code here");
  if (html) {
    editor.insertHTML(html);
  }
}
function highlight() {
  editor.surroundHTML('<span style="background-color: yellow">', '</span>');
}
</script>

</head>

<!-- use <body onload="HTMLArea.replaceAll()" if you don't care about
     customizing the editor.  It's the easiest way! :) -->
<body onload="initEditor()">

<h1>HTMLArea 3.0</h1>

<p>A replacement for <code>TEXTAREA</code> elements.  &copy; <a
href="http://interactivetools.com">InteractiveTools.com</a>, 2003.</p>

<p>Page that demonstrates the additional features of the
<tt>TableOperations</tt> plugin (sponsored by <a
href="http://www.bloki.com">Zapatec Inc.</a>).</p>

<form action="test.cgi" method="post" id="edit" name="edit">

<textarea id="ta" name="ta" style="width:100%" rows="24" cols="80">

<h1>Plugin: <tt>TableOperations</tt></h1>

<p>This page exemplifies the table operations toolbar, provided by the
TableOperations plugin.</p>

<p>Following there is a table.</p>

<table border="1" style="border: 2px solid rgb(255, 0, 0); width: 80%; background-image: none; border-collapse: collapse; color: rgb(153, 102, 0); background-color: rgb(255, 255, 51);" align="center" cellspacing="2" cellpadding="1" summary="">
  <caption>This <span style="font-weight: bold;">is</span> a table</caption>
  <tbody>
  <tr style="border-style: none; background-image: none; background-color: rgb(255, 255, 153);" char="." align="left" valign="middle"> <td>1.1</td> <td>1.2</td> <td>1.3</td> <td>1.4</td> </tr>
  <tr> <td>2.1</td> <td style="border: 1px solid rgb(51, 51, 255); background-image: none; background-color: rgb(102, 255, 255); color: rgb(0, 0, 51);" char="." align="left" valign="middle">2.2</td> <td>2.3</td> <td>2.4</td> </tr>
  <tr> <td>3.1</td> <td>3.2</td> <td style="border: 2px dashed rgb(51, 204, 102); background-image: none; background-color: rgb(102, 255, 153); color: rgb(0, 51, 0);" char="." align="left" valign="middle">3.3</td> <td>3.4</td> </tr>
  <tr> <td style="background-color: rgb(255, 204, 51);">4.1</td> <td style="background-color: rgb(255, 204, 51);">4.2</td> <td style="background-color: rgb(255, 204, 51);">4.3</td> <td style="background-color: rgb(255, 204, 51);">4.4</td> </tr>
  </tbody>
</table>

<p>Text after the table</p>

</textarea>

<p />

<input type="submit" name="ok" value="  submit  " />
<input type="button" name="ins" value="  insert html  " onclick="return insertHTML();" />
<input type="button" name="hil" value="  highlight text  " onclick="return highlight();" />

<a href="javascript:mySubmit()">submit</a>

<script type="text/javascript">
function mySubmit() {
// document.edit.save.value = "yes";
document.edit.onsubmit(); // workaround browser bugs.
document.edit.submit();
};
</script>

</form>

</body>
</html>

Index: loncom/html/htmlarea/example.html
+++ loncom/html/htmlarea/example.html
<html>
<head>
<title>Example of HTMLArea 3.0</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script type="text/javascript" src="htmlarea.js"></script>
<script type="text/javascript" src="lang/en.js"></script>
<script type="text/javascript" src="dialog.js"></script>

<style type="text/css">
@import url(htmlarea.css);

html, body {
  font-family: Verdana,sans-serif;
  background-color: #fea;
  color: #000;
}
a:link, a:visited { color: #00f; }
a:hover { color: #048; }
a:active { color: #f00; }

textarea { background-color: #fff; border: 1px solid 00f; }
</style>

<script type="text/javascript">
var editor = null;
function initEditor() {
  editor = new HTMLArea("ta");

  // comment the following two lines to see how customization works
  editor.generate();
  return false;

  var cfg = editor.config; // this is the default configuration
  cfg.registerButton({
    id        : "my-hilite",
    tooltip   : "Highlight text",
    image     : "ed_custom.gif",
    textMode  : false,
    action    : function(editor) {
                  editor.surroundHTML("<span class=\"hilite\">", "</span>");
                },
    context   : 'table'
  });

  cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar

  // BEGIN: code that adds a custom button
  // uncomment it to test
  var cfg = editor.config; // this is the default configuration
  /*
  cfg.registerButton({
    id        : "my-hilite",
    tooltip   : "Highlight text",
    image     : "ed_custom.gif",
    textMode  : false,
    action    : function(editor) {
                  editor.surroundHTML("<span class=\"hilite\">", "</span>");
                }
  });
  */

function clickHandler(editor, buttonId) {
  switch (buttonId) {
    case "my-toc":
      editor.insertHTML("<h1>Table Of Contents</h1>");
      break;
    case "my-date":
      editor.insertHTML((new Date()).toString());
      break;
    case "my-bold":
      editor.execCommand("bold");
      editor.execCommand("italic");
      break;
    case "my-hilite":
      editor.surroundHTML("<span class=\"hilite\">", "</span>");
      break;
  }
};
cfg.registerButton("my-toc",  "Insert TOC", "ed_custom.gif", false, clickHandler);
cfg.registerButton("my-date", "Insert date/time", "ed_custom.gif", false, clickHandler);
cfg.registerButton("my-bold", "Toggle bold/italic", "ed_custom.gif", false, clickHandler);
cfg.registerButton("my-hilite", "Hilite selection", "ed_custom.gif", false, clickHandler);

cfg.registerButton("my-sample", "Class: sample", "ed_custom.gif", false,
  function(editor) {
    if (HTMLArea.is_ie) {
      editor.insertHTML("<span class=\"sample\">&nbsp;&nbsp;</span>");
      var r = editor._doc.selection.createRange();
      r.move("character", -2);
      r.moveEnd("character", 2);
      r.select();
    } else { // Gecko/W3C compliant
      var n = editor._doc.createElement("span");
      n.className = "sample";
      editor.insertNodeAtSelection(n);
      var sel = editor._iframe.contentWindow.getSelection();
      sel.removeAllRanges();
      var r = editor._doc.createRange();
      r.setStart(n, 0);
      r.setEnd(n, 0);
      sel.addRange(r);
    }
  }
);


  /*
  cfg.registerButton("my-hilite", "Highlight text", "ed_custom.gif", false,
    function(editor) {
      editor.surroundHTML('<span class="hilite">', '</span>');
    }
  );
  */
  cfg.pageStyle = "body { background-color: #efd; } .hilite { background-color: yellow; } "+
                  ".sample { color: green; font-family: monospace; }";
  cfg.toolbar.push(["linebreak", "my-toc", "my-date", "my-bold", "my-hilite", "my-sample"]); // add the new button to the toolbar
  // END: code that adds a custom button

  editor.generate();
}
function insertHTML() {
  var html = prompt("Enter some HTML code here");
  if (html) {
    editor.insertHTML(html);
  }
}
function highlight() {
  editor.surroundHTML('<span style="background-color: yellow">', '</span>');
}
</script>

</head>

<!-- use <body onload="HTMLArea.replaceAll()" if you don't care about
     customizing the editor.  It's the easiest way! :) -->
<body onload="initEditor()">

<h1>HTMLArea 3.0</h1>

<p>A replacement for <code>TEXTAREA</code> elements.  &copy; <a
href="http://interactivetools.com">InteractiveTools.com</a>, 2003.</p>

<form action="test.cgi" method="post" id="edit" name="edit">

<textarea id="ta" name="ta" style="width:100%" rows="20" cols="80">
  &lt;p&gt;Here is some sample text: &lt;b&gt;bold&lt;/b&gt;, &lt;i&gt;italic&lt;/i&gt;, &lt;u&gt;underline&lt;/u&gt;. &lt;/p&gt;
  &lt;p align=center&gt;Different fonts, sizes and colors (all in bold):&lt;/p&gt;
  &lt;p&gt;&lt;b&gt;
   &lt;font face="arial"           size="7" color="#000066"&gt;arial&lt;/font&gt;,
   &lt;font face="courier new"     size="6" color="#006600"&gt;courier new&lt;/font&gt;,
   &lt;font face="georgia"         size="5" color="#006666"&gt;georgia&lt;/font&gt;,
   &lt;font face="tahoma"          size="4" color="#660000"&gt;tahoma&lt;/font&gt;,
   &lt;font face="times new roman" size="3" color="#660066"&gt;times new roman&lt;/font&gt;,
   &lt;font face="verdana"         size="2" color="#666600"&gt;verdana&lt;/font&gt;,
   &lt;font face="tahoma"          size="1" color="#666666"&gt;tahoma&lt;/font&gt;
  &lt;/b&gt;&lt;/p&gt;
  &lt;p&gt;Click on &lt;a href="http://www.interactivetools.com/"&gt;this link&lt;/a&gt; and then on the link button to the details ... OR ... select some text and click link to create a &lt;b&gt;new&lt;/b&gt; link.&lt;/p&gt;
</textarea>

<p />

<input type="submit" name="ok" value="  submit  " />
<input type="button" name="ins" value="  insert html  " onclick="return insertHTML();" />
<input type="button" name="hil" value="  highlight text  " onclick="return highlight();" />

<a href="javascript:mySubmit()">submit</a>

<script type="text/javascript">
function mySubmit() {
// document.edit.save.value = "yes";
document.edit.onsubmit(); // workaround browser bugs.
document.edit.submit();
};
</script>

</form>

</body>
</html>

Index: loncom/html/htmlarea/htmlarea.css
+++ loncom/html/htmlarea/htmlarea.css
.htmlarea { background: #fff; }

.htmlarea .toolbar {
  cursor: default;
  background: ButtonFace;
  padding: 1px 1px 2px 1px;
  border: 1px solid;
  border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
}
.htmlarea .toolbar table { font-family: tahoma,verdana,sans-serif; font-size: 11px; }
.htmlarea .toolbar img { border: none; }
.htmlarea .toolbar .label { padding: 0px 3px; }

.htmlarea .toolbar .button {
  background: ButtonFace;
  color: ButtonText;
  border: 1px solid ButtonFace;
  padding: 1px;
  margin: 0px;
}
.htmlarea .toolbar .buttonHover {
  border: 1px solid;
  border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
}
.htmlarea .toolbar .buttonActive, .htmlarea .toolbar .buttonPressed {
  padding: 2px 0px 0px 2px;
  border: 1px solid;
  border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
}
.htmlarea .toolbar .buttonPressed {
  background: ButtonHighlight;
}
.htmlarea .toolbar .indicator {
  padding: 0px 3px;
  overflow: hidden;
  width: 20px;
  text-align: center;
  cursor: default;
  border: 1px solid ButtonShadow;
}

.htmlarea .toolbar .buttonDisabled { background-color: #aaa; }

.htmlarea .toolbar .buttonDisabled img {
  filter: alpha(opacity = 25);
  -moz-opacity: 25%;
}

.htmlarea .toolbar .separator {
  position: relative;
  margin: 3px;
  border-left: 1px solid ButtonShadow;
  border-right: 1px solid ButtonHighlight;
  width: 0px;
  height: 16px;
  padding: 0px;
}

.htmlarea .toolbar .space { width: 5px; }

.htmlarea .toolbar select { font: 11px Tahoma,Verdana,sans-serif; }

.htmlarea .toolbar select,
.htmlarea .toolbar select:hover,
.htmlarea .toolbar select:active { background: FieldFace; color: ButtonText; }

.htmlarea .statusBar {
  border: 1px solid;
  border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
  padding: 2px 4px;
  background-color: ButtonFace;
  color: ButtonText;
  font: 11px Tahoma,Verdana,sans-serif;
}

.htmlarea .statusBar .statusBarTree a {
  padding: 2px 5px;
  color: #00f;
}

.htmlarea .statusBar .statusBarTree a:visited { color: #00f; }
.htmlarea .statusBar .statusBarTree a:hover {
  background-color: Highlight;
  color: HighlightText;
  padding: 1px 4px;
  border: 1px solid HighlightText;
}


/* Hidden DIV popup dialogs (PopupDiv) */

.dialog {
  color: ButtonText;
  background: ButtonFace;
}

.dialog .content { padding: 2px; }

.dialog, .dialog button, .dialog input, .dialog select, .dialog textarea, .dialog table {
  font: 11px Tahoma,Verdana,sans-serif;
}

.dialog table { border-collapse: collapse; }

.dialog .title {
  background: #008;
  color: #ff8;
  border-bottom: 1px solid #000;
  padding: 1px 0px 2px 5px;
  font-size: 12px;
  font-weight: bold;
  cursor: default;
}

.dialog .title .button {
  float: right;
  border: 1px solid #66a;
  padding: 0px 1px 0px 2px;
  margin-right: 1px;
  color: #fff;
  text-align: center;
}

.dialog .title .button-hilite { border-color: #88f; background: #44c; }

.dialog button {
  width: 5em;
  padding: 0px;
}

.dialog .buttonColor {
  padding: 1px;
  cursor: default;
  border: 1px solid;
  border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
}

.dialog .buttonColor-hilite {
  border-color: #000;
}

.dialog .buttonColor .chooser, .dialog .buttonColor .nocolor {
  height: 0.6em;
  border: 1px solid;
  padding: 0px 1em;
  border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
}

.dialog .buttonColor .nocolor { padding: 0px; }
.dialog .buttonColor .nocolor-hilite { background-color: #fff; color: #f00; }

.dialog .label { text-align: right; width: 6em; }
.dialog .value input { width: 100%; }
.dialog .buttons { text-align: right; padding: 2px 4px 0px 4px; }

.dialog legend { font-weight: bold; }
.dialog fieldset table { margin: 2px 0px; }

.popupdiv {
  border: 2px solid;
  border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
}

.popupwin {
  padding: 0px;
  margin: 0px;
}

.popupwin .title {
  background: #fff;
  color: #000;
  font-weight: bold;
  font-size: 120%;
  padding: 3px 10px;
  margin-bottom: 10px;
  border-bottom: 1px solid black;
  letter-spacing: 2px;
}

form { margin: 0px; border: none; }

Index: loncom/html/htmlarea/htmlarea.js
+++ loncom/html/htmlarea/htmlarea.js
//
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
// This copyright notice MUST stay intact for use (see license.txt).
//
// A free WYSIWYG editor replacement for <textarea> fields.
// For full source code and docs, visit http://www.interactivetools.com/
//
// Version 3.0 developed by Mihai Bazon for InteractiveTools.
//	     http://students.infoiasi.ro/~mishoo
//
// $Id: htmlarea.js,v 1.1 2004/02/18 08:07:15 www Exp $

// Creates a new HTMLArea object.  Tries to replace the textarea with the given
// ID with it.
function HTMLArea(textarea, config) {
	if (HTMLArea.checkSupportedBrowser()) {
		if (typeof config == "undefined") {
			this.config = new HTMLArea.Config();
		} else {
			this.config = config;
		}
		this._htmlArea = null;
		this._textArea = textarea;
		this._editMode = "wysiwyg";
		this.plugins = {};
		this._timerToolbar = null;
		this._mdoc = document; // cache the document, we need it in plugins
	}
};

HTMLArea.Config = function () {
	this.version = "3.0";

	this.width = "auto";
	this.height = "auto";

	// enable creation of a status bar?
	this.statusBar = true;

	// the next parameter specifies whether the toolbar should be included
	// in the size or not.
	this.sizeIncludesToolbar = true;

	// style included in the iframe document
	this.pageStyle = "body { background-color: #fff; font-family: verdana,sans-serif; }";
	if (typeof _editor_url != "undefined") {
		this.editorURL = _editor_url;
	} else {
		this.editorURL = "";
	}

	// URL-s
	this.imgURL = "images/";
	this.popupURL = "popups/";

	// configuration for plugins
	this.plugins = {};

	/** CUSTOMIZING THE TOOLBAR
	 * -------------------------
	 *
	 * It is recommended that you customize the toolbar contents in an
	 * external file (i.e. the one calling HTMLArea) and leave this one
	 * unchanged.  That's because when we (InteractiveTools.com) release a
	 * new official version, it's less likely that you will have problems
	 * upgrading HTMLArea.
	 */
	this.toolbar = [
		[ "fontname", "space",
		  "fontsize", "space",
		  "formatblock", "space",
		  "bold", "italic", "underline", "separator",
		  "strikethrough", "subscript", "superscript", "separator",
		  "copy", "cut", "paste", "space", "undo", "redo" ],
		
		[ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator",
		  "insertorderedlist", "insertunorderedlist", "outdent", "indent", "separator",
		  "forecolor", "hilitecolor", "textindicator", "separator",
		  "inserthorizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator",
		  "popupeditor", "separator", "showhelp", "about" ]
		];

	this.fontname = {
		"Arial":	   'arial,helvetica,sans-serif',
		"Courier New":	   'courier new,courier,monospace',
		"Georgia":	   'georgia,times new roman,times,serif',
		"Tahoma":	   'tahoma,arial,helvetica,sans-serif',
		"Times New Roman": 'times new roman,times,serif',
		"Verdana":	   'verdana,arial,helvetica,sans-serif',
		"impact":	   'impact',
		"WingDings":	   'wingdings'
	};

	this.fontsize = {
		"1 (8 pt)":  "1",
		"2 (10 pt)": "2",
		"3 (12 pt)": "3",
		"4 (14 pt)": "4",
		"5 (18 pt)": "5",
		"6 (24 pt)": "6",
		"7 (36 pt)": "7"
	};

	this.formatblock = {
		"Heading 1": "h1",
		"Heading 2": "h2",
		"Heading 3": "h3",
		"Heading 4": "h4",
		"Heading 5": "h5",
		"Heading 6": "h6",
		"Normal": "p",
		"Address": "address",
		"Formatted": "pre"
	};

	this.customSelects = {};

	function cut_copy_paste(e, cmd, obj) {
		try {
			e.execCommand(cmd);
		} catch (e) {
			if (HTMLArea.is_gecko) {
				alert("Some revisions of Mozilla/Gecko do not support programatic " +
				      "access to cut/copy/paste functions, for security reasons.  " +
				      "Your browser is one of them.  Please use the standard key combinations:\n" +
				      "CTRL-X for cut, CTRL-C for copy, CTRL-V for paste.");
				obj.element.style.display = "none";
			}
		}
	};

	// ADDING CUSTOM BUTTONS: please read below!
	// format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]"
	//    - ID: unique ID for the button.  If the button calls document.execCommand
	//	    it's wise to give it the same name as the called command.
	//    - ACTION: function that gets called when the button is clicked.
	//              it has the following prototype:
	//                 function(editor, buttonName)
	//              - editor is the HTMLArea object that triggered the call
	//              - buttonName is the ID of the clicked button
	//              These 2 parameters makes it possible for you to use the same
	//              handler for more HTMLArea objects or for more different buttons.
	//    - ToolTip: default tooltip, for cases when it is not defined in the -lang- file (HTMLArea.I18N)
	//    - Icon: path to an icon image file for the button (TODO: use one image for all buttons!)
	//    - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time.
	this.btnList = {
		bold: [ "Bold", "images/ed_format_bold.gif", false, function(e) {e.execCommand("bold");} ],
		italic: [ "Italic", "images/ed_format_italic.gif", false, function(e) {e.execCommand("italic");} ],
		underline: [ "Underline", "images/ed_format_underline.gif", false, function(e) {e.execCommand("underline");} ],
		strikethrough: [ "Strikethrough", "images/ed_format_strike.gif", false, function(e) {e.execCommand("strikethrough");} ],
		subscript: [ "Subscript", "images/ed_format_sub.gif", false, function(e) {e.execCommand("subscript");} ],
		superscript: [ "Superscript", "images/ed_format_sup.gif", false, function(e) {e.execCommand("superscript");} ],
		justifyleft: [ "Justify Left", "images/ed_align_left.gif", false, function(e) {e.execCommand("justifyleft");} ],
		justifycenter: [ "Justify Center", "images/ed_align_center.gif", false, function(e) {e.execCommand("justifycenter");} ],
		justifyright: [ "Justify Right", "images/ed_align_right.gif", false, function(e) {e.execCommand("justifyright");} ],
		justifyfull: [ "Justify Full", "images/ed_align_justify.gif", false, function(e) {e.execCommand("justifyfull");} ],
		insertorderedlist: [ "Ordered List", "images/ed_list_num.gif", false, function(e) {e.execCommand("insertorderedlist");} ],
		insertunorderedlist: [ "Bulleted List", "images/ed_list_bullet.gif", false, function(e) {e.execCommand("insertunorderedlist");} ],
		outdent: [ "Decrease Indent", "images/ed_indent_less.gif", false, function(e) {e.execCommand("outdent");} ],
		indent: [ "Increase Indent", "images/ed_indent_more.gif", false, function(e) {e.execCommand("indent");} ],
		forecolor: [ "Font Color", "images/ed_color_fg.gif", false, function(e) {e.execCommand("forecolor");} ],
		hilitecolor: [ "Background Color", "images/ed_color_bg.gif", false, function(e) {e.execCommand("hilitecolor");} ],
		inserthorizontalrule: [ "Horizontal Rule", "images/ed_hr.gif", false, function(e) {e.execCommand("inserthorizontalrule");} ],
		createlink: [ "Insert Web Link", "images/ed_link.gif", false, function(e) {e.execCommand("createlink", true);} ],
		insertimage: [ "Insert Image", "images/ed_image.gif", false, function(e) {e.execCommand("insertimage");} ],
		inserttable: [ "Insert Table", "images/insert_table.gif", false, function(e) {e.execCommand("inserttable");} ],
		htmlmode: [ "Toggle HTML Source", "images/ed_html.gif", true, function(e) {e.execCommand("htmlmode");} ],
		popupeditor: [ "Enlarge Editor", "images/fullscreen_maximize.gif", true, function(e) {e.execCommand("popupeditor");} ],
		about: [ "About this editor", "images/ed_about.gif", true, function(e) {e.execCommand("about");} ],
		showhelp: [ "Help using editor", "images/ed_help.gif", true, function(e) {e.execCommand("showhelp");} ],
		undo: [ "Undoes your last action", "images/ed_undo.gif", false, function(e) {e.execCommand("undo");} ],
		redo: [ "Redoes your last action", "images/ed_redo.gif", false, function(e) {e.execCommand("redo");} ],
		cut: [ "Cut selection", "images/ed_cut.gif", false, cut_copy_paste ],
		copy: [ "Copy selection", "images/ed_copy.gif", false, cut_copy_paste ],
		paste: [ "Paste from clipboard", "images/ed_paste.gif", false, cut_copy_paste ]
	};
	/* ADDING CUSTOM BUTTONS
	 * ---------------------
	 *
	 * It is recommended that you add the custom buttons in an external
	 * file and leave this one unchanged.  That's because when we
	 * (InteractiveTools.com) release a new official version, it's less
	 * likely that you will have problems upgrading HTMLArea.
	 *
	 * Example on how to add a custom button when you construct the HTMLArea:
	 *
	 *   var editor = new HTMLArea("your_text_area_id");
	 *   var cfg = editor.config; // this is the default configuration
	 *   cfg.btnList["my-hilite"] =
	 *	[ function(editor) { editor.surroundHTML('<span style="background:yellow">', '</span>'); }, // action
	 *	  "Highlight selection", // tooltip
	 *	  "my_hilite.gif", // image
	 *	  false // disabled in text mode
	 *	];
	 *   cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar
	 *
	 * An alternate (also more convenient and recommended) way to
	 * accomplish this is to use the registerButton function below.
	 */
	// initialize tooltips from the I18N module
	for (var i in this.btnList) {
		var btn = this.btnList[i];
		if (typeof HTMLArea.I18N.tooltips[i] != "undefined") {
			btn[0] = HTMLArea.I18N.tooltips[i];
		}
	}
};

/** Helper function: register a new button with the configuration.  It can be
 * called with all 5 arguments, or with only one (first one).  When called with
 * only one argument it must be an object with the following properties: id,
 * tooltip, image, textMode, action.  Examples:
 *
 * 1. config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...});
 * 2. config.registerButton({
 *      id       : "my-hilite",      // the ID of your button
 *      tooltip  : "Hilite text",    // the tooltip
 *      image    : "my-hilite.gif",  // image to be displayed in the toolbar
 *      textMode : false,            // disabled in text mode
 *      action   : function(editor) { // called when the button is clicked
 *                   editor.surroundHTML('<span class="hilite">', '</span>');
 *                 },
 *      context  : "p"               // will be disabled if outside a <p> element
 *    });
 */
HTMLArea.Config.prototype.registerButton = function(id, tooltip, image, textMode, action, context) {
	var the_id;
	if (typeof id == "string") {
		the_id = id;
	} else if (typeof id == "object") {
		the_id = id.id;
	} else {
		alert("ERROR [HTMLArea.Config::registerButton]:\ninvalid arguments");
		return false;
	}
	// check for existing id
	if (typeof this.customSelects[the_id] != "undefined") {
		alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists.");
	}
	if (typeof this.btnList[the_id] != "undefined") {
		alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists.");
	}
	switch (typeof id) {
	    case "string": this.btnList[id] = [ tooltip, image, textMode, action, context ]; break;
	    case "object": this.btnList[id.id] = [ id.tooltip, id.image, id.textMode, id.action, id.context ]; break;
	}
};

/** The following helper function registers a dropdown box with the editor
 * configuration.  You still have to add it to the toolbar, same as with the
 * buttons.  Call it like this:
 *
 * FIXME: add example
 */
HTMLArea.Config.prototype.registerDropdown = function(object) {
	// check for existing id
	if (typeof this.customSelects[object.id] != "undefined") {
		alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists.");
	}
	if (typeof this.btnList[object.id] != "undefined") {
		alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists.");
	}
	this.customSelects[object.id] = object;
};

/** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */
HTMLArea.replaceAll = function(config) {
	var tas = document.getElementsByTagName("textarea");
	for (var i = tas.length; i > 0; (new HTMLArea(tas[--i], config)).generate());
};

/** Helper function: replaces the TEXTAREA with the given ID with HTMLArea. */
HTMLArea.replace = function(id, config) {
	var ta = document.getElementById(id);
	return ta ? (new HTMLArea(ta, config)).generate() : null;
};

// Creates the toolbar and appends it to the _htmlarea
HTMLArea.prototype._createToolbar = function () {
	var editor = this;	// to access this in nested functions

	var toolbar = document.createElement("div");
	this._toolbar = toolbar;
	toolbar.className = "toolbar";
	toolbar.unselectable = "1";
	var tb_row = null;
	var tb_objects = new Object();
	this._toolbarObjects = tb_objects;

	// creates a new line in the toolbar
	function newLine() {
		var table = document.createElement("table");
		table.border = "0px";
		table.cellSpacing = "0px";
		table.cellPadding = "0px";
		toolbar.appendChild(table);
		// TBODY is required for IE, otherwise you don't see anything
		// in the TABLE.
		var tb_body = document.createElement("tbody");
		table.appendChild(tb_body);
		tb_row = document.createElement("tr");
		tb_body.appendChild(tb_row);
	}; // END of function: newLine
	// init first line
	newLine();

	// updates the state of a toolbar element.  This function is member of
	// a toolbar element object (unnamed objects created by createButton or
	// createSelect functions below).
	function setButtonStatus(id, newval) {
		var oldval = this[id];
		var el = this.element;
		if (oldval != newval) {
			switch (id) {
			    case "enabled":
				if (newval) {
					HTMLArea._removeClass(el, "buttonDisabled");
					el.disabled = false;
				} else {
					HTMLArea._addClass(el, "buttonDisabled");
					el.disabled = true;
				}
				break;
			    case "active":
				if (newval) {
					HTMLArea._addClass(el, "buttonPressed");
				} else {
					HTMLArea._removeClass(el, "buttonPressed");
				}
				break;
			}
			this[id] = newval;
		}
	}; // END of function: setButtonStatus

	// this function will handle creation of combo boxes.  Receives as
	// parameter the name of a button as defined in the toolBar config.
	// This function is called from createButton, above, if the given "txt"
	// doesn't match a button.
	function createSelect(txt) {
		var options = null;
		var el = null;
		var cmd = null;
		var customSelects = editor.config.customSelects;
		var context = null;
		switch (txt) {
		    case "fontsize":
		    case "fontname":
		    case "formatblock":
			// the following line retrieves the correct
			// configuration option because the variable name
			// inside the Config object is named the same as the
			// button/select in the toolbar.  For instance, if txt
			// == "formatblock" we retrieve config.formatblock (or
			// a different way to write it in JS is
			// config["formatblock"].
			options = editor.config[txt];
			cmd = txt;
			break;
		    default:
			// try to fetch it from the list of registered selects
			cmd = txt;
			var dropdown = customSelects[cmd];
			if (typeof dropdown != "undefined") {
				options = dropdown.options;
				context = dropdown.context;
			} else {
				alert("ERROR [createSelect]:\nCan't find the requested dropdown definition");
			}
			break;
		}
		if (options) {
			el = document.createElement("select");
			var obj = {
				name	: txt, // field name
				element : el,	// the UI element (SELECT)
				enabled : true, // is it enabled?
				text	: false, // enabled in text mode?
				cmd	: cmd, // command ID
				state	: setButtonStatus, // for changing state
				context : context
			};
			tb_objects[txt] = obj;
			for (var i in options) {
				var op = document.createElement("option");
				op.appendChild(document.createTextNode(i));
				op.value = options[i];
				el.appendChild(op);
			}
			HTMLArea._addEvent(el, "change", function () {
				editor._comboSelected(el, txt);
			});
		}
		return el;
	}; // END of function: createSelect

	// appends a new button to toolbar
	function createButton(txt) {
		// the element that will be created
		var el = null;
		var btn = null;
		switch (txt) {
		    case "separator":
			el = document.createElement("div");
			el.className = "separator";
			break;
		    case "space":
			el = document.createElement("div");
			el.className = "space";
			break;
		    case "linebreak":
			newLine();
			return false;
		    case "textindicator":
			el = document.createElement("div");
			el.appendChild(document.createTextNode("A"));
			el.className = "indicator";
			el.title = HTMLArea.I18N.tooltips.textindicator;
			var obj = {
				name	: txt, // the button name (i.e. 'bold')
				element : el, // the UI element (DIV)
				enabled : true, // is it enabled?
				active	: false, // is it pressed?
				text	: false, // enabled in text mode?
				cmd	: "textindicator", // the command ID
				state	: setButtonStatus // for changing state
			};
			tb_objects[txt] = obj;
			break;
		    default:
			btn = editor.config.btnList[txt];
		}
		if (!el && btn) {
			el = document.createElement("div");
			el.title = btn[0];
			el.className = "button";
			// let's just pretend we have a button object, and
			// assign all the needed information to it.
			var obj = {
				name	: txt, // the button name (i.e. 'bold')
				element : el, // the UI element (DIV)
				enabled : true, // is it enabled?
				active	: false, // is it pressed?
				text	: btn[2], // enabled in text mode?
				cmd	: btn[3], // the command ID
				state	: setButtonStatus, // for changing state
				context : btn[4] || null // enabled in a certain context?
			};
			tb_objects[txt] = obj;
			// handlers to emulate nice flat toolbar buttons
			HTMLArea._addEvent(el, "mouseover", function () {
				if (obj.enabled) {
					HTMLArea._addClass(el, "buttonHover");
				}
			});
			HTMLArea._addEvent(el, "mouseout", function () {
				if (obj.enabled) with (HTMLArea) {
					_removeClass(el, "buttonHover");
					_removeClass(el, "buttonActive");
					(obj.active) && _addClass(el, "buttonPressed");
				}
			});
			HTMLArea._addEvent(el, "mousedown", function (ev) {
				if (obj.enabled) with (HTMLArea) {
					_addClass(el, "buttonActive");
					_removeClass(el, "buttonPressed");
					_stopEvent(is_ie ? window.event : ev);
				}
			});
			// when clicked, do the following:
			HTMLArea._addEvent(el, "click", function (ev) {
				if (obj.enabled) with (HTMLArea) {
					_removeClass(el, "buttonActive");
					_removeClass(el, "buttonHover");
					obj.cmd(editor, obj.name, obj);
					_stopEvent(is_ie ? window.event : ev);
				}
			});
			var img = document.createElement("img");
			img.src = editor.imgURL(btn[1]);
			img.style.width = "18px";
			img.style.height = "18px";
			el.appendChild(img);
		} else if (!el) {
			el = createSelect(txt);
		}
		if (el) {
			var tb_cell = document.createElement("td");
			tb_row.appendChild(tb_cell);
			tb_cell.appendChild(el);
		} else {
			alert("FIXME: Unknown toolbar item: " + txt);
		}
		return el;
	};

	var first = true;
	for (var i in this.config.toolbar) {
		if (!first) {
			createButton("linebreak");
		} else {
			first = false;
		}
		var group = this.config.toolbar[i];
		for (var j in group) {
			var code = group[j];
			if (/^([IT])\[(.*?)\]/.test(code)) {
				// special case, create text label
				var l7ed = RegExp.$1 == "I"; // localized?
				var label = RegExp.$2;
				if (l7ed) {
					label = HTMLArea.I18N.custom[label];
				}
				var tb_cell = document.createElement("td");
				tb_row.appendChild(tb_cell);
				tb_cell.className = "label";
				tb_cell.innerHTML = label;
			} else {
				createButton(code);
			}
		}
	}

	this._htmlArea.appendChild(toolbar);
};

HTMLArea.prototype._createStatusBar = function() {
	var div = document.createElement("div");
	div.className = "statusBar";
	this._htmlArea.appendChild(div);
	this._statusBar = div;
	div.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": "));
	// creates a holder for the path view
	div = document.createElement("span");
	div.className = "statusBarTree";
	this._statusBarTree = div;
	this._statusBar.appendChild(div);
	if (!this.config.statusBar) {
		// disable it...
		div.style.display = "none";
	}
};

// Creates the HTMLArea object and replaces the textarea with it.
HTMLArea.prototype.generate = function () {
	var editor = this;	// we'll need "this" in some nested functions
	// get the textarea
	var textarea = this._textArea;
	if (typeof textarea == "string") {
		// it's not element but ID
		this._textArea = textarea = document.getElementById(textarea);
	}
	this._ta_size = {
		w: textarea.offsetWidth,
		h: textarea.offsetHeight
	};
	textarea.style.display = "none";

	// create the editor framework
	var htmlarea = document.createElement("div");
	htmlarea.className = "htmlarea";
	this._htmlArea = htmlarea;

	// insert the editor before the textarea.
	textarea.parentNode.insertBefore(htmlarea, textarea);

	if (textarea.form) {
		// we have a form, on submit get the HTMLArea content and
		// update original textarea.
		textarea.form.onsubmit = function() {
			editor._textArea.value = editor.getHTML();
		};
	}

	// add a handler for the "back/forward" case -- on body.unload we save
	// the HTML content into the original textarea.
	window.onunload = function() {
		editor._textArea.value = editor.getHTML();
	};

	// creates & appends the toolbar
	this._createToolbar();

	// create the IFRAME
	var iframe = document.createElement("iframe");
	htmlarea.appendChild(iframe);

	this._iframe = iframe;

	// creates & appends the status bar, if the case
	this._createStatusBar();

	// remove the default border as it keeps us from computing correctly
	// the sizes.  (somebody tell me why doesn't this work in IE)

	if (!HTMLArea.is_ie) {
		iframe.style.borderWidth = "1px";
	// iframe.frameBorder = "1";
	// iframe.marginHeight = "0";
	// iframe.marginWidth = "0";
	}

	// size the IFRAME according to user's prefs or initial textarea
	var height = (this.config.height == "auto" ? (this._ta_size.h + "px") : this.config.height);
	height = parseInt(height);
	var width = (this.config.width == "auto" ? (this._ta_size.w + "px") : this.config.width);
	width = parseInt(width);

	if (!HTMLArea.is_ie) {
		height -= 2;
		width -= 2;
	}

	iframe.style.width = width + "px";
	if (this.config.sizeIncludesToolbar) {
		// substract toolbar height
		height -= this._toolbar.offsetHeight;
		height -= this._statusBar.offsetHeight;
	}
	if (height < 0) {
		height = 0;
	}
	iframe.style.height = height + "px";

	// the editor including the toolbar now have the same size as the
	// original textarea.. which means that we need to reduce that a bit.
	textarea.style.width = iframe.style.width;
 	textarea.style.height = iframe.style.height;

	// IMPORTANT: we have to allow Mozilla a short time to recognize the
	// new frame.  Otherwise we get a stupid exception.
	function initIframe() {
		var doc = editor._iframe.contentWindow.document;
		if (!doc) {
			// Try again..
			// FIXME: don't know what else to do here.  Normally
			// we'll never reach this point.
			if (HTMLArea.is_gecko) {
				setTimeout(initIframe, 10);
				return false;
			} else {
				alert("ERROR: IFRAME can't be initialized.");
			}
		}
		if (HTMLArea.is_gecko) {
			// enable editable mode for Mozilla
			doc.designMode = "on";
		}
		editor._doc = doc;
		doc.open();
		var html = "<html>\n";
		html += "<head>\n";
		html += "<style>" + editor.config.pageStyle + "</style>\n";
		html += "</head>\n";
		html += "<body>\n";
		html += editor._textArea.value;
		html += "</body>\n";
		html += "</html>";
		doc.write(html);
		doc.close();

		if (HTMLArea.is_ie) {
			// enable editable mode for IE.	 For some reason this
			// doesn't work if done in the same place as for Gecko
			// (above).
			doc.body.contentEditable = true;
		}

		editor.focusEditor();
		// intercept some events; for updating the toolbar & keyboard handlers
		HTMLArea._addEvents
			(doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"],
			 function (event) {
				 return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event);
			 });
		editor.updateToolbar();
	};
	setTimeout(initIframe, HTMLArea.is_gecko ? 10 : 0);
};

// Switches editor mode; parameter can be "textmode" or "wysiwyg".  If no
// parameter was passed this function toggles between modes.
HTMLArea.prototype.setMode = function(mode) {
	if (typeof mode == "undefined") {
		mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode");
	}
	switch (mode) {
	    case "textmode":
		this._textArea.value = this.getHTML();
		this._iframe.style.display = "none";
		this._textArea.style.display = "block";
		if (this.config.statusBar) {
			this._statusBar.innerHTML = HTMLArea.I18N.msg["TEXT_MODE"];
		}
		break;
	    case "wysiwyg":
		if (HTMLArea.is_gecko) {
			// disable design mode before changing innerHTML
			this._doc.designMode = "off";
		}
		this._doc.body.innerHTML = this.getHTML();
		this._iframe.style.display = "block";
		this._textArea.style.display = "none";
		if (HTMLArea.is_gecko) {
			// we need to refresh that info for Moz-1.3a
			this._doc.designMode = "on";
		}
		if (this.config.statusBar) {
			this._statusBar.innerHTML = '';
			this._statusBar.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": "));
			this._statusBar.appendChild(this._statusBarTree);
		}
		break;
	    default:
		alert("Mode <" + mode + "> not defined!");
		return false;
	}
	this._editMode = mode;
	this.focusEditor();
};

/***************************************************
 *  Category: PLUGINS
 ***************************************************/

// Create the specified plugin and register it with this HTMLArea
HTMLArea.prototype.registerPlugin = function(pluginName) {
	this.plugins[pluginName] = eval("new " + pluginName + "(this);");
};

// static function that loads the required plugin and lang file, based on the
// language loaded already for HTMLArea.  You better make sure that the plugin
// _has_ that language, otherwise shit might happen ;-)
HTMLArea.loadPlugin = function(pluginName) {
	var editorurl = '';
	if (typeof _editor_url != "undefined") {
		editorurl = _editor_url + "/";
	}
	var dir = editorurl + "plugins/" + pluginName;
	var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g,
					function (str, l1, l2, l3) {
						return l1 + "-" + l2.toLowerCase() + l3;
					}).toLowerCase() + ".js";
	document.write("<script type='text/javascript' src='" + dir + "/" + plugin + "'></script>");
	document.write("<script type='text/javascript' src='" + dir + "/lang/" + HTMLArea.I18N.lang + ".js'></script>");
};

/***************************************************
 *  Category: EDITOR UTILITIES
 ***************************************************/

HTMLArea.prototype.forceRedraw = function() {
	this._doc.body.style.visibility = "hidden";
	this._doc.body.style.visibility = "visible";
	// this._doc.body.innerHTML = this.getInnerHTML();
};

// focuses the iframe window.  returns a reference to the editor document.
HTMLArea.prototype.focusEditor = function() {
	switch (this._editMode) {
	    case "wysiwyg" : this._iframe.contentWindow.focus(); break;
	    case "textmode": this._textArea.focus(); break;
	    default	   : alert("ERROR: mode " + this._editMode + " is not defined");
	}
	return this._doc;
};

// updates enabled/disable/active state of the toolbar elements
HTMLArea.prototype.updateToolbar = function(noStatus) {
	var doc = this._doc;
	var text = (this._editMode == "textmode");
	var ancestors = null;
	if (!text) {
		ancestors = this.getAllAncestors();
		if (this.config.statusBar && !noStatus) {
			this._statusBarTree.innerHTML = ''; // clear
			for (var i = ancestors.length; --i >= 0;) {
				var el = ancestors[i];
				if (!el) {
					// hell knows why we get here; this
					// could be a classic example of why
					// it's good to check for conditions
					// that are impossible to happen ;-)
					continue;
				}
				var a = document.createElement("a");
				a.href = "#";
				a.el = el;
				a.editor = this;
				a.onclick = function() {
					this.blur();
					this.editor.selectNodeContents(this.el);
					this.editor.updateToolbar(true);
					return false;
				};
				a.oncontextmenu = function() {
					// TODO: add context menu here
					this.blur();
					var info = "Inline style:\n\n";
					info += this.el.style.cssText.split(/;\s*/).join(";\n");
					alert(info);
					return false;
				};
				var txt = el.tagName.toLowerCase();
				a.title = el.style.cssText;
				if (el.id) {
					txt += "#" + el.id;
				}
				if (el.className) {
					txt += "." + el.className;
				}
				a.appendChild(document.createTextNode(txt));
				this._statusBarTree.appendChild(a);
				if (i != 0) {
					this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb)));
				}
			}
		}
	}
	for (var i in this._toolbarObjects) {
		var btn = this._toolbarObjects[i];
		var cmd = i;
		var inContext = true;
		if (btn.context && !text) {
			inContext = false;
			var context = btn.context;
			var attrs = [];
			if (/(.*)\[(.*?)\]/.test(context)) {
				context = RegExp.$1;
				attrs = RegExp.$2.split(",");
			}
			context = context.toLowerCase();
			var match = (context == "*");
			for (var k in ancestors) {
				if (!ancestors[k]) {
					// the impossible really happens.
					continue;
				}
				if (match || (ancestors[k].tagName.toLowerCase() == context)) {
					inContext = true;
					for (var ka in attrs) {
						if (!eval("ancestors[k]." + attrs[ka])) {
							inContext = false;
							break;
						}
					}
					if (inContext) {
						break;
					}
				}
			}
		}
		btn.state("enabled", (!text || btn.text) && inContext);
		if (typeof cmd == "function") {
			continue;
		}
		// look-it-up in the custom dropdown boxes
		var dropdown = this.config.customSelects[cmd];
		if ((!text || btn.text) && (typeof dropdown != "undefined")) {
			dropdown.refresh(this);
			continue;
		}
		switch (cmd) {
		    case "fontname":
		    case "fontsize":
		    case "formatblock":
			if (!text) {
				var value = ("" + doc.queryCommandValue(cmd)).toLowerCase();
				if (!value) {
					// FIXME: what do we do here?
					break;
				}
				// HACK -- retrieve the config option for this
				// combo box.  We rely on the fact that the
				// variable in config has the same name as
				// button name in the toolbar.
				var options = this.config[cmd];
				var k = 0;
				// btn.element.selectedIndex = 0;
				for (var j in options) {
					// FIXME: the following line is scary.
					if ((j.toLowerCase() == value) ||
					    (options[j].substr(0, value.length).toLowerCase() == value)) {
						btn.element.selectedIndex = k;
						break;
					}
					++k;
				}
			}
			break;
		    case "textindicator":
			if (!text) {
				try {with (btn.element.style) {
					backgroundColor = HTMLArea._makeColor(
						doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor"));
					if (/transparent/i.test(backgroundColor)) {
						// Mozilla
						backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor"));
					}
					color = HTMLArea._makeColor(doc.queryCommandValue("forecolor"));
					fontFamily = doc.queryCommandValue("fontname");
					fontWeight = doc.queryCommandState("bold") ? "bold" : "normal";
					fontStyle = doc.queryCommandState("italic") ? "italic" : "normal";
				}} catch (e) {
					// alert(e + "\n\n" + cmd);
				}
			}
			break;
		    case "htmlmode": btn.state("active", text); break;
		    default:
			try {
				btn.state("active", (!text && doc.queryCommandState(cmd)));
			} catch (e) {}
		}
	}
};

/** Returns a node after which we can insert other nodes, in the current
 * selection.  The selection is removed.  It splits a text node, if needed.
 */
HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
	if (!HTMLArea.is_ie) {
		var sel = this._getSelection();
		var range = this._createRange(sel);
		// remove the current selection
		sel.removeAllRanges();
		range.deleteContents();
		var node = range.startContainer;
		var pos = range.startOffset;
		switch (node.nodeType) {
		    case 3: // Node.TEXT_NODE
			// we have to split it at the caret position.
			if (toBeInserted.nodeType == 3) {
				// do optimized insertion
				node.insertData(pos, toBeInserted.data);
				range = this._createRange();
				range.setEnd(node, pos + toBeInserted.length);
				range.setStart(node, pos + toBeInserted.length);
				sel.addRange(range);
			} else {
				node = node.splitText(pos);
				var selnode = toBeInserted;
				if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
					selnode = selnode.firstChild;
				}
				node.parentNode.insertBefore(toBeInserted, node);
				this.selectNodeContents(selnode);
				this.updateToolbar();
			}
			break;
		    case 1: // Node.ELEMENT_NODE
			var selnode = toBeInserted;
			if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
				selnode = selnode.firstChild;
			}
			node.insertBefore(toBeInserted, node.childNodes[pos]);
			this.selectNodeContents(selnode);
			this.updateToolbar();
			break;
		}
	} else {
		return null;	// this function not yet used for IE <FIXME>
	}
};

// Returns the deepest node that contains both endpoints of the selection.
HTMLArea.prototype.getParentElement = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	if (HTMLArea.is_ie) {
		return range.parentElement ? range.parentElement() : this._doc.body;
	} else {
		var p = range.commonAncestorContainer;
		while (p.nodeType == 3) {
			p = p.parentNode;
		}
		return p;
	}
};

// Returns an array with all the ancestor nodes of the selection.
HTMLArea.prototype.getAllAncestors = function() {
	var p = this.getParentElement();
	var a = [];
	while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
		a.push(p);
		p = p.parentNode;
	}
	a.push(this._doc.body);
	return a;
};

// Selects the contents inside the given node
HTMLArea.prototype.selectNodeContents = function(node, pos) {
	this.focusEditor();
	this.forceRedraw();
	var range;
	var collapsed = (typeof pos != "undefined");
	if (HTMLArea.is_ie) {
		range = this._doc.body.createTextRange();
		range.moveToElementText(node);
		(collapsed) && range.collapse(pos);
		range.select();
	} else {
		var sel = this._getSelection();
		range = this._doc.createRange();
		range.selectNodeContents(node);
		(collapsed) && range.collapse(pos);
		sel.removeAllRanges();
		sel.addRange(range);
	}
};

/** Call this function to insert HTML code at the current position.  It deletes
 * the selection, if any.
 */
HTMLArea.prototype.insertHTML = function(html) {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	if (HTMLArea.is_ie) {
		range.pasteHTML(html);
	} else {
		// construct a new document fragment with the given HTML
		var fragment = this._doc.createDocumentFragment();
		var div = this._doc.createElement("div");
		div.innerHTML = html;
		while (div.firstChild) {
			// the following call also removes the node from div
			fragment.appendChild(div.firstChild);
		}
		// this also removes the selection
		var node = this.insertNodeAtSelection(fragment);
	}
};

/**
 *  Call this function to surround the existing HTML code in the selection with
 *  your tags.  FIXME: buggy!  This function will be deprecated "soon".
 */
HTMLArea.prototype.surroundHTML = function(startTag, endTag) {
	var html = this.getSelectedHTML();
	// the following also deletes the selection
	this.insertHTML(startTag + html + endTag);
};

/// Retrieve the selected block
HTMLArea.prototype.getSelectedHTML = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	var existing = null;
	if (HTMLArea.is_ie) {
		existing = range.htmlText;
	} else {
		existing = HTMLArea.getHTML(range.cloneContents(), false);
	}
	return existing;
};

// Called when the user clicks on "InsertImage" button
HTMLArea.prototype._insertImage = function() {
	var editor = this;	// for nested functions
	this._popupDialog("insert_image.html", function(param) {
		if (!param) {	// user must have pressed Cancel
			return false;
		}
		var sel = editor._getSelection();
		var range = editor._createRange(sel);
		editor._doc.execCommand("insertimage", false, param["f_url"]);
		var img = null;
		if (HTMLArea.is_ie) {
			img = range.parentElement();
			// wonder if this works...
			if (img.tagName.toLowerCase() != "img") {
				img = img.previousSibling;
			}
		} else {
			img = range.startContainer.previousSibling;
		}
		for (field in param) {
			var value = param[field];
			if (!value) {
				continue;
			}
			switch (field) {
			    case "f_alt"    : img.alt	 = value; break;
			    case "f_border" : img.border = parseInt(value); break;
			    case "f_align"  : img.align	 = value; break;
			    case "f_vert"   : img.vspace = parseInt(value); break;
			    case "f_horiz"  : img.hspace = parseInt(value); break;
			}
		}
	}, null);
};

// Called when the user clicks the Insert Table button
HTMLArea.prototype._insertTable = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	var editor = this;	// for nested functions
	this._popupDialog("insert_table.html", function(param) {
		if (!param) {	// user must have pressed Cancel
			return false;
		}
		var doc = editor._doc;
		// create the table element
		var table = doc.createElement("table");
		// assign the given arguments
		for (var field in param) {
			var value = param[field];
			if (!value) {
				continue;
			}
			switch (field) {
			    case "f_width"   : table.style.width = value + param["f_unit"]; break;
			    case "f_align"   : table.align	 = value; break;
			    case "f_border"  : table.border	 = parseInt(value); break;
			    case "f_spacing" : table.cellspacing = parseInt(value); break;
			    case "f_padding" : table.cellpadding = parseInt(value); break;
			}
		}
		var tbody = doc.createElement("tbody");
		table.appendChild(tbody);
		for (var i = 0; i < param["f_rows"]; ++i) {
			var tr = doc.createElement("tr");
			tbody.appendChild(tr);
			for (var j = 0; j < param["f_cols"]; ++j) {
				var td = doc.createElement("td");
				tr.appendChild(td);
				// Mozilla likes to see something inside the cell.
				(HTMLArea.is_gecko) && td.appendChild(doc.createElement("br"));
			}
		}
		if (HTMLArea.is_ie) {
			range.pasteHTML(table.outerHTML);
		} else {
			// insert the table
			editor.insertNodeAtSelection(table);
		}
		return true;
	}, null);
};

/***************************************************
 *  Category: EVENT HANDLERS
 ***************************************************/

// el is reference to the SELECT object
// txt is the name of the select field, as in config.toolbar
HTMLArea.prototype._comboSelected = function(el, txt) {
	this.focusEditor();
	var value = el.options[el.selectedIndex].value;
	switch (txt) {
	    case "fontname":
	    case "fontsize": this.execCommand(txt, false, value); break;
	    case "formatblock":
		(HTMLArea.is_ie) && (value = "<" + value + ">");
		this.execCommand(txt, false, value);
		break;
	    default:
		// try to look it up in the registered dropdowns
		var dropdown = this.config.customSelects[txt];
		if (typeof dropdown != "undefined") {
			dropdown.action(this);
		} else {
			alert("FIXME: combo box " + txt + " not implemented");
		}
	}
};

// the execCommand function (intercepts some commands and replaces them with
// our own implementation)
HTMLArea.prototype.execCommand = function(cmdID, UI, param) {
	var editor = this;	// for nested functions
	this.focusEditor();
	switch (cmdID.toLowerCase()) {
	    case "htmlmode" : this.setMode(); break;
	    case "hilitecolor":
		(HTMLArea.is_ie) && (cmdID = "backcolor");
	    case "forecolor":
		this._popupDialog("select_color.html", function(color) {
			if (color) { // selection not canceled
				editor._doc.execCommand(cmdID, false, "#" + color);
			}
		}, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID)));
		break;
	    case "createlink":
		if (HTMLArea.is_ie || !UI) {
			this._doc.execCommand(cmdID, UI, param);
		} else {
			// browser is Mozilla & wants UI
			var param;
			if ((param = prompt("Enter URL"))) {
				this._doc.execCommand(cmdID, false, param);
			}
		}
		break;
	    case "popupeditor":
		if (HTMLArea.is_ie) {
			window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",
				    "toolbar=no,location=no,directories=no,status=no,menubar=no," +
				    "scrollbars=no,resizable=yes,width=640,height=480");
		} else {
			window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",
				    "toolbar=no,menubar=no,personalbar=no,width=640,height=480," +
				    "scrollbars=no,resizable=yes");
		}
		// pass this object to the newly opened window
		HTMLArea._object = this;
		break;
	    case "inserttable": this._insertTable(); break;
	    case "insertimage": this._insertImage(); break;
	    case "about"    : this._popupDialog("about.html", null, null); break;
	    case "showhelp" : window.open("reference.html", "ha_help"); break;
	    default: this._doc.execCommand(cmdID, UI, param);
	}
	this.updateToolbar();
	return false;
};

/** A generic event handler for things that happen in the IFRAME's document.
 * This function also handles key bindings. */
HTMLArea.prototype._editorEvent = function(ev) {
	var editor = this;
	var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (ev.type == "keypress");
	if (keyEvent && ev.ctrlKey) {
		var sel = null;
		var range = null;
		var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase();
		var cmd = null;
		var value = null;
		switch (key) {
		    case 'a':
			if (!HTMLArea.is_ie) {
				// KEY select all
				sel = this._getSelection();
				sel.removeAllRanges();
				range = this._createRange();
				range.selectNodeContents(this._doc.body);
				sel.addRange(range);
				HTMLArea._stopEvent(ev);
			}
			break;

			// simple key commands follow

		    case 'b': cmd = "bold"; break;
		    case 'i': cmd = "italic"; break;
		    case 'u': cmd = "underline"; break;
		    case 's': cmd = "strikethrough"; break;
		    case 'l': cmd = "justifyleft"; break;
		    case 'e': cmd = "justifycenter"; break;
		    case 'r': cmd = "justifyright"; break;
		    case 'j': cmd = "justifyfull"; break;

			// headings
		    case '1':
		    case '2':
		    case '3':
		    case '4':
		    case '5':
		    case '6':
			cmd = "formatblock";
			value = "h" + key;
			if (HTMLArea.is_ie) {
				value = "<" + value + ">";
			}
			break;
		}
		if (cmd) {
			// execute simple command
			this.execCommand(cmd, false, value);
			HTMLArea._stopEvent(ev);
		}
	}
	/*
	else if (keyEvent) {
		// other keys here
		switch (ev.keyCode) {
		    case 13: // KEY enter
			// if (HTMLArea.is_ie) {
			this.insertHTML("<br />");
			HTMLArea._stopEvent(ev);
			// }
			break;
		}
	}
	*/
	// update the toolbar state after some time
	if (editor._timerToolbar) {
		clearTimeout(editor._timerToolbar);
	}
	editor._timerToolbar = setTimeout(function() {
		editor.updateToolbar();
		editor._timerToolbar = null;
	}, 50);
};

// retrieve the HTML
HTMLArea.prototype.getHTML = function() {
	switch (this._editMode) {
	    case "wysiwyg"  : return HTMLArea.getHTML(this._doc.body, false);
	    case "textmode" : return this._textArea.value;
	    default	    : alert("Mode <" + mode + "> not defined!");
	}
	return false;
};

// retrieve the HTML (fastest version, but uses innerHTML)
HTMLArea.prototype.getInnerHTML = function() {
	switch (this._editMode) {
	    case "wysiwyg"  : return this._doc.body.innerHTML;
	    case "textmode" : return this._textArea.value;
	    default	    : alert("Mode <" + mode + "> not defined!");
	}
	return false;
};

// completely change the HTML inside
HTMLArea.prototype.setHTML = function(html) {
	switch (this._editMode) {
	    case "wysiwyg"  : this._doc.body.innerHTML = html; break;
	    case "textmode" : this._textArea.value = html; break;
	    default	    : alert("Mode <" + mode + "> not defined!");
	}
	return false;
};

/***************************************************
 *  Category: UTILITY FUNCTIONS
 ***************************************************/

// browser identification

HTMLArea.agt = navigator.userAgent.toLowerCase();
HTMLArea.is_ie	   = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1));
HTMLArea.is_opera  = (HTMLArea.agt.indexOf("opera") != -1);
HTMLArea.is_mac	   = (HTMLArea.agt.indexOf("mac") != -1);
HTMLArea.is_mac_ie = (HTMLArea.is_ie && HTMLArea.is_mac);
HTMLArea.is_win_ie = (HTMLArea.is_ie && !HTMLArea.is_mac);
HTMLArea.is_gecko  = (navigator.product == "Gecko");

// variable used to pass the object to the popup editor window.
HTMLArea._object = null;

// FIXME!!! this should return false for IE < 5.5
HTMLArea.checkSupportedBrowser = function() {
	if (HTMLArea.is_gecko) {
		if (navigator.productSub < 20021201) {
			alert("You need at least Mozilla-1.3 Alpha.\n" +
			      "Sorry, your Gecko is not supported.");
			return false;
		}
		if (navigator.productSub < 20030210) {
			alert("Mozilla < 1.3 Beta is not supported!\n" +
			      "I'll try, though, but it might not work.");
		}
	}
	return HTMLArea.is_gecko || HTMLArea.is_ie;
};

// selection & ranges

// returns the current selection object
HTMLArea.prototype._getSelection = function() {
	if (HTMLArea.is_ie) {
		return this._doc.selection;
	} else {
		return this._iframe.contentWindow.getSelection();
	}
};

// returns a range for the current selection
HTMLArea.prototype._createRange = function(sel) {
	if (HTMLArea.is_ie) {
		return sel.createRange();
	} else {
		this.focusEditor();
		if (typeof sel != "undefined") {
			return sel.getRangeAt(0);
		} else {
			return this._doc.createRange();
		}
	}
};

// event handling

HTMLArea._addEvent = function(el, evname, func) {
	if (HTMLArea.is_ie) {
		el.attachEvent("on" + evname, func);
	} else {
		el.addEventListener(evname, func, true);
	}
};

HTMLArea._addEvents = function(el, evs, func) {
	for (var i in evs) {
		HTMLArea._addEvent(el, evs[i], func);
	}
};

HTMLArea._removeEvent = function(el, evname, func) {
	if (HTMLArea.is_ie) {
		el.detachEvent("on" + evname, func);
	} else {
		el.removeEventListener(evname, func, true);
	}
};

HTMLArea._removeEvents = function(el, evs, func) {
	for (var i in evs) {
		HTMLArea._removeEvent(el, evs[i], func);
	}
};

HTMLArea._stopEvent = function(ev) {
	if (HTMLArea.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
};

HTMLArea._removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

HTMLArea._addClass = function(el, className) {
	// remove the class first, if already there
	HTMLArea._removeClass(el, className);
	el.className += " " + className;
};

HTMLArea._hasClass = function(el, className) {
	if (!(el && el.className)) {
		return false;
	}
	var cls = el.className.split(" ");
	for (var i = cls.length; i > 0;) {
		if (cls[--i] == className) {
			return true;
		}
	}
	return false;
};

HTMLArea.isBlockElement = function(el) {
	var blockTags = " body form textarea fieldset ul ol dl li div " +
		"p h1 h2 h3 h4 h5 h6 quote pre table thead " +
		"tbody tfoot tr td iframe address ";
	return (blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
};

HTMLArea.needsClosingTag = function(el) {
	var closingTags = " script style div span tr td tbody table em strong font a ";
	return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
};

// performs HTML encoding of some given string
HTMLArea.htmlEncode = function(str) {
	// we don't need regexp for that, but.. so be it for now.
	str = str.replace(/&/ig, "&amp;");
	str = str.replace(/</ig, "&lt;");
	str = str.replace(/>/ig, "&gt;");
	str = str.replace(/\x22/ig, "&quot;");
	// \x22 means '"' -- we use hex reprezentation so that we don't disturb
	// JS compressors (well, at least mine fails.. ;)
	return str;
};

// Retrieves the HTML code from the given node.	 This is a replacement for
// getting innerHTML, using standard DOM calls.
HTMLArea.getHTML = function(root, outputRoot) {
	var html = "";
	switch (root.nodeType) {
	    case 1: // Node.ELEMENT_NODE
	    case 11: // Node.DOCUMENT_FRAGMENT_NODE
		var closed;
		var i;
		if (outputRoot) {
			closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root)));
			html = "<" + root.tagName.toLowerCase();
			var attrs = root.attributes;
			for (i = 0; i < attrs.length; ++i) {
				var a = attrs.item(i);
				if (!a.specified) {
					continue;
				}
				var name = a.nodeName.toLowerCase();
				if (/_moz/.test(name)) {
					// Mozilla reports some special tags
					// here; we don't need them.
					continue;
				}
				var value;
				if (name != "style") {
					// IE5.5 reports 25 when cellSpacing is
					// 1; other values might be doomed too.
					// For this reason we extract the
					// values directly from the root node.
					// I'm starting to HATE JavaScript
					// development.  Browser differences
					// suck.
					if (typeof root[a.nodeName] != "undefined") {
						value = root[a.nodeName];
					} else {
						value = a.nodeValue;
					}
				} else { // IE fails to put style in attributes list
					// FIXME: cssText reported by IE is UPPERCASE
					value = root.style.cssText;
				}
				if (/_moz/.test(value)) {
					// Mozilla reports some special tags
					// here; we don't need them.
					continue;
				}
				html += " " + name + '="' + value + '"';
			}
			html += closed ? " />" : ">";
		}
		for (i = root.firstChild; i; i = i.nextSibling) {
			html += HTMLArea.getHTML(i, true);
		}
		if (outputRoot && !closed) {
			html += "</" + root.tagName.toLowerCase() + ">";
		}
		break;
	    case 3: // Node.TEXT_NODE
		html = HTMLArea.htmlEncode(root.data);
		break;
	    case 8: // Node.COMMENT_NODE
		html = "<!--" + root.data + "-->";
		break;		// skip comments, for now.
	}
	return html;
};

// creates a rgb-style color from a number
HTMLArea._makeColor = function(v) {
	if (typeof v != "number") {
		// already in rgb (hopefully); IE doesn't get here.
		return v;
	}
	// IE sends number; convert to rgb.
	var r = v & 0xFF;
	var g = (v >> 8) & 0xFF;
	var b = (v >> 16) & 0xFF;
	return "rgb(" + r + "," + g + "," + b + ")";
};

// returns hexadecimal color representation from a number or a rgb-style color.
HTMLArea._colorToRgb = function(v) {
	// returns the hex representation of one byte (2 digits)
	function hex(d) {
		return (d < 16) ? ("0" + d.toString(16)) : d.toString(16);
	};

	if (typeof v == "number") {
		// we're talking to IE here
		var r = v & 0xFF;
		var g = (v >> 8) & 0xFF;
		var b = (v >> 16) & 0xFF;
		return "#" + hex(r) + hex(g) + hex(b);
	}

	if (v.substr(0, 3) == "rgb") {
		// in rgb(...) form -- Mozilla
		var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/;
		if (v.match(re)) {
			var r = parseInt(RegExp.$1);
			var g = parseInt(RegExp.$2);
			var b = parseInt(RegExp.$3);
			return "#" + hex(r) + hex(g) + hex(b);
		}
		// doesn't match RE?!  maybe uses percentages or float numbers
		// -- FIXME: not yet implemented.
		return null;
	}

	if (v[0] == "#") {
		// already hex rgb (hopefully :D )
		return v;
	}

	// if everything else fails ;)
	return null;
};

// modal dialogs for Mozilla (for IE we're using the showModalDialog() call).

// receives an URL to the popup dialog and a function that receives one value;
// this function will get called after the dialog is closed, with the return
// value of the dialog.
HTMLArea.prototype._popupDialog = function(url, action, init) {
	Dialog(this.popupURL(url), action, init);
};

// paths

HTMLArea.prototype.imgURL = function(file, plugin) {
	if (typeof plugin == "undefined") {
		return this.config.editorURL + file;
	} else {
		return this.config.editorURL + "plugins/" + plugin + "/img/" + file;
	}
};

HTMLArea.prototype.popupURL = function(file) {
	return this.config.editorURL + this.config.popupURL + file;
};

// EOF
// Local variables: //
// c-basic-offset:8 //
// indent-tabs-mode:t //
// End: //

Index: loncom/html/htmlarea/index.html
+++ loncom/html/htmlarea/index.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.2//EN">
<html>
  <head>
    <title>HTMLArea -- the free, customizable online editor</title>

    <style type="text/css">
      html, body { font-family: georgia,"times new roman",serif; background-color: #fff; color: #000; }
      .label { text-align: right; padding-right: 0.3em; }
      .bline { border-bottom: 1px solid #aaa; }
    </style>
  </head>

  <body>
    <div style="float: right; border: 1px solid #aaa; background-color: #eee; padding: 3px; margin-left: 10px; margin-bottom: 10px;">
      <table cellspacing="0" cellpadding="0" border="0">
        <tr>
          <td class="label">Version:</td><td>3.0</td>
        </tr>
        <tr>
          <td class="label">Release:</td><td>beta (<a href="release-notes.html">release notes</a>)</td>
        </tr>
        <tr>
          <td class="label bline">Compiled at:</td><td class="bline">Aug 11, 2003 [21:30] GMT</td>
        </tr>
        <tr>
          <td class="label">SourceForge page:</td><td><a href="http://sf.net/projects/itools-htmlarea/">http://sf.net/projects/itools-htmlarea/</a></td>
      </table>
    </div>
    <h1>HTMLArea -- the free<br/>customizable online editor</h1>

    <p>
      HTMLArea is a free, customizable online editor.  It works inside your
      browser.  It uses a non-standard feature implemented in Internet
      Explorer 5.5 or better for Windows and Mozilla 1.3 or better (any
      platform), therefore it will only work in one of these browsers.
    </p>

    <p>
      HTMLArea is copyright <a
      href="http://interactivetools.com">InteractiveTools.com</a> and
      released under a BSD-style license.  HTMLArea is created and developed
      upto version 2.03 by InteractiveTools.com.  Version 3.0 developed by
      <a href="http://students.infoiasi.ro/~mishoo/">Mihai Bazon</a> for
      InteractiveTools.  It contains code sponsored by other companies as
      well.
    </p>

    <h2>Online demos</h2>

    <ul>

      <li><a href="example.html">HTMLArea standard</a> -- contains the core
        editor.</li>

      <li><a href="example-table-operations.html">HTMLArea + tables</a> --
        loads the <tt>TableOperations</tt> plugin, sponsored by <a
          href="http://bloki.com">Zapatec Inc.</a></li>

      <li><a href="example-spell-checker.html">HTMLArea + spell checher</a>
        -- loads the <tt>SpellChecker</tt> plugin, sponsored by <a
          href="http://americanbible.org">American Bible Society</a>.</li>

      <li><a href="example-fully-loaded.html">HTMLArea fully loaded</a> ;-)</li>

    </ul>

    <h2>Installation</h2>

    <p>
      Installation is (or should be) easy.  You need to unpack the ZIP file
      in a directory accessible through your webserver.  Supposing you
      unpack in your <tt>DocumentRoot</tt> and your <tt>DocumentRoot</tt> is
      <tt>/var/www/html</tt> as in a standard RedHat installation, you need
      to acomplish the following steps: (the example is for a Unix-like
      operating system)
    </p>

    <pre style="margin-left: 2em"
>
cd /var/www/html
unzip /path/to/archive/HTMLArea-3.0-beta.zip
mv HTMLArea-3.0-beta htmlarea
find htmlarea/ -type f -exec chmod 644 {} \;
find htmlarea/ -type d -exec chmod 755 {} \;
find htmlarea/ -name "*.cgi" -exec chmod 755 {} \;</pre>

    <p>
      <strong>Notes.</strong> You may chose to symlink "htmlarea" to "HTMLArea-3.0-beta", in which case your server needs to be configured to
      "<tt>FollowSymLinks</tt>".  You need to make sure that *.cgi files are
      interpreted as CGI scripts.  If you want to use the SpellChecker
      plugin you need to have a recent version of Perl installed (I
      recommend 5.8.0) on the server, and the module Text::Aspell, available
      from CPAN.  More info in "<a
      href="plugins/SpellChecker/readme-tech.html">plugins/SpellChecker/readme-tech.html</a>".
    </p>

    <p>About how to setup your pages to use the editor, please read the
      [outdated yet generally valid] <a
        href="reference.html">documentation</a>.</p>

    <h2>Status and links</h2>

    <p>HTMLArea has reached version 3.0.  As of this version, it
      supports:</p>

    <ul>

      <li>Customizable toolbar</li>

      <li>Easy internationalization</li>

      <li>Plugin-based infrastructure</li>

      <li>Delivers W3-compliant HTML (with few exceptions)</li>

      <li>Has a subset of Microsoft Word's keyboard shortcuts</li>

      <li>Full-screen editor</li>

      <li>Advanced table operations (by external plugin
        "TableOperations")</li>

      <li>Spell checker (by external plugin "SpellChecker")</li>

      <li>probably more... ;-)</li>

    </ul>

    <p>We have a <a
    href="http://sourceforge.net/projects/itools-htmlarea/">project page</a>
    at <a href="http://sourceforge.net">SourceForge.net</a>.  There you can
    also find out <a href="http://sourceforge.net/cvs/?group_id=69750">how
    to retrieve the code from CVS</a>, or you can <a
    href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/itools-htmlarea">browse
    the CVS online</a>.  We also have a <a
    href="http://sourceforge.net/tracker/?atid=525656&group_id=69750&func=browse">bug
    system</a>, a <a
    href="http://sourceforge.net/tracker/?atid=525658&group_id=69750&func=browse">patch
    tracking system</a> and a <a
    href="http://sourceforge.net/tracker/?atid=525659&group_id=69750&func=browse">feature
    request page</a>.</p>

    <p>We invite you to say everything you want about HTMLArea <a
    href="http://www.interactivetools.com/forum/gforum.cgi?forum=14;">on the
    forums</a> at InteractiveTools.com.  There you should also find the
    latest news.</p>

    <p>Sometimes I post news about the latest developments on <a
    href="http://students.infoiasi.ro/~mishoo/">my personal homepage</a>.</p>

    <h2>"It doesn't work, what's wrong?"</h2>

    <p>If it doesn't work, you have several options:</p>

    <ul>

      <li>Post a message to the forum.  Describe your problem in as much
      detail as possible.  Include errors you might find in the JavaScript
      console (if you are a Mozilla user), or errors displayed by IE (though
      they're most of the times useless).</li>

      <li>If you're positive that you discovered a bug in HTMLArea then feel
      free to fill a bug report in our bug system.  If you have the time you
      should check to see if a similar bug was reported or not; it might be
      fixed already in the CVS ;-) If you're positive that a similar bug was
      not yet reported, do fill a bug report and please include as much
      detail as possible, such as your browser, OS, errors from JavaScript
      console, etc.</li>

      <li>If you want a new feature to be implemented, post it on the
      features request and someone will hopefully take care of it.</li>

    </ul>

    <p>You can <a href="mailto:mishoo@infoiasi.ro">contact me directly</a>
    <em>only</em> if you want to pay me for implementing custom features to
    HTMLArea.  If you want to sponsor these features (that is, allow them to
    get back into the public HTMLArea distribution) I'll be cheaper. ;-)</p>

    <hr />
    <address><a href="http://students.infoiasi.ro/~mishoo/">Mihai Bazon</a></address>
<!-- Created: Sun Aug  3 14:11:26 EEST 2003 -->
<!-- hhmts start -->
Last modified on Tue Aug 12 00:23:26 2003
<!-- hhmts end -->
<!-- doc-lang: English -->
  </body>
</html>



Index: loncom/html/htmlarea/license.txt
+++ loncom/html/htmlarea/license.txt
htmlArea License (based on BSD license)
Copyright (c) 2002, interactivetools.com, inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 

2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 

3) Neither the name of interactivetools.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Index: loncom/html/htmlarea/popupdiv.js
+++ loncom/html/htmlarea/popupdiv.js
/** This file is derived from PopupDiv, developed by Mihai Bazon for
 * SamWare.net.  Modifications were needed to make it usable in HTMLArea.
 * HTMLArea is a free WYSIWYG online HTML editor from InteractiveTools.com.
 *
 * This file does not function standalone.  It is dependent of global functions
 * defined in HTMLArea-3.0 (htmlarea.js).
 *
 * Please see file htmlarea.js for further details.
 **/

var is_ie = ( (navigator.userAgent.toLowerCase().indexOf("msie") != -1) &&
	      (navigator.userAgent.toLowerCase().indexOf("opera") == -1) );
var is_compat = (document.compatMode == "BackCompat");

function PopupDiv(editor, titleText, handler, initFunction) {
	var self = this;

	this.editor = editor;
	this.doc = editor._mdoc;
	this.handler = handler;

	var el = this.doc.createElement("div");
	el.className = "content";

	var popup = this.doc.createElement("div");
	popup.className = "dialog popupdiv";
	this.element = popup;
	var s = popup.style;
	s.position = "absolute";
	s.left = "0px";
	s.top = "0px";

	var title = this.doc.createElement("div");
	title.className = "title";
	this.title = title;
	popup.appendChild(title);

	HTMLArea._addEvent(title, "mousedown", function(ev) {
		self._dragStart(is_ie ? window.event : ev);
	});

	var button = this.doc.createElement("div");
	button.className = "button";
	title.appendChild(button);
	button.innerHTML = "&#x00d7;";
	title.appendChild(this.doc.createTextNode(titleText));
	this.titleText = titleText;

	button.onmouseover = function() {
		this.className += " button-hilite";
	};
	button.onmouseout = function() {
		this.className = this.className.replace(/\s*button-hilite\s*/g, " ");
	};
	button.onclick = function() {
		this.className = this.className.replace(/\s*button-hilite\s*/g, " ");
		self.close();
	};

	popup.appendChild(el);
	this.content = el;

	this.doc.body.appendChild(popup);

	this.dragging = false;
	this.onShow = null;
	this.onClose = null;
	this.modal = false;

	initFunction(this);
};

PopupDiv.currentPopup = null;

PopupDiv.prototype.showAtElement = function(el, mode) {
	this.defaultSize();
	var pos, ew, eh;
	var popup = this.element;
	popup.style.display = "block";
	var w = popup.offsetWidth;
	var h = popup.offsetHeight;
	popup.style.display = "none";
	if (el != window) {
		pos = PopupDiv.getAbsolutePos(el);
		ew = el.offsetWidth;
		eh = el.offsetHeight;
	} else {
		pos = {x:0, y:0};
		var size = PopupDiv.getWindowSize();
		ew = size.x;
		eh = size.y;
	}
	var FX = false, FY = false;
	if (mode.indexOf("l") != -1) {
		pos.x -= w;
		FX = true;
	}
	if (mode.indexOf("r") != -1) {
		pos.x += ew;
		FX = true;
	}
	if (mode.indexOf("t") != -1) {
		pos.y -= h;
		FY = true;
	}
	if (mode.indexOf("b") != -1) {
		pos.y += eh;
		FY = true;
	}
	if (mode.indexOf("c") != -1) {
		FX || (pos.x += Math.round((ew - w) / 2));
		FY || (pos.y += Math.round((eh - h) / 2));
	}
	this.showAt(pos.x, pos.y);
};

PopupDiv.prototype.defaultSize = function() {
	var s = this.element.style;
	var cs = this.element.currentStyle;
	var addX = (is_ie && is_compat) ? (parseInt(cs.borderLeftWidth) +
					   parseInt(cs.borderRightWidth) +
					   parseInt(cs.paddingLeft) +
					   parseInt(cs.paddingRight)) : 0;
	var addY = (is_ie && is_compat) ? (parseInt(cs.borderTopWidth) +
					   parseInt(cs.borderBottomWidth) +
					   parseInt(cs.paddingTop) +
					   parseInt(cs.paddingBottom)) : 0;
	s.display = "block";
	s.width = (this.content.offsetWidth + addX) + "px";
	s.height = (this.content.offsetHeight + this.title.offsetHeight) + "px";
	s.display = "none";
};

PopupDiv.prototype.showAt = function(x, y) {
	this.defaultSize();
	var s = this.element.style;
	s.display = "block";
	s.left = x + "px";
	s.top = y + "px";
	this.hideShowCovered();

	PopupDiv.currentPopup = this;
	HTMLArea._addEvents(this.doc.body, ["mousedown", "click"], PopupDiv.checkPopup);
	HTMLArea._addEvents(this.editor._doc.body, ["mousedown", "click"], PopupDiv.checkPopup);
	if (is_ie && this.modal) {
		this.doc.body.setCapture(false);
		this.doc.body.onlosecapture = function() {
			(PopupDiv.currentPopup) && (this.doc.body.setCapture(false));
		};
	}
	window.event && HTMLArea._stopEvent(window.event);

	if (typeof this.onShow == "function") {
		this.onShow();
	} else if (typeof this.onShow == "string") {
		eval(this.onShow);
	}

	var field = this.element.getElementsByTagName("input")[0];
	if (!field) {
		field = this.element.getElementsByTagName("select")[0];
	}
	if (!field) {
		field = this.element.getElementsByTagName("textarea")[0];
	}
	if (field) {
		field.focus();
	}
};

PopupDiv.prototype.close = function() {
	this.element.style.display = "none";
	PopupDiv.currentPopup = null;
	this.hideShowCovered();
	HTMLArea._removeEvents(this.doc.body, ["mousedown", "click"], PopupDiv.checkPopup);
	HTMLArea._removeEvents(this.editor._doc.body, ["mousedown", "click"], PopupDiv.checkPopup);
	is_ie && this.modal && this.doc.body.releaseCapture();
	if (typeof this.onClose == "function") {
		this.onClose();
	} else if (typeof this.onClose == "string") {
		eval(this.onClose);
	}
	this.element.parentNode.removeChild(this.element);
};

PopupDiv.prototype.getForm = function() {
	var forms = this.content.getElementsByTagName("form");
	return (forms.length > 0) ? forms[0] : null;
};

PopupDiv.prototype.callHandler = function() {
	var tags = ["input", "textarea", "select"];
	var params = new Object();
	for (var ti in tags) {
		var tag = tags[ti];
		var els = this.content.getElementsByTagName(tag);
		for (var j = 0; j < els.length; ++j) {
			var el = els[j];
			params[el.name] = el.value;
		}
	}
	this.handler(this, params);
	return false;
};

PopupDiv.getAbsolutePos = function(el) {
	var r = { x: el.offsetLeft, y: el.offsetTop };
	if (el.offsetParent) {
		var tmp = PopupDiv.getAbsolutePos(el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}
	return r;
};

PopupDiv.getWindowSize = function() {
	if (window.innerHeight) {
		return { y: window.innerHeight, x: window.innerWidth };
	}
	if (this.doc.body.clientHeight) {
		return { y: this.doc.body.clientHeight, x: this.doc.body.clientWidth };
	}
	return { y: this.doc.documentElement.clientHeight, x: this.doc.documentElement.clientWidth };
};

PopupDiv.prototype.hideShowCovered = function () {
	var self = this;
	function isContained(el) {
		while (el) {
			if (el == self.element) {
				return true;
			}
			el = el.parentNode;
		}
		return false;
	};
	var tags = new Array("applet", "select");
	var el = this.element;

	var p = PopupDiv.getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	if (el.style.display == "none") {
		EX1 = EX2 = EY1 = EY2 = 0;
	}

	for (var k = tags.length; k > 0; ) {
		var ar = this.doc.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];
			if (isContained(cc)) {
				cc.style.visibility = "visible";
				continue;
			}

			p = PopupDiv.getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;

			if ((CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				cc.style.visibility = "visible";
			} else {
				cc.style.visibility = "hidden";
			}
		}
	}
};

PopupDiv.prototype._dragStart = function (ev) {
	if (this.dragging) {
		return false;
	}
	this.dragging = true;
	PopupDiv.currentPopup = this;
	var posX = ev.clientX;
	var posY = ev.clientY;
	if (is_ie) {
		posY += this.doc.body.scrollTop;
		posX += this.doc.body.scrollLeft;
	} else {
		posY += window.scrollY;
		posX += window.scrollX;
	}
	var st = this.element.style;
	this.xOffs = posX - parseInt(st.left);
	this.yOffs = posY - parseInt(st.top);
	HTMLArea._addEvent(this.doc, "mousemove", PopupDiv.dragIt);
	HTMLArea._addEvent(this.doc, "mouseover", HTMLArea._stopEvent);
	HTMLArea._addEvent(this.doc, "mouseup", PopupDiv.dragEnd);
	HTMLArea._stopEvent(ev);
};

PopupDiv.dragIt = function (ev) {
	var popup = PopupDiv.currentPopup;
	if (!(popup && popup.dragging)) {
		return false;
	}
	is_ie && (ev = window.event);
	var posX = ev.clientX;
	var posY = ev.clientY;
	if (is_ie) {
		posY += this.doc.body.scrollTop;
		posX += this.doc.body.scrollLeft;
	} else {
		posY += window.scrollY;
		posX += window.scrollX;
	}
	popup.hideShowCovered();
	var st = popup.element.style;
	st.left = (posX - popup.xOffs) + "px";
	st.top = (posY - popup.yOffs) + "px";
	HTMLArea._stopEvent(ev);
};

PopupDiv.dragEnd = function () {
	var popup = PopupDiv.currentPopup;
	if (!popup) {
		return false;
	}
	popup.dragging = false;
	HTMLArea._removeEvent(popup.doc, "mouseup", PopupDiv.dragEnd);
	HTMLArea._removeEvent(popup.doc, "mouseover", HTMLArea._stopEvent);
	HTMLArea._removeEvent(popup.doc, "mousemove", PopupDiv.dragIt);
	popup.hideShowCovered();
};

PopupDiv.checkPopup = function (ev) {
	is_ie && (ev = window.event);
	var el = is_ie ? ev.srcElement : ev.target;
	var cp = PopupDiv.currentPopup;
	for (; (el != null) && (el != cp.element); el = el.parentNode);
	if (el == null) {
		cp.modal || ev.type == "mouseover" || cp.close();
		HTMLArea._stopEvent(ev);
	}
};

PopupDiv.prototype.addButtons = function() {
	var self = this;
	var div = this.doc.createElement("div");
	this.content.appendChild(div);
	div.className = "buttons";
	for (var i = 0; i < arguments.length; ++i) {
		var btn = arguments[i];
		var button = this.doc.createElement("button");
		div.appendChild(button);
		button.innerHTML = HTMLArea.I18N.buttons[btn];
		switch (btn) {
		    case "ok":
			button.onclick = function() {
				self.callHandler();
				self.close();
			};
			break;
		    case "cancel":
			button.onclick = function() {
				self.close();
			};
			break;
		}
	}
};

Index: loncom/html/htmlarea/popupwin.js
+++ loncom/html/htmlarea/popupwin.js
function PopupWin(editor, title, handler, initFunction) {
	this.editor = editor;
	this.handler = handler;
	var dlg = window.open("", "__ha_dialog",
			      "toolbar=no,menubar=no,personalbar=no,width=600,height=600," +
			      "scrollbars=no,resizable=no");
	this.window = dlg;
	var doc = dlg.document;
	this.doc = doc;
	var self = this;

	var base = document.baseURI || document.URL;
	if (base && base.match(/(.*)\/([^\/]+)/)) {
		base = RegExp.$1 + "/";
	}
	this.baseURL = base;

	doc.open();
	var html = "<html><head><title>" + title + "</title>\n";
	// html += "<base href='" + base + "htmlarea.js' />\n";
	html += "<style type='text/css'>@import url(" + base + "htmlarea.css);</style></head>\n";
	html += "<body class='dialog popupwin' id='--HA-body'></body></html>";
	doc.write(html);
	doc.close();

	// sometimes I Hate Mozilla... ;-(
	function init2() {
		var body = doc.body;
		if (!body) {
			setTimeout(init2, 25);
			return false;
		}
		dlg.title = title;
		doc.documentElement.style.padding = "0px";
		doc.documentElement.style.margin = "0px";
		var content = doc.createElement("div");
		content.className = "content";
		self.content = content;
		body.appendChild(content);
		self.element = body;
		initFunction(self);
		dlg.focus();
	};
	init2();
};

PopupWin.prototype.callHandler = function() {
	var tags = ["input", "textarea", "select"];
	var params = new Object();
	for (var ti in tags) {
		var tag = tags[ti];
		var els = this.content.getElementsByTagName(tag);
		for (var j = 0; j < els.length; ++j) {
			var el = els[j];
			var val = el.value;
			if (el.tagName.toLowerCase() == "input") {
				if (el.type == "checkbox") {
					val = el.checked;
				}
			}
			params[el.name] = val;
		}
	}
	this.handler(this, params);
	return false;
};

PopupWin.prototype.close = function() {
	this.window.close();
};

PopupWin.prototype.addButtons = function() {
	var self = this;
	var div = this.doc.createElement("div");
	this.content.appendChild(div);
	div.className = "buttons";
	for (var i = 0; i < arguments.length; ++i) {
		var btn = arguments[i];
		var button = this.doc.createElement("button");
		div.appendChild(button);
		button.innerHTML = HTMLArea.I18N.buttons[btn];
		switch (btn) {
		    case "ok":
			button.onclick = function() {
				self.callHandler();
				self.close();
				return false;
			};
			break;
		    case "cancel":
			button.onclick = function() {
				self.close();
				return false;
			};
			break;
		}
	}
};

PopupWin.prototype.showAtElement = function() {
	var self = this;
	// Mozilla needs some time to realize what's goin' on..
	setTimeout(function() {
		var w = self.content.offsetWidth + 4;
		var h = self.content.offsetHeight + 4;
		// size to content -- that's fuckin' buggy in all fuckin' browsers!!!
		// so that we set a larger size for the dialog window and then center
		// the element inside... phuck!

		// center...
		var el = self.content;
		var s = el.style;
		// s.width = el.offsetWidth + "px";
		// s.height = el.offsetHeight + "px";
		s.position = "absolute";
		s.left = (w - el.offsetWidth) / 2 + "px";
		s.top = (h - el.offsetHeight) / 2 + "px";
		if (HTMLArea.is_gecko) {
			self.window.innerWidth = w;
			self.window.innerHeight = h;
		} else {
			self.window.resizeTo(w + 8, h + 35);
		}
	}, 25);
};

Index: loncom/html/htmlarea/reference.html
+++ loncom/html/htmlarea/reference.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.2//EN">
<html> <head>
<title>HTMLArea-3.0 Reference</title>

<style type="text/css">
  @import url(htmlarea.css);
  body { font: 14px verdana,sans-serif; background: #fff; color: #000; }
  h1, h2 { font-family:tahoma,sans-serif; }
  h1 { border-bottom: 2px solid #000; }
  h2 { border-bottom: 1px solid #aaa; }
  h3, h4 { margin-bottom: 0px; font-family: Georgia,serif; font-style: italic; }
  h4 { font-size: 90%; margin-left: 1em; }
  acronym { border-bottom: 1px dotted #063; color: #063; }
  p { margin-left: 2em; margin-top: 0.3em; }
  li p { margin-left: 0px; }
  .abstract { padding: 5px; margin: 0px 10em; font-size: 90%; border: 1px dashed #aaa; background: #eee;}
  li { margin-left: 2em; }
  em { color: #042; }
  a { color: #00f; }
  a:hover { color: #f00; }
  a:active { color: #f80; }
  span.browser { font-weight: bold; color: #864; }
  .fixme { font-size: 20px; font-weight: bold; color: red; background: #fab;
padding: 5px; text-align: center; }
  .code {
   background: #e4efff; padding: 5px; border: 1px dashed #abc; margin-left: 2em; margin-right: 2em;
   font-family: fixed,"lucidux mono","andale mono","courier new",monospace;
  }
  .note, .warning { font-weight: bold; color: #0a0; font-variant: small-caps; }
  .warning { color: #a00; }

.string {
  color: #06c;
} /* font-lock-string-face */
.comment {
  color: #840;
} /* font-lock-comment-face */
.variable-name {
  color: #000;
} /* font-lock-variable-name-face */
.type {
  color: #008;
  font-weight: bold;
} /* font-lock-type-face */
.reference {
  color: #048;
} /* font-lock-reference-face */
.preprocessor {
  color: #808;
} /* font-lock-preprocessor-face */
.keyword {
  color: #00f;
  font-weight: bold;
} /* font-lock-keyword-face */
.function-name {
  color: #044;
} /* font-lock-function-name-face */
.html-tag {
  font-weight: bold;
} /* html-tag-face */
.html-helper-italic {
  font-style: italic;
} /* html-helper-italic-face */
.html-helper-bold {
  font-weight: bold;
} /* html-helper-bold-face */

</style>

<script type="text/javascript" src="htmlarea.js"></script>
<script type="text/javascript" src="dialog.js"></script>
<script tyle="text/javascript" src="lang/en.js"></script>

</head>

<body onload="HTMLArea.replace('TA')">


<h1>HTMLArea-3.0 Documentation</h1>

<div class="abstract" style="color: red; font-weight: bold">

      This documentation contains valid information, but is outdated in the
      terms that it does not covers all the features of HTMLArea.  A new
      documentation project will be started, based on LaTeX.

</div>


<h2>Introduction</h2>

<h3>What is HTMLArea?</h3>

<p>HTMLArea is a free <acronym title="What You See Is What You Get"
>WYSIWYG</acronym> editor replacement for <code>&lt;textarea&gt;</code>
fields.  By adding a few simple lines of JavaScript code to your web page
you can replace a regular textarea with a rich text editor that lets your
users do the following:</p>

<ul>
  <li>Format text to be bold, italicized, or underlined.</li>
  <li>Change the face, size, style and color.</li>
  <li>Left, center, or right-justify paragraphs.</li>
  <li>Make bulleted or numbered lists.</li>
  <li>Indent or un-indent paragraphs.</li>
  <li>Insert a horizontal line.</li>
  <li>Insert hyperlinks and images.</li>
  <li>View the raw HTML source of what they're editing.</li>
  <li>and much more...</li>
</ul>

<p>Some of the interesting features of HTMLArea that set's it apart from
other web based WYSIWYG editors are as follows:</p>

<ul>
  <li>It's lightweight, fast loading and can transform a regular textarea
  into a rich-text editor with a single line of JavaScript.</li>
  <li>Generates clean, valid HTML.</li>
  <li>It's 100% backwards compatible with older or non-supported browsers
  (they get the original textarea field).</li>
  <li>It's free and can be incorporated into any free or commercial
  program.</li>
  <li>It works with any server-side languages (ASP, PHP, Perl, Java,
  etc).</li>
  <li>It's written in JavaScript and can be easily viewed, modified or
  extended.</li>
  <li>It remembers entered content when a user navigates away and then hits
  "back" in their browser.</li>
  <li>Since it replaces existing textareas it doesn't require a lot of code
  to add it to your pages (just one line).</li>
  <li>Did we mention it was free? ;-)</li>
</ul>

<h3>Is it really free?  What's the catch?</h3>

<p>Yes! It's really free. You can use it, modify it, distribute it with your
software, or do just about anything you like with it.</p>

<h3>What are the browser requirements?</h3>

<p>HTMLArea requires <span class="browser"><a
href="http://www.microsoft.com/ie">Internet Explorer</a> &gt;= 5.5</span>
(Windows only), or <span class="browser"><a
href="http://mozilla.org">Mozilla</a> &gt;= 1.3-Beta</span> on any platform.
Any browser based on <a href="http://mozilla.org/newlayout">Gecko</a> will
also work, provided that Gecko version is at least the one included in
Mozilla-1.3-Beta (for example, <a
href="http://galeon.sf.net">Galeon-1.2.8</a>).  However, it is backwards
compatible with other browsers. They will get a regular textarea field
instead of a WYSIWYG editor.</p>

<h3>Can I see an example of what it looks like?</h3>

<p>Just make sure you're using one of the browsers mentioned above and see
below.</p>

<form onsubmit="return false;">
<textarea id="TA" style="width: 100%; height: 15em;">
<p>Here is some sample text in textarea that's been transformed with <font
color="#0000CC"><b>HTMLArea</b></font>.<br />
You can make things <b>bold</b>, <i>italic</i>, <u>underline</u>.  You can change the
<font size="3">size</font> and <b><font color="#0000CC">c</font><font color="#00CC00">o</font><font color="#00CCCC">l</font><font color="#CC0000">o</font><font color="#CC00CC">r</font><font color="#CCCC00">s</font><font color="#CCCCCC">!</font></b>
And lots more...</p>

<p align="center"><font size="4" color="#ff0000"><b><u>Try HTMLArea
today!</u></b></font><br /></p>
</textarea>
</form>

<h3>Where can I find out more info, download the latest version and talk to
other HTMLArea users?</h3>

<p>You can find out more about HTMLArea and download the latest version on
the <a href="http://www.interactivetools.com/products/htmlarea/">HTMLArea
homepage</a> and you can talk to other HTMLArea users and post any comments
or suggestions you have in the <a
href="http://www.interactivetools.com/iforum/Open_Source_C3/htmlArea_v3.0_-_Alpha_Release_F14/"
>HTMLArea forum</a>.</p>

<h2>Keyboard shortcuts</h2>

<p>The editor provides the following key combinations:</p>

<ul>
  <li>CTRL-A -- select all</li>
  <li>CTRL-B -- bold</li>
  <li>CTRL-I -- italic</li>
  <li>CTRL-U -- underline</li>
  <li>CTRL-S -- strikethrough</li>
  <li>CTRL-L -- justify left</li>
  <li>CTRL-E -- justify center</li>
  <li>CTRL-R -- justify right</li>
  <li>CTRL-J -- justify full</li>
  <li>CTRL-1 .. CTRL-6 -- headings (&lt;h1&gt; .. &lt;h6&gt;)</li>
</ul>

<h2>Installation</h2>

<h3>How do I add HTMLArea to my web page?</h3>

<p>It's easy.  First you need to upload HTMLArea files to your website.
Just follow these steps.</p>

<ol>
  <li>Download the latest version from the <a
  href="http://www.interactivetools.com/products/htmlarea/">htmlArea
  homepage</a>.</li>
  <li>Unzip the files onto your local computer (making sure to maintain the
  directory structure contained in the zip).</li>
  <li>Create a new folder on your website called /htmlarea/ (make sure it's
  NOT inside the cgi-bin).</li>
  <li>Transfer all the HTMLArea files from your local computer into the
  /htmlarea/ folder on your website.</li>
  <li>Open the example page /htmlarea/example.html with your browser to make
  sure everything works.</li>
</ol>

<p>Once htmlArea is on your website all you need to do is add some
JavaScript to any pages that you want to add WYSIWYG editors to.  Here's how
to do that.</p>

<ol>

  <li>Include the "htmlarea.js" script:
  <pre class="code"
  ><span class="function-name">&lt;</span><span class="html-tag">script</span> <span class="variable-name">type=</span><span class="string">&quot;text/javascript&quot;</span> <span class="variable-name">src=</span><span class="string">&quot;/htmlarea/htmlarea.js&quot;</span><span class="function-name">&gt;</span><span class="paren-face-match">&lt;</span><span class="html-tag">/script</span><span class="paren-face-match">&gt;</span></pre>
  </li>

  <li>If you are using popup dialogs, i.e. for insert table, insert image,
  select color, then you need to include the "dialog.js" file.  This is
  recommended anyway.
  <pre class="code"
  ><span class="function-name">&lt;</span><span class="html-tag">script</span> <span class="variable-name">type=</span><span class="string">&quot;text/javascript&quot;</span> <span class="variable-name">src=</span><span class="string">&quot;/htmlarea/dialog.js&quot;</span><span class="paren-face-match">&gt;</span><span class="function-name">&lt;</span><span class="html-tag">/script</span><span class="function-name">&gt;</span></pre>
  </li>

  <li>Include the corresponding language definition file.  <span
  class="note">Note</span>:
  internationalization is available only since version 3.0.  Check the files
  containing "lang" in the distribution ZIP.  If your preferred language is
  not there yet and you decide to write it, please consider sending it to
  us so that it gets included in the next release.
  <pre class="code"
  ><span class="function-name">&lt;</span><span class="html-tag">script</span> <span class="variable-name">type=</span><span class="string">&quot;text/javascript&quot;</span> <span class="variable-name">src=</span><span class="string">&quot;/htmlarea/lang/en.js&quot;</span><span class="function-name">&gt;</span><span class="paren-face-match">&lt;</span><span class="html-tag">/script</span><span class="paren-face-match">&gt;</span></pre>

  <li>Include the stylesheet (be sure to put this inside the HEAD tag):
  <pre class="code"
  ><span class="function-name">&lt;</span><span class="html-tag">style</span> <span class="variable-name">type=</span><span class="string">&quot;text/css&quot;</span><span class="function-name">&gt;</span>@import url<span class="function-name">(</span>/htmlarea/htmlarea.css<span class="function-name">)</span><span class="paren-face-match">&lt;</span><span class="html-tag">/style</span><span class="paren-face-match">&gt;</span></pre>
  </li>

  <li><p>If you want to change all your &lt;textarea&gt;-s into
  HTMLArea-s then you can use the simplest way to create HTMLArea:</p>
  <pre class="code"
  ><span class="function-name">&lt;</span><span class="html-tag">script</span> <span class="variable-name">type=</span><span class="string">&quot;text/javascript&quot;</span> <span class="variable-name">defer=</span><span class="string">&quot;1&quot;</span><span class="function-name">&gt;</span>
    HTMLArea.replaceAll<span class="function-name">()</span>;
<span class="paren-face-match">&lt;</span><span class="html-tag">/script</span><span class="paren-face-match">&gt;</span></pre>
  <p><span class="note">Note:</span> you can also add the
  <code>HTMLArea.replaceAll()</code> code to the <code>onload</code>
  event handler for the <code>body</code> element, if you find it more appropriate.</p>

  <p>A different approach, if you have more than one textarea and only want
  to change one of them, is to use <code>HTMLArea.replace("id")</code> --
  pass the <code>id</code> of your textarea.  Do not use the
  <code>name</code> attribute anymore, it's not a standard solution!</p>

</ol>

<h3>I want to change the editor settings, how do I do that?</h3>

<p>While it's true that all you need is one line of JavaScript to create an
htmlArea WYSIWYG editor, you can also specify more config settings in the
code to control how the editor works and looks.  Here's an example of some of
the available settings:</p>

<pre class="code"
><span class="keyword">var</span> <span class="variable-name">config</span> = <span class="keyword">new</span> HTMLArea.Config(); <span class="comment">// create a new configuration object
</span>                                    <span class="comment">// having all the default values
</span>config.width = '<span class="string">90%</span>';
config.height = '<span class="string">200px</span>';

<span class="comment">// the following sets a style for the page body (black text on yellow page)
// and makes all paragraphs be bold by default
</span>config.pageStyle =
  '<span class="string">body { background-color: yellow; color: black; font-family: verdana,sans-serif } </span>' +
  '<span class="string">p { font-width: bold; } </span>';

<span class="comment">// the following replaces the textarea with the given id with a new
// HTMLArea object having the specified configuration
</span>HTMLArea.replace('<span class="string">id</span>', config);</pre>

<p><span class="warning">Important:</span> It's recommended that you add
custom features and configuration to a separate file.  This will ensure you
that when we release a new official version of HTMLArea you'll have no
trouble upgrading it.</p>

<h3>How do I customize the toolbar?</h3>

<p>Using the configuration object introduced above allows you to completely
control what the toolbar contains.  Following is an example of a one-line,
customized toolbar, much simpler than the default one:</p>

<pre class="code"
><span class="keyword">var</span> <span class="variable-name">config</span> = <span class="keyword">new</span> HTMLArea.Config();
config.toolbar = [
  ['<span class="string">fontname</span>', '<span class="string">space</span>',
   '<span class="string">fontsize</span>', '<span class="string">space</span>',
   '<span class="string">formatblock</span>', '<span class="string">space</span>',
   '<span class="string">bold</span>', '<span class="string">italic</span>', '<span class="string">underline</span>']
];
HTMLArea.replace('<span class="string">id</span>', config);</pre>

<p>The toolbar is an Array of Array objects.  Each array in the toolbar
defines a new line.  The default toolbar looks like this:</p>

<pre class="code"
>config.toolbar = [
[ &quot;<span class="string">fontname</span>&quot;, &quot;<span class="string">space</span>&quot;,
  &quot;<span class="string">fontsize</span>&quot;, &quot;<span class="string">space</span>&quot;,
  &quot;<span class="string">formatblock</span>&quot;, &quot;<span class="string">space</span>&quot;,
  &quot;<span class="string">bold</span>&quot;, &quot;<span class="string">italic</span>&quot;, &quot;<span class="string">underline</span>&quot;, &quot;<span class="string">separator</span>&quot;,
  &quot;<span class="string">strikethrough</span>&quot;, &quot;<span class="string">subscript</span>&quot;, &quot;<span class="string">superscript</span>&quot;, &quot;<span class="string">separator</span>&quot;,
  &quot;<span class="string">copy</span>&quot;, &quot;<span class="string">cut</span>&quot;, &quot;<span class="string">paste</span>&quot;, &quot;<span class="string">space</span>&quot;, &quot;<span class="string">undo</span>&quot;, &quot;<span class="string">redo</span>&quot; ],
		
[ &quot;<span class="string">justifyleft</span>&quot;, &quot;<span class="string">justifycenter</span>&quot;, &quot;<span class="string">justifyright</span>&quot;, &quot;<span class="string">justifyfull</span>&quot;, &quot;<span class="string">separator</span>&quot;,
  &quot;<span class="string">insertorderedlist</span>&quot;, &quot;<span class="string">insertunorderedlist</span>&quot;, &quot;<span class="string">outdent</span>&quot;, &quot;<span class="string">indent</span>&quot;, &quot;<span class="string">separator</span>&quot;,
  &quot;<span class="string">forecolor</span>&quot;, &quot;<span class="string">hilitecolor</span>&quot;, &quot;<span class="string">textindicator</span>&quot;, &quot;<span class="string">separator</span>&quot;,
  &quot;<span class="string">inserthorizontalrule</span>&quot;, &quot;<span class="string">createlink</span>&quot;, &quot;<span class="string">insertimage</span>&quot;, &quot;<span class="string">inserttable</span>&quot;, &quot;<span class="string">htmlmode</span>&quot;, &quot;<span class="string">separator</span>&quot;,
  &quot;<span class="string">popupeditor</span>&quot;, &quot;<span class="string">separator</span>&quot;, &quot;<span class="string">showhelp</span>&quot;, &quot;<span class="string">about</span>&quot; ]
];</pre>

<p>Except three strings, all others in the examples above need to be defined
in the <code>config.btnList</code> object (detailed a bit later in this
document).  The three exceptions are: 'space', 'separator' and 'linebreak'.
These three have the following meaning, and need not be present in
<code>btnList</code>:</p>

<ul>
  <li>'space' -- Inserts a space of 5 pixels (the width is configurable by external
  <acronym title="Cascading Style Sheets">CSS</acronym>) at the current
  position in the toolbar.</li>
  <li>'separator' -- Inserts a small vertical separator, for visually grouping related
  buttons.</li>
  <li>'linebreak' -- Starts a new line in the toolbar.  Subsequent controls will be
  inserted on the new line.</li>
</ul>

<p><span class="warning">Important:</span> It's recommended that you add
custom features and configuration to a separate file.  This will ensure you
that when we release a new official version of HTMLArea you'll have no
trouble upgrading it.</p>

<h3>How do I create custom buttons?</h3>

<p>By design, the toolbar is easily extensible.  For adding a custom button
one needs to follow two steps.</p>

<h4 id="regbtn">1. Register the button in <code>config.btnList</code>.</h4>

<p>For each button in the toolbar, HTMLArea needs to know the following
information:</p>
<ul>
  <li>a name for it (we call it the ID of the button);</li>
  <li>the path to an image to be displayed in the toolbar;</li>
  <li>a tooltip for it;</li>
  <li>whether the button is enabled or not in text mode;</li>
  <li>what to do when the button is clicked;</li>
</ul>
<p>You need to provide all this information for registering a new button
too.  The button ID can be any string identifier and it's used when
defining the toolbar, as you saw above.  We recommend starting
it with "my-" so that it won't clash with the standard ID-s (those from
the default toolbar).</p>

<p class="note">Register button example #1</p>

<pre class="code"
><span class="comment">// get a default configuration
</span><span class="keyword">var</span> <span class="variable-name">config</span> = <span class="keyword">new</span> HTMLArea.Config();
<span class="comment">// register the new button using Config.registerButton.
// parameters:        button ID,   tooltip,          image,           textMode,
</span>config.registerButton(&quot;<span class="string">my-hilite</span>&quot;, &quot;<span class="string">Highlight text</span>&quot;, &quot;<span class="string">my-hilite.gif</span>&quot;, <span class="keyword">false</span>,
<span class="comment">// function that gets called when the button is clicked
</span>  <span class="keyword">function</span>(editor, id) {
    editor.surroundHTML('<span class="string">&lt;span class=&quot;hilite&quot;&gt;</span>', '<span class="string">&lt;/span&gt;</span>');
  }
);</pre>

<p>An alternate way of calling registerButton is exemplified above.  Though
the code might be a little bit larger, using this form makes your code more
maintainable.  It doesn't even needs comments as it's pretty clear.</p>

<p class="note">Register button example #2</p>

<pre class="code"
><span class="keyword">var</span> <span class="variable-name">config</span> = <span class="keyword">new</span> HTMLArea.Config();
config.registerButton({
  id        : &quot;<span class="string">my-hilite</span>&quot;,
  tooltip   : &quot;<span class="string">Highlight text</span>&quot;,
  image     : &quot;<span class="string">my-hilite.gif</span>&quot;,
  textMode  : <span class="keyword">false</span>,
  action    : <span class="keyword">function</span>(editor, id) {
                editor.surroundHTML('<span class="string">&lt;span class=&quot;hilite&quot;&gt;</span>', '<span class="string">&lt;/span&gt;</span>');
              }
});</pre>

<p>You might notice that the "action" function receives two parameters:
<b>editor</b> and <b>id</b>.  In the examples above we only used the
<b>editor</b> parameter.  But it could be helpful for you to understand
both:</p>

<ul>
  <li><b>editor</b> is a reference to the HTMLArea object.  Since our entire
  code now has an <acronym title="Object Oriented Programming">OOP</acronym>-like
  design, you need to have a reference to
  the editor object in order to do things with it.  In previous versions of
  HTMLArea, in order to identify the object an ID was used -- the ID of the
  HTML element.  In this version ID-s are no longer necessary.</li>

  <li><b>id</b> is the button ID.  Wondering why is this useful?  Well, you
  could use the same handler function (presuming that it's not an anonymous
  function like in the examples above) for more buttons.  You can <a
  href="#btnex">see an example</a> a bit later in this document.</li>
</ul>

<h4>2. Inserting it into the toolbar</h4>

<p>At this step you need to specify where in the toolbar to insert the
button, or just create the whole toolbar again as you saw in the previous
section.  You use the button ID, as shown in the examples of customizing the
toolbar in the previous section.</p>

<p>For the sake of completion, following there are another examples.</p>

<p class="note">Append your button to the default toolbar</p>

<pre class="code"
>config.toolbar.push([ &quot;<span class="string">my-hilite</span>&quot; ]);</pre>

<p class="note">Customized toolbar</p>

<pre class="code"
>config.toolbar = [
  ['<span class="string">fontname</span>', '<span class="string">space</span>',
   '<span class="string">fontsize</span>', '<span class="string">space</span>',
   '<span class="string">formatblock</span>', '<span class="string">space</span>',
   '<span class="string">separator</span>', '<span class="string">my-hilite</span>', '<span class="string">separator</span>', '<span class="string">space</span>', <span class="comment">// here's your button
</span>   '<span class="string">bold</span>', '<span class="string">italic</span>', '<span class="string">underline</span>', '<span class="string">space</span>']
];</pre>

<p><span class="note">Note:</span> in the example above our new button is
between two vertical separators.  But this is by no means required.  You can
put it wherever you like.  Once registered in the btnList (<a
href="#regbtn">step 1</a>) your custom button behaves just like a default
button.</p>

<p><span class="warning">Important:</span> It's recommended that you add
custom features and configuration to a separate file.  This will ensure you
that when we release a new official version of HTMLArea you'll have no
trouble upgrading it.</p>

<h4 id="btnex">A complete example</h4>

<p>Please note that it is by no means necessary to include the following
code into the htmlarea.js file.  On the contrary, it might not work there.
The configuration system is designed such that you can always customize the
editor <em>from outside files</em>, thus keeping the htmlarea.js file
intact.  This will make it easy for you to upgrade your HTMLArea when we
release a new official version.  OK, I promise it's the last time I said
this. ;)</p>

<pre class="code"
><span class="comment">// All our custom buttons will call this function when clicked.
// We use the <b>buttonId</b> parameter to determine what button
// triggered the call.
</span><span class="keyword">function</span> <span class="function-name">clickHandler</span>(editor, buttonId) {
  <span class="keyword">switch</span> (buttonId) {
    <span class="keyword">case</span> &quot;<span class="string">my-toc</span>&quot;:
      editor.insertHTML(&quot;<span class="string">&lt;h1&gt;Table Of Contents&lt;/h1&gt;</span>&quot;);
      <span class="keyword">break</span>;
    <span class="keyword">case</span> &quot;<span class="string">my-date</span>&quot;:
      editor.insertHTML((<span class="keyword">new</span> Date()).toString());
      <span class="keyword">break</span>;
    <span class="keyword">case</span> &quot;<span class="string">my-bold</span>&quot;:
      editor.execCommand(&quot;<span class="string">bold</span>&quot;);
      editor.execCommand(&quot;<span class="string">italic</span>&quot;);
      <span class="keyword">break</span>;
    <span class="keyword">case</span> &quot;<span class="string">my-hilite</span>&quot;:
      editor.surroundHTML(&quot;<span class="string">&lt;span class=\&quot;hilite\&quot;&gt;</span>&quot;, &quot;<span class="string">&lt;/span&gt;</span>&quot;);
      <span class="keyword">break</span>;
  }
};

<span class="comment">// Create a new configuration object
</span><span class="keyword">var</span> <span class="variable-name">config</span> = <span class="keyword">new</span> HTMLArea.Config();

<span class="comment">// Register our custom buttons
</span>config.registerButton(&quot;<span class="string">my-toc</span>&quot;,  &quot;<span class="string">Insert TOC</span>&quot;, &quot;<span class="string">my-toc.gif</span>&quot;, <span class="keyword">false</span>, clickHandler);
config.registerButton(&quot;<span class="string">my-date</span>&quot;, &quot;<span class="string">Insert date/time</span>&quot;, &quot;<span class="string">my-date.gif</span>&quot;, <span class="keyword">false</span>, clickHandler);
config.registerButton(&quot;<span class="string">my-bold</span>&quot;, &quot;<span class="string">Toggle bold/italic</span>&quot;, &quot;<span class="string">my-bold.gif</span>&quot;, <span class="keyword">false</span>, clickHandler);
config.registerButton(&quot;<span class="string">my-hilite</span>&quot;, &quot;<span class="string">Hilite selection</span>&quot;, &quot;<span class="string">my-hilite.gif</span>&quot;, <span class="keyword">false</span>, clickHandler);

<span class="comment">// Append the buttons to the default toolbar
</span>config.toolbar.push([&quot;<span class="string">linebreak</span>&quot;, &quot;<span class="string">my-toc</span>&quot;, &quot;<span class="string">my-date</span>&quot;, &quot;<span class="string">my-bold</span>&quot;, &quot;<span class="string">my-hilite</span>&quot;]);

<span class="comment">// Replace an existing textarea with an HTMLArea object having the above config.
</span>HTMLArea.replace(&quot;<span class="string">textAreaID</span>&quot;, config);</pre>


<hr />
<address>&copy; <a href="http://interactivetools.com" title="Visit our website"
>InteractiveTools.com</a> 2002, 2003.
<br />
HTMLArea v3.0 developed by <a
href="http://students.infoiasi.ro/~mishoo">Mihai Bazon</a> for
InteractiveTools.com.
<br />
Documentation written by Mihai Bazon.
</address>
<!-- hhmts start -->
Last modified on Sun Aug  3 16:11:23 2003
<!-- hhmts end -->
<!-- doc-lang: English -->
</body> </html>

Index: loncom/html/htmlarea/release-notes.html
+++ loncom/html/htmlarea/release-notes.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.2//EN">
<html>
  <head>
    <title>HTMLArea-3.0-beta release notes</title>
  </head>

  <body>

    <h1>HTMLArea-3.0-beta release notes</h1>

    <p>This release was compiled on Aug 11, 2003 [21:30] GMT.</p>


    <p>Changes since 3.0-Alpha:</p>

    <ul>

      <li>Performance improvements.</li>

      <li>Many bugs fixed.</li>

      <li>Plugin infrastructure.</li>

      <li>TableOperations plugin.</li>

      <li>SpellChecker plugin.</li>

      <li>Status bar.</li>

      <li>API for registering custom buttons and drop-down boxes in the
        toolbar.</li>

      <li>Toolbar can contain text labels.</li>

      <li>Cut, copy, paste, undo, redo buttons.</li>

    </ul>

    <h2>Rationale for Beta</h2>

    <p>Why was this released as "Beta"?  The code is quite stable and it
    didn't deserve a "Beta" qualification.  However, there are some things
    left to do for the real 3.0 version.  These things will not affect the
    API to work with HTMLArea, in other words, you can install the Beta
    right now and then install the final release without modifying your
    code.  That's if you don't modify HTMLArea itself.  ;-)</p>

    <h2>To-Do before 3.0 final</h2>

    <ol>

      <li>We should use a single popup interface.  Currently there are two:
      dialog.js and popupwin.js; dialog.js emulates modal dialogs, which
      sucks when you want to open "select-color" from another popup and not
      from the editor itself.  Very buggy in IE.  We should probably use only
      modeless dialogs (that is, popupwin.js).</li>

      <li>Internationalization for the SpellChecker plugin.</li>

      <li>Internationalization for the TableOperations plugin.</li>

      <li>People who sent translations are invited to re-iterate through
        their work and make it up-to-date with lang/en.js which is the main
        lang file for HTMLArea-3.0.  Some things have changed but not all
        translations are updated.</li>

      <li><strong>Documentation</strong>.</li>

    </ol>


    <hr />
    <address><a href="http://students.infoiasi.ro/~mishoo/">Mihai Bazon</a></address>
<!-- Created: Sun Aug  3 16:55:08 EEST 2003 -->
<!-- hhmts start -->
Last modified on Sun Aug 10 19:31:39 2003
<!-- hhmts end -->
<!-- doc-lang: English -->
  </body>
</html>



Index: loncom/html/htmlarea/test.cgi
+++ loncom/html/htmlarea/test.cgi
#! /usr/bin/perl -w
#
#
#



use CGI;

print "Content-type: text/html\n\n";
$c = new CGI;
$ta = $c->param('ta');

print <<EOF;
<html>
<body>
<textarea style="width: 100%; height: 200px">$ta</textarea>
$ta
</body>
</html>
EOF

Index: loncom/html/htmlarea/lang/b5.js
+++ loncom/html/htmlarea/lang/b5.js
// I18N constants -- Chinese Big-5
// by Dave Lo -- dlo@interactivetools.com
HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "b5",

	tooltips: {
		bold:           "²ÊÅé",
		italic:         "±×Åé",
		underline:      "©³½u",
		strikethrough:  "§R°£½u",
		subscript:      "¤U¼Ð",
		superscript:    "¤W¼Ð",
		justifyleft:    "¦ì¸m¾a¥ª",
		justifycenter:  "¦ì¸m©~¤¤",
		justifyright:   "¦ì¸m¾a¥k",
		justifyfull:    "¦ì¸m¥ª¥k¥­µ¥",
		orderedlist:    "¶¶§Ç²M³æ",
		unorderedlist:  "µL§Ç²M³æ",
		outdent:        "´î¤p¦æ«eªÅ¥Õ",
		indent:         "¥[¼e¦æ«eªÅ¥Õ",
		forecolor:      "¤å¦rÃC¦â",
		backcolor:      "­I´ºÃC¦â",
		horizontalrule: "¤ô¥­½u",
		createlink:     "´¡¤J³sµ²",
		insertimage:    "´¡¤J¹Ï§Î",
		inserttable:    "´¡¤Jªí®æ",
		htmlmode:       "¤Á´«HTML­ì©l½X",
		popupeditor:    "©ñ¤j",
		about:          "Ãö©ó HTMLArea",
		help:           "»¡©ú",
		textindicator:  "¦rÅé¨Ò¤l"
	}
};

Index: loncom/html/htmlarea/lang/da.js
+++ loncom/html/htmlarea/lang/da.js
// danish version for htmlArea v3.0 - Alpha Release
// - translated by rene<rene@laerke.net>
// term´s and licenses are equal to htmlarea!

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "da",

	tooltips: {
		bold:           "Fed",
		italic:         "Kursiv",
		underline:      "Understregning",
		strikethrough:  "Overstregning ",
		subscript:      "Sænket skrift",
		superscript:    "Hævet skrift",
		justifyleft:    "Venstrejuster",
		justifycenter:  "Centrer",
		justifyright:   "Højrejuster",
		justifyfull:    "Lige margener",
		orderedlist:    "Opstilling med tal",
		unorderedlist:  "Opstilling med punkttegn",
		outdent:        "Formindsk indrykning",
		indent:         "Forøg indrykning",
		forecolor:      "Skriftfarve",
		backcolor:      "Baggrundsfarve",
		horizontalrule: "Horisontal linie",
		createlink:     "Indsæt hyperlink",
		insertimage:    "Indsæt billede",
		inserttable:    "Indsæt tabel",
		htmlmode:       "HTML visning",
		popupeditor:    "Vis editor i popup",
		about:          "Om htmlarea",
		help:           "Hjælp",
		textindicator:  "Anvendt stil"
	}
};

Index: loncom/html/htmlarea/lang/de.js
+++ loncom/html/htmlarea/lang/de.js
// german version for htmlArea v3.0 - Alpha Release
// - translated by AtK<atk@chello.at>
// term´s and licenses are equal to htmlarea!

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "de",

	tooltips: {
		bold:           "Fett",
		italic:         "Kursiv",
		underline:      "Unterstrichen",
		strikethrough:  "Durchgestrichen",
		subscript:      "hochgestellt",
		superscript:    "tiefgestellt",
		justifyleft:    "Links ausrichten",
		justifycenter:  "Zentrieren",
		justifyright:   "Rechts ausrichten",
		justifyfull:    "Blocksatz",
		orderedlist:    "Nummerierung",
		unorderedlist:  "Aufzählungszeichen",
		outdent:        "Einzug verkleinern",
		indent:         "Einzug vergrössern",
		forecolor:      "Text Farbe",
		backcolor:      "Hintergrund Farbe",
		horizontalrule: "Horizontale Linie",
		createlink:     "Hyperlink einfügen",
		insertimage:    "Bild einfügen",
		inserttable:    "Tabelle einfügen",
		htmlmode:       "HTML Modus",
		popupeditor:    "Editor im Popup öffnen",
		about:          "Über htmlarea",
		help:           "Hilfe",
		textindicator:  "derzeitiger Stil"
	}
};

Index: loncom/html/htmlarea/lang/en.js
+++ loncom/html/htmlarea/lang/en.js
// I18N constants

// LANG: "en", ENCODING: UTF-8 | ISO-8859-1
// Author: Mihai Bazon, <mishoo@infoiasi.ro>

// FOR TRANSLATORS:
//
//   1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE
//      (at least a valid email address)
//
//   2. PLEASE TRY TO USE UTF-8 FOR ENCODING;
//      (if this is not possible, please include a comment
//       that states what encoding is necessary.)

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "en",

	tooltips: {
		bold:           "Bold",
		italic:         "Italic",
		underline:      "Underline",
		strikethrough:  "Strikethrough",
		subscript:      "Subscript",
		superscript:    "Superscript",
		justifyleft:    "Justify Left",
		justifycenter:  "Justify Center",
		justifyright:   "Justify Right",
		justifyfull:    "Justify Full",
		orderedlist:    "Ordered List",
		unorderedlist:  "Bulleted List",
		outdent:        "Decrease Indent",
		indent:         "Increase Indent",
		forecolor:      "Font Color",
		hilitecolor:    "Background Color",
		horizontalrule: "Horizontal Rule",
		createlink:     "Insert Web Link",
		insertimage:    "Insert Image",
		inserttable:    "Insert Table",
		htmlmode:       "Toggle HTML Source",
		popupeditor:    "Enlarge Editor",
		about:          "About this editor",
		showhelp:       "Help using editor",
		textindicator:  "Current style",
		undo:           "Undoes your last action",
		redo:           "Redoes your last action",
		cut:            "Cut selection",
		copy:           "Copy selection",
		paste:          "Paste from clipboard"
	},

	buttons: {
		"ok":           "OK",
		"cancel":       "Cancel"
	},

	msg: {
		"Path":         "Path",
		"TEXT_MODE":    "You are in TEXT MODE.  Use the [<>] button to switch back to WYSIWIG."
	}
};

Index: loncom/html/htmlarea/lang/es.js
+++ loncom/html/htmlarea/lang/es.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "es",

	tooltips: {
		bold:           "Negritas",
		italic:         "Cursiva",
		underline:      "Subrayado",
		strikethrough:  "Texto Cruzado",
		subscript:      "Subscript",
		superscript:    "Superscript",
		justifyleft:    "Alinear a la Izquierda",
		justifycenter:  "Centrar",
		justifyright:   "Alinear a la Derecha",
		justifyfull:    "Justificar",
		orderedlist:    "Lista Ordenada",
		unorderedlist:  "Lista No Ordenada",
		outdent:        "Aumentar Sangría",
		indent:         "Disminuir Sangría",
		forecolor:      "Color del Texto",
		backcolor:      "Color del Fondo",
		horizontalrule: "Línea Horizontal",
		createlink:     "Insertar Enlace",
		insertimage:    "Insertar Imagen",
		inserttable:    "Insertar Tabla",
		htmlmode:       "Ver Documento en HTML",
		popupeditor:    "Ampliar Editor",
		about:          "Acerca del Editor",
		help:           "Ayuda",
		textindicator:  "Estilo Actual"
	}
};

Index: loncom/html/htmlarea/lang/fi.js
+++ loncom/html/htmlarea/lang/fi.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "en",

	tooltips: {
		bold:           	"Lihavoitu",
		italic:         	"Kursivoitu",
		underline:      	"Alleviivattu",
		strikethrough:  	"Yliviivattu",
		subscript:      	"Alaindeksi",
		superscript:    	"Yläindeksi",
		justifyleft:    	"Tasaa vasemmat reunat",
		justifycenter:  	"Keskitä",
		justifyright:   	"Tasaa oikeat reunat",
		justifyfull:    	"Tasaa molemmat reunat",
		insertorderedlist: 	"Numerointi",
		insertunorderedlist: 	"Luettelomerkit",
		outdent:        	"Lisää sisennystä",
		indent:         	"Pienennä sisennystä",
		forecolor:      	"Fontin väri",
		hilitecolor:    	"Taustaväri",
		inserthorizontalrule: 	"Vaakaviiva",
		createlink:     	"Lisää Linkki",
		insertimage:    	"Lisää Kuva",
		inserttable:    	"Lisää Taulu",
		htmlmode:       	"HTML Lähdekoodi vs WYSIWYG",
		popupeditor:    	"Suurenna Editori",
		about:          	"Tietoja Editorista",
		showhelp:           	"Näytä Ohje",
		textindicator:  	"Nykyinen tyyli",
		undo:           	"Peruuta viimeinen toiminto",
		redo:           	"Palauta viimeinen toiminto",
		cut:            	"Leikkaa maalattu",
		copy:           	"Kopioi maalattu",
		paste:          	"Liitä leikepyödältä"
	},

	buttons: {
		"ok":           	"Hyväksy",
		"cancel":       	"Peruuta"
	}
};

Index: loncom/html/htmlarea/lang/fr.js
+++ loncom/html/htmlarea/lang/fr.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "fr",

	tooltips: {
		bold:           "Gras",
		italic:         "Italique",
		underline:      "Souligné",
		strikethrough:  "Barré",
		subscript:      "Subscript",
		superscript:    "Superscript",
		justifyleft:    "Aligné à gauche",
		justifycenter:  "Centré",
		justifyright:   "Aligné à droite",
		justifyfull:    "Justifié",
		orderedlist:    "Numérotation",
		unorderedlist:  "Puces",
		outdent:        "Augmenter le retrait",
		indent:         "Diminuer le retrait",
		forecolor:      "Couleur du texte",
		backcolor:      "Couleur du fond",
		horizontalrule: "Ligne horizontale",
		createlink:     "Insérer un lien",
		insertimage:    "Insérer une image",
		inserttable:    "Insérer un tableau",
		htmlmode:       "Passer au code source HTML",
		popupeditor:    "Agrandir l'éditeur",
		about:          "A propos de cet éditeur",
		help:           "Aide sur l'éditeur",
		textindicator:  "Style courant"
	}
};

Index: loncom/html/htmlarea/lang/gb.js
+++ loncom/html/htmlarea/lang/gb.js
// I18N constants -- Chinese GB
// by Dave Lo -- dlo@interactivetools.com
HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "gb",

	tooltips: {
		bold:           "´ÖÌå",
		italic:         "бÌå",
		underline:      "µ×Ïß",
		strikethrough:  "ɾ³ýÏß",
		subscript:      "챐",
		superscript:    "Éϱê",
		justifyleft:    "λÖÿ¿×ó",
		justifycenter:  "λÖþÓÖÐ",
		justifyright:   "λÖÿ¿ÓÒ",
		justifyfull:    "λÖÃ×óÓÒƽµÈ",
		orderedlist:    "˳ÐòÇåµ¥",
		unorderedlist:  "ÎÞÐòÇåµ¥",
		outdent:        "¼õСÐÐÇ°¿Õ°×",
		indent:         "¼Ó¿íÐÐÇ°¿Õ°×",
		forecolor:      "ÎÄ×ÖÑÕÉ«",
		backcolor:      "±³¾°ÑÕÉ«",
		horizontalrule: "ˮƽÏß",
		createlink:     "²åÈëÁ¬½á",
		insertimage:    "²åÈëͼÐÎ",
		inserttable:    "²åÈë±í¸ñ",
		htmlmode:       "Çл»HTMLԭʼÂë",
		popupeditor:    "·Å´ó",
		about:          "¹Øì¶ HTMLArea",
		help:           "˵Ã÷",
		textindicator:  "×ÖÌåÀý×Ó"
	}
};

Index: loncom/html/htmlarea/lang/it.js
+++ loncom/html/htmlarea/lang/it.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "it",

	tooltips: {
		bold:           "Grassetto",
		italic:         "Corsivo",
		underline:      "Sottolineato",
		strikethrough:  "Barrato",
		subscript:      "Pedice",
		superscript:    "Apice",
		justifyleft:    "Allinea a sinistra",
		justifycenter:  "Centra",
		justifyright:   "Allinea a destra",
		justifyfull:    "Giustifica",
		orderedlist:    "Elenco numerato",
		unorderedlist:  "Elenco puntato",
		outdent:        "Riduci rientro",
		indent:         "Aumenta rientro",
		forecolor:      "Colore carattere",
		backcolor:      "Colore di sfondo",
		horizontalrule: "Linea orizzontale",
		createlink:     "Inserisci collegamento ipertestuale",
		insertimage:    "Inserisci immagine",
		inserttable:    "Inserisci tabella",
		htmlmode:       "Passa alla visualizzazione HTML",
		popupeditor:    "Ingrandisci editor",
		about:          "Info",
		help:           "Aiuto",
		textindicator:  "Stile utilizzato"
	}
};

Index: loncom/html/htmlarea/lang/ja-euc.js
+++ loncom/html/htmlarea/lang/ja-euc.js
// I18N constants -- Japanese EUC
// by Manabu Onoue -- tmocsys@tmocsys.com

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "ja-euc",

	tooltips: {
		bold:           "ÂÀ»ú",
		italic:         "¼ÐÂÎ",
		underline:      "²¼Àþ",
		strikethrough:  "ÂǤÁ¾Ã¤·Àþ",
		subscript:      "²¼ÉÕ¤­Åº¤¨»ú",
		superscript:    "¾åÉÕ¤­Åº¤¨»ú",
		justifyleft:    "º¸´ó¤»",
		justifycenter:  "Ãæ±û´ó¤»",
		justifyright:   "±¦´ó¤»",
		justifyfull:    "¶ÑÅù³äÉÕ",
		orderedlist:    "ÈÖ¹æÉÕ¤­²Õ¾ò½ñ¤­",
		unorderedlist:  "µ­¹æÉÕ¤­²Õ¾ò½ñ¤­",
		outdent:        "¥¤¥ó¥Ç¥ó¥È²ò½ü",
		indent:         "¥¤¥ó¥Ç¥ó¥ÈÀßÄê",
		forecolor:      "ʸ»ú¿§",
		backcolor:      "ÇØ·Ê¿§",
		horizontalrule: "¿åÊ¿Àþ",
		createlink:     "¥ê¥ó¥¯ºîÀ®",
		insertimage:    "²èÁüÁÞÆþ",
		inserttable:    "¥Æ¡¼¥Ö¥ëÁÞÆþ",
		htmlmode:       "HTMLɽ¼¨ÀÚÂØ",
		popupeditor:    "¥¨¥Ç¥£¥¿³ÈÂç",
		about:          "¥Ð¡¼¥¸¥ç¥ó¾ðÊó",
		help:           "¥Ø¥ë¥×",
		textindicator:  "¸½ºß¤Î¥¹¥¿¥¤¥ë"
	}
};

Index: loncom/html/htmlarea/lang/ja-jis.js
+++ loncom/html/htmlarea/lang/ja-jis.js
// I18N constants -- Japanese JIS
// by Manabu Onoue -- tmocsys@tmocsys.com

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "ja-jis",

	tooltips: {
		bold:           "$BB@;z(B",
		italic:         "$B<PBN(B",
		underline:      "$B2<@~(B",
		strikethrough:  "$BBG$A>C$7@~(B",
		subscript:      "$B2<IU$-E:$(;z(B",
		superscript:    "$B>eIU$-E:$(;z(B",
		justifyleft:    "$B:84s$;(B",
		justifycenter:  "$BCf1{4s$;(B",
		justifyright:   "$B1&4s$;(B",
		justifyfull:    "$B6QEy3dIU(B",
		orderedlist:    "$BHV9fIU$-2U>r=q$-(B",
		unorderedlist:  "$B5-9fIU$-2U>r=q$-(B",
		outdent:        "$B%$%s%G%s%H2r=|(B",
		indent:         "$B%$%s%G%s%H@_Dj(B",
		forecolor:      "$BJ8;z?'(B",
		backcolor:      "$BGX7J?'(B",
		horizontalrule: "$B?eJ?@~(B",
		createlink:     "$B%j%s%/:n@.(B",
		insertimage:    "$B2hA|A^F~(B",
		inserttable:    "$B%F!<%V%kA^F~(B",
		htmlmode:       "HTML$BI=<(@ZBX(B",
		popupeditor:    "$B%(%G%#%?3HBg(B",
		about:          "$B%P!<%8%g%s>pJs(B",
		help:           "$B%X%k%W(B",
		textindicator:  "$B8=:_$N%9%?%$%k(B"
	}
};

Index: loncom/html/htmlarea/lang/ja-sjis.js
+++ loncom/html/htmlarea/lang/ja-sjis.js
// I18N constants -- Japanese Shift-JIS
// by Manabu Onoue -- tmocsys@tmocsys.com

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "ja-sjis",

	tooltips: {
		bold:           "‘¾Žš",
		italic:         "ŽÎ‘Ì",
		underline:      "伟",
		strikethrough:  "‘Å‚¿Á‚µü",
		subscript:      "‰º•t‚«“Y‚¦Žš",
		superscript:    "ã•t‚«“Y‚¦Žš",
		justifyleft:    "¶Šñ‚¹",
		justifycenter:  "’†‰›Šñ‚¹",
		justifyright:   "‰EŠñ‚¹",
		justifyfull:    "‹Ï“™Š„•t",
		orderedlist:    "”Ô†•t‚«‰Óð‘‚«",
		unorderedlist:  "‹L†•t‚«‰Óð‘‚«",
		outdent:        "ƒCƒ“ƒfƒ“ƒg‰ðœ",
		indent:         "ƒCƒ“ƒfƒ“ƒgÝ’è",
		forecolor:      "•¶ŽšF",
		backcolor:      "”wŒiF",
		horizontalrule: "…•½ü",
		createlink:     "ƒŠƒ“ƒNì¬",
		insertimage:    "‰æ‘œ‘}“ü",
		inserttable:    "ƒe[ƒuƒ‹‘}“ü",
		htmlmode:       "HTML•\Ž¦Ø‘Ö",
		popupeditor:    "ƒGƒfƒBƒ^Šg‘å",
		about:          "ƒo[ƒWƒ‡ƒ“î•ñ",
		help:           "ƒwƒ‹ƒv",
		textindicator:  "Œ»Ý‚̃Xƒ^ƒCƒ‹"
	}
};

Index: loncom/html/htmlarea/lang/ja-utf8.js
+++ loncom/html/htmlarea/lang/ja-utf8.js
// I18N constants -- Japanese UTF-8
// by Manabu Onoue -- tmocsys@tmocsys.com

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "ja-utf8",

	tooltips: {
		bold:           "太字",
		italic:         "斜体",
		underline:      "下線",
		strikethrough:  "打ã¡æ¶ˆã—ç·š",
		subscript:      "下付ãæ·»ãˆå­—",
		superscript:    "上付ãæ·»ãˆå­—",
		justifyleft:    "左寄ã›",
		justifycenter:  "中央寄ã›",
		justifyright:   "å³å¯„ã›",
		justifyfull:    "å‡ç­‰å‰²ä»˜",
		orderedlist:    "番å·ä»˜ã箇æ¡æ›¸ã",
		unorderedlist:  "記å·ä»˜ã箇æ¡æ›¸ã",
		outdent:        "インデント解除",
		indent:         "インデント設定",
		forecolor:      "文字色",
		backcolor:      "背景色",
		horizontalrule: "水平線",
		createlink:     "リンク作æˆ",
		insertimage:    "ç”»åƒæŒ¿å…¥",
		inserttable:    "テーブル挿入",
		htmlmode:       "HTML表示切替",
		popupeditor:    "エディタ拡大",
		about:          "ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…å ±",
		help:           "ヘルプ",
		textindicator:  "ç¾åœ¨ã®ã‚¹ã‚¿ã‚¤ãƒ«"
	}
};

Index: loncom/html/htmlarea/lang/nb.js
+++ loncom/html/htmlarea/lang/nb.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "nb",

	tooltips: {
		bold:           "Fet",
		italic:         "Kursiv",
		underline:      "Understreket",
		strikethrough:  "Gjennomstreket",
		subscript:      "Senket",
		superscript:    "Hevet",
		justifyleft:    "Venstrejuster",
		justifycenter:  "Midtjuster",
		justifyright:   "Høyrejuster",
		justifyfull:    "Blokkjuster",
		orderedlist:    "Nummerert liste",
		unorderedlist:  "Punktmerket liste",
		outdent:        "Øke innrykk",
		indent:         "Reduser innrykk",
		forecolor:      "Skriftfarge",
		backcolor:      "Bakgrunnsfarge",
		horizontalrule: "Horisontal linje",
		createlink:     "Sett inn lenke",
		insertimage:    "Sett inn bilde",
		inserttable:    "Sett inn tabell",
		htmlmode:       "Vis HTML kode",
		popupeditor:    "Forstørr redigeringsvindu",
		about:          "Om..",
		help:           "Hjelp",
		textindicator:  "Gjeldende stil"
	}
};

Index: loncom/html/htmlarea/lang/nl.js
+++ loncom/html/htmlarea/lang/nl.js
// Dutch version
// Author: Wouter Meeus alias Redspider <webmaster@tielt.be>

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "nl",

	tooltips: {
		bold:           "Vet",
		italic:         "Cursief",
		underline:      "Onderlijnen",
		strikethrough:  "Doorstrepen",
		subscript:      "Subscript",
		superscript:    "Superscript",
		justifyleft:    "Links Uitlijnen",
		justifycenter:  "Centreren",
		justifyright:   "Rechts Uitlijnen",
		justifyfull:    "Uitvullen",
		orderedlist:    "Nummering",
		unorderedlist:  "Opsomming",
		outdent:        "Verklein insprong",
		indent:         "Vergroot insprong",
		forecolor:      "Tekst Kleur",
		backcolor:      "Achtergrond Kleur",
		horizontalrule: "Horizontale lijn",
		createlink:     "Hyperlink invoegen",
		insertimage:    "Afbeelding invoegen",
		inserttable:    "Tabel invoegen",
		htmlmode:       "HTML broncode",
		popupeditor:    "Vergroot Editor",
		about:          "Over deze editor",
		help:           "Help",
		textindicator:  "Huidige stijl"
	}
};

Index: loncom/html/htmlarea/lang/pl.js
+++ loncom/html/htmlarea/lang/pl.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "pl",

	tooltips: {
		bold:           "Pogrubienie",
		italic:         "Pochylenie",
		underline:      "Podkreœlenie",
		strikethrough:  "Przekreœlenie",
		subscript:      "Indeks dolny",
		superscript:    "Indeks górny",
		justifyleft:    "Wyrównaj do lewej",
		justifycenter:  "Wyœrodkuj",
		justifyright:   "Wyrównaj do prawej",
		justifyfull:    "Wyjustuj",
		orderedlist:    "Numerowanie",
		unorderedlist:  "Wypunktowanie",
		outdent:        "Zmniejsz wciêcie",
		indent:         "Zwiêksz wciêcie",
		forecolor:      "Kolor czcionki",
		backcolor:      "Kolor t³a",
		horizontalrule: "Linia pozioma",
		createlink:     "Wstaw adres sieci Web",
		insertimage:    "Wstaw obraz",
		inserttable:    "Wstaw tabelê",
		htmlmode:       "Edycja WYSIWYG/w Ÿródle strony",
		popupeditor:    "Pe³ny ekran",
		about:          "Informacje o tym edytorze",
		help:           "Pomoc",
		textindicator:  "Obecny styl"
	}
};

Index: loncom/html/htmlarea/lang/pt_br.js
+++ loncom/html/htmlarea/lang/pt_br.js
// I18N constants
// Brazilian Portuguese Translation by Alex Piaz <webmaster@globalmap.com>

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "pt_br",

	tooltips: {
		bold:           "Negrito",
		italic:         "Itálico",
		underline:      "Sublinhado",
		strikethrough:  "Tachado",
		subscript:      "Subescrito",
		superscript:    "Sobrescrito",
		justifyleft:    "Alinhar à Esquerda",
		justifycenter:  "Centralizar",
		justifyright:   "Alinhar à Direita",
		justifyfull:    "Justificar",
		orderedlist:    "Lista Numerada",
		unorderedlist:  "Lista Marcadores",
		outdent:        "Diminuir Indentação",
		indent:         "Aumentar Indentação",
		forecolor:      "Cor da Fonte",
		backcolor:      "Cor do Fundo",
		horizontalrule: "Linha Horizontal",
		createlink:     "Inserir Link",
		insertimage:    "Inserir Imagem",
		inserttable:    "Inserir Tabela",
		htmlmode:       "Ver Código-Fonte",
		popupeditor:    "Expandir Editor",
		about:          "Sobre",
		help:           "Ajuda",
		textindicator:  "Estilo Atual"
	}
};

Index: loncom/html/htmlarea/lang/ro.js
+++ loncom/html/htmlarea/lang/ro.js
// I18N constants

// LANG: "ro", ENCODING: UTF-8
// Author: Mihai Bazon, <mishoo@infoiasi.ro>

// FOR TRANSLATORS:
//
//   1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE
//      (at least a valid email address)
//
//   2. PLEASE TRY TO USE UTF-8 FOR ENCODING;
//      (if this is not possible, please include a comment
//       that states what encoding is necessary.)

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "ro",

	tooltips: {
		bold:           "ÃŽngroÅŸat",
		italic:         "Italic",
		underline:      "Subliniat",
		strikethrough:  "Tăiat",
		subscript:      "Subscript",
		superscript:    "Superscript",
		justifyleft:    "Aliniere la stânga",
		justifycenter:  "Aliniere pe centru",
		justifyright:   "Aliniere la dreapta",
		justifyfull:    "Aliniere în ambele părţi",
		orderedlist:    "Listă ordonată",
		unorderedlist:  "Listă marcată",
		outdent:        "Micşorează alineatul",
		indent:         "Măreşte alineatul",
		forecolor:      "Culoarea textului",
		hilitecolor:    "Culoare de fundal",
		horizontalrule: "Linie orizontală",
		createlink:     "Inserează link",
		insertimage:    "Inserează o imagine",
		inserttable:    "Inserează un tabel",
		htmlmode:       "Sursa HTML / WYSIWYG",
		popupeditor:    "Maximizează editorul",
		about:          "Despre editor",
		showhelp:       "Documentaţie (devel)",
		textindicator:  "Stilul curent",
		undo:           "Anulează ultima acţiune",
		redo:           "Reface ultima acţiune anulată",
		cut:            "Taie în clipboard",
		copy:           "Copie în clipboard",
		paste:          "Aduce din clipboard"
	},

	buttons: {
		"ok":           "OK",
		"cancel":       "Anulează"
	},

	msg: {
		"Path":         "Calea",
		"TEXT_MODE":    "Eşti în modul TEXT.  Apasă butonul [<>] pentru a te întoarce în modul WYSIWYG."
	}
};

Index: loncom/html/htmlarea/lang/ru.js
+++ loncom/html/htmlarea/lang/ru.js
// I18N constants

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "ru",

	tooltips: {
		bold:           "Æèðíûé",
		italic:         "Íàêëîííûé",
		underline:      "Ïîä÷åðêíóòûé",
		strikethrough:  "Ïåðå÷åðêíóòûé",
		subscript:      "Íèæíèé èíäåêñ",
		superscript:    "Âåðõíèé èíäåêñ",
		justifyleft:    "Âûðàâíèâàíèå ïî ëåâîìó êðàþ",
		justifycenter:  "Âûðàâíèâàíèå ïî öåíòðó",
		justifyright:   "Âûðàâíèâàíèå ïî ïðàâîìó êðàþ",
		justifyfull:    "Ðàñòÿíóòûé òåêñò",
		orderedlist:    "Íóìåðîâàííûé ñïèñîê",
		unorderedlist:  "Ìàðêèðîâàííûé ñïèñîê",
		outdent:        "Ñäâèã â ëåâî",
		indent:         "Ñäâèã â ïðàâî",
		forecolor:      "Öâåò øðèôòà",
		backcolor:      "Öâåò ôîíà",
		horizontalrule: "Ãîðèçîíòàëüíàÿ ëèíèÿ",
		createlink:     "Âñòàâèòü ññûëêó",
		insertimage:    "Âñòàâèòü êàðòèíêó",
		inserttable:    "Âñòàâèòü òàáëèöó",
		htmlmode:       "Âèäåòü HTML êîä",
		popupeditor:    "Óâåëè÷èòü ðåäàêòîð",
		about:          "Î ðåäàêòîðå",
		help:           "Ïîìîùü â èñïîëüçîâàíèè",
		textindicator:  "Äàííûé ñòèëü"
	}
};

Index: loncom/html/htmlarea/lang/se.js
+++ loncom/html/htmlarea/lang/se.js
// Swedish version for htmlArea v3.0 - Alpha Release
// - translated by pat<pat@engvall.nu>
// term´s and licenses are equal to htmlarea!

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "se",

	tooltips: {
		bold:           "Fet",
		italic:         "Kursiv",
		underline:      "Understruken",
		strikethrough:  "Genomstruken",
		subscript:      "Nedsänkt",
		superscript:    "Upphöjd",
		justifyleft:    "Vänsterjustera",
		justifycenter:  "Centrera",
		justifyright:   "Högerjustera",
		justifyfull:    "Marginaljustera",
		orderedlist:    "Numrerad lista",
		unorderedlist:  "Punktlista",
		outdent:        "Minska indrag",
		indent:         "Öka indrag",
		forecolor:      "Textfärg",
		backcolor:      "Bakgrundsfärg",
		horizontalrule: "Vågrät linje",
		createlink:     "Infoga länk",
		insertimage:    "Infoga bild",
		inserttable:    "Infoga tabell",
		htmlmode:       "Visa källkod",
		popupeditor:    "Visa i eget fönster",
		about:          "Om denna editor",
		help:           "Hjälp",
		textindicator:  "Nuvarande stil"
	}
};

Index: loncom/html/htmlarea/lang/vn.js
+++ loncom/html/htmlarea/lang/vn.js
// I18N constants : Vietnamese
// mviet: download the free Vietnamese script addon for htmlArea at: www.mviet.org
// email: mviet@socal.rr.com

HTMLArea.I18N = {

	// the following should be the filename without .js extension
	// it will be used for automatically load plugin language.
	lang: "vn",

	tooltips: {
		bold:           "Äậm",
		italic:         "Nghiêng",
		underline:      "Gạch Äít",
		strikethrough:  "Gạch Xóa",
		subscript:      "Viết Xuống Dưới",
		superscript:    "Viết Lên Trên ",
		justifyleft:    "Ngay Hàng Bên Trái  ",
		justifycenter:  "Ngay Hàng Giữa",
		justifyright:   "Ngay Hàng Lên Phải",
		justifyfull:    "Ngay Hàng Trái & Phải",
		orderedlist:    "Chuỗi Thứ Tự 123",
		unorderedlist:  "Chuỗi Nút",
		outdent:        "Giảm Vào Hàng",
		indent:         "Tăng Vào Hàng",
		forecolor:      "Màu Chữ",
		backcolor:      "Màu Ná»n",
		horizontalrule: "ThÆ°á»›c Ngang",
		createlink:     "Tạo Nối",
		insertimage:    "Mang Hình Vô",
		inserttable:    "Mang Khuôn Vô",
		htmlmode:       "Bật / Tắt Nguồn HTML",
		popupeditor:    "Póp Lớn Khung Viết",
		about:          "Nói VỠChương Trình",
		help:           "Giúp Äỡ",
		textindicator:  "Loại Kiểu Viết"
	}
};

Index: loncom/html/htmlarea/plugins/SpellChecker/readme-tech.html
+++ loncom/html/htmlarea/plugins/SpellChecker/readme-tech.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.2//EN">
<html>
  <head>
    <title>HTMLArea Spell Checker</title>
  </head>

  <body>
    <h1>HTMLArea Spell Checker</h1>

    <p>The HTMLArea Spell Checker subsystem consists of the following
      files:</p>

    <ul>

      <li>spell-checker.js &mdash; the spell checker plugin interface for
        HTMLArea</li>

      <li>spell-checker-ui.html &mdash; the HTML code for the user
        interface</li>

      <li>spell-checker-ui.js &mdash; functionality of the user
        interface</li>

      <li>spell-checker-logic.cgi &mdash; Perl CGI script that checks a text
        given through POST for spelling errors</li>

      <li>spell-checker-style.css &mdash; style for mispelled words</li>

      <li>lang/en.js &mdash; main language file (English).</li>

    </ul>

    <h2>Process overview</h2>

    <p>
      When an end-user clicks the "spell-check" button in the HTMLArea
      editor, a new window is opened with the URL of "spell-check-ui.html".
      This window initializes itself with the text found in the editor (uses
      <tt>window.opener.SpellChecker.editor</tt> global variable) and it
      submits the text to the server-side script "spell-check-logic.cgi".
      The target of the FORM is an inline frame which is used both to
      display the text and correcting.
    </p>

    <p>
      Further, spell-check-logic.cgi calls Aspell for each portion of plain
      text found in the given HTML.  It rebuilds an HTML file that contains
      clear marks of which words are incorrect, along with suggestions for
      each of them.  This file is then loaded in the inline frame.  Upon
      loading, a JavaScript function from "spell-check-ui.js" is called.
      This function will retrieve all mispelled words from the HTML of the
      iframe and will setup the user interface so that it allows correction.
    </p>

    <h2>The server-side script (spell-check-logic.cgi)</h2>

    <p>
      <strong>Unicode safety</strong> &mdash; the program <em>is</em>
      Unicode safe.  HTML entities are expanded into their corresponding
      Unicode characters.  These characters will be matched as part of the
      word passed to Aspell.  All texts passed to Aspell are in Unicode
      (when appropriate).  However, Aspell seems to not support Unicode
      yet (<a
        href="http://mail.gnu.org/archive/html/aspell-user/2000-11/msg00007.html">thread concerning Aspell and Unicode</a>).
      This mean that words containing Unicode
      characters that are not in 0..255 are likely to be reported as "mispelled" by Aspell.
    </p>

    <p>
      I digged the Net for a couple of hours today and I can't seem to find
      any open-source spell checker that has Unicode support.  For this
      reason we keep using Aspell, because it also seems to have the
      best suggestions engine.  Unicode support will eventually be
      implemented in Aspell.  <a href="mailto:kevin@atkinson.dhs.org">Email
        Kevin Atkinson</a> (Aspell author and maintainer) about this ;-)
    </p>

    <p>
      The Perl Unicode manual (man perluniintro) states:
    </p>

    <blockquote>
      <em>
        Starting from Perl 5.6.0, Perl has had the capacity to handle Unicode
        natively.  Perl 5.8.0, however, is the first recommended release for
        serious Unicode work.  The maintenance release 5.6.1 fixed many of the
        problems of the initial Unicode implementation, but for example regular
        expressions still do not work with Unicode in 5.6.1.
      </em>
    </blockquote>

    <p>In other words, do <em>not</em> assume that this script is
      Unicode-safe on Perl interpreters older than 5.8.0.</p>

    <p>The following Perl modules are required:</p>

    <ul>
      <li><a href="http://search.cpan.org/search?query=Text%3A%3AAspell&mode=all" target="_blank">Text::Aspell</a></li>
      <li><a href="http://search.cpan.org/search?query=HTML%3A%3AParser&mode=all" target="_blank">HTML::Parser</a></li>
      <li><a href="http://search.cpan.org/search?query=HTML%3A%3AEntities&mode=all" target="_blank">HTML::Entities</a></li>
      <li><a href="http://search.cpan.org/search?query=CGI&mode=all" target="_blank">CGI</a></li>
    </ul>

    <p>Of these, only Text::Aspell might need to be installed manually.  The
      others are likely to be available by default in most Perl distributions.</p>

    <hr />
    <address><a href="http://students.infoiasi.ro/~mishoo/">Mihai Bazon</a></address>
<!-- Created: Thu Jul 17 13:22:27 EEST 2003 -->
<!-- hhmts start -->
Last modified on Sun Aug 10 12:28:24 2003
<!-- hhmts end -->
<!-- doc-lang: English -->
  </body>
</html>

Index: loncom/html/htmlarea/plugins/SpellChecker/spell-check-logic.cgi
+++ loncom/html/htmlarea/plugins/SpellChecker/spell-check-logic.cgi
#! /usr/bin/perl -w

# Spell Checker Plugin for HTMLArea-3.0
# Implementation by Mihai Bazon.  Sponsored by www.americanbible.org
#
# htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
# This notice MUST stay intact for use (see license.txt).
#
# A free WYSIWYG editor replacement for <textarea> fields.
# For full source code and docs, visit http://www.interactivetools.com/
#
# Version 3.0 developed by Mihai Bazon for InteractiveTools.
#	     http://students.infoiasi.ro/~mishoo
#
# $Id: spell-check-logic.cgi,v 1.1 2004/02/18 08:07:15 www Exp $

use strict;
use utf8;
use Encode;
use Text::Aspell;
use HTML::Parser;
use HTML::Entities;
use CGI;

my $debug = 0;

open (DEBUG, '>:encoding(UTF-8)', '> /tmp/spell-check-debug.log') if $debug;

# use Data::Dumper; # for debug only

my $speller = new Text::Aspell;
my $cgi = new CGI;

# FIXME: report a nice error...
die "Can't create speller!" unless $speller;

# add configurable option for this
my $dict = $cgi->param('dictionary') || 'en_US';
$speller->set_option('lang', $dict);

# ultra, fast, normal, bad-spellers
# bad-spellers seems to cause segmentation fault
$speller->set_option('sug-mode', 'ultra');

my @replacements = ();

sub text_handler {
    my ($offset, $length, $text, $is_cdata) = @_;
    if ($is_cdata or $text =~ /^\s*$/) {
        return 0;
    }
    # print STDERR "*** OFFSET: $offset, LENGTH: $length, $text\n";
    $text = decode_entities($text);
    $text =~ s/&#([0-9]+);/chr($1)/eg;
    $text =~ s/&#x([0-9a-fA-F]+);/chr(hex $1)/eg;
    my $repl = spellcheck($text);
    if ($repl) {
        push(@replacements, [ $offset, $length, $repl ]);
    }
}

my $p = HTML::Parser->new
  (api_version => 3,
   handlers => { start => [ sub {
                                my ($self, $tagname, $attrs) = @_;
                                # print STDERR "\033[1;31m parsing tag: $tagname\033[0m\n";
                                # following we skip words that have already been marked as "fixed".
                                if ($tagname eq "span" and $attrs->{class} =~ /HA-spellcheck-fixed/) {
                                    $self->handler(text => undef);
                                }
                            }, "self, tagname, attr"
                          ],
                 end => [ sub {
                              my ($self, $tagname) = @_;
                              # print STDERR "\033[1;32m END tag: $tagname\033[0m\n";
                              $self->handler(text => \&text_handler, 'offset, length, dtext, is_cdata');
                          }, "self, tagname"
                        ]
               }
  );
$p->handler(text => \&text_handler, 'offset, length, dtext, is_cdata');
$p->case_sensitive(1);
my $file_content = $cgi->param('content');

if ($debug) {
    open (FOO, '>:encoding(UTF-8)', '/tmp/spell-check-before');
    print FOO $file_content, "\n";
    close(FOO);
}

$p->parse($file_content);
$p->eof();

foreach (reverse @replacements) {
    substr($file_content, $_->[0], $_->[1], $_->[2]);
}

# we output UTF-8
binmode(STDOUT, ':encoding(UTF-8)'); # apparently, this sucks.
print "Content-type: text/html; charset: utf-8\n\n";
print qq^
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" media="all" href="spell-check-style.css" />
</head>
<body onload="window.parent.finishedSpellChecking();">^;

print $file_content;
if ($cgi->param('init') eq '1') {
    my @dicts = $speller->dictionary_info();
    my $dictionaries = '';
    foreach my $i (@dicts) {
        $dictionaries .= ',' . $i->{name} unless $i->{jargon};
    }
    $dictionaries =~ s/^,//;
    print qq^
<div id="HA-spellcheck-dictionaries"
>$dictionaries</div>
^;
}

if ($debug) {
    open (FOO, '>:encoding(UTF-8)', '/tmp/spell-check-after');
    print FOO $file_content, "\n";
    close(FOO);
}

print '</body></html>';

# Perl is beautiful.
sub spellcheck {
    my $text = shift;
    sub check {                 # called for each word in the text
        # input is in UTF-8
        my $U_word = shift;
        my $word = encode($speller->get_option('encoding'), $U_word);
        print DEBUG "*$U_word* ----> |$word|\n" if $debug;
        if ($speller->check($word)) {
            return $U_word;      # we return the word in UTF-8
        } else {
            # we should have suggestions; give them back to browser in UTF-8
            my $suggestions = decode($speller->get_option('encoding'), join(',', $speller->suggest($word)));
            my $ret = '<span class="HA-spellcheck-error">'.$U_word.'</span><span class="HA-spellcheck-suggestions">'.$suggestions.'</span>';
            return $ret;
        }
    }
    $text =~ s/([[:word:]']+)/check($1)/egs;
    # $text =~ s/(\w+)/check($1)/egs;

    # the following is definitely what we want to use; too bad it sucks most.
    # $text =~ s/(\p{IsWord}+)/check($1)/egs;
    return $text;
}

Index: loncom/html/htmlarea/plugins/SpellChecker/spell-check-style.css
+++ loncom/html/htmlarea/plugins/SpellChecker/spell-check-style.css
.HA-spellcheck-error { border-bottom: 2px dotted #f00; cursor: default; }
.HA-spellcheck-same { background-color: #ff8; color: #000; }
.HA-spellcheck-hover { background-color: #433; color: white; }
.HA-spellcheck-fixed { border-bottom: 1px dotted #0b8; }
.HA-spellcheck-current { background-color: #7be; color: #000; }
.HA-spellcheck-suggestions { display: none; }

#HA-spellcheck-dictionaries { display: none; }

a:link, a:visited { color: #55e; }

Index: loncom/html/htmlarea/plugins/SpellChecker/spell-check-ui.html
+++ loncom/html/htmlarea/plugins/SpellChecker/spell-check-ui.html
<!--

  Strangely, IE sucks with or without the DOCTYPE switch.
  I thought it would only suck without it.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

   Spell Checker Plugin for HTMLArea-3.0
   Implementation by Mihai Bazon.  Sponsored by www.americanbible.org
  
   htmlArea v3.0 - Copyright (c) 2003 interactivetools.com, inc.
   This notice MUST stay intact for use (see license.txt).
  
   A free WYSIWYG editor replacement for <textarea> fields.
   For full source code and docs, visit http://www.interactivetools.com/
  
   Version 3.0 developed by Mihai Bazon for InteractiveTools.
  	     http://students.infoiasi.ro/~mishoo
  
   $Id: spell-check-ui.html,v 1.1 2004/02/18 08:07:15 www Exp $

-->
<html xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <title>Spell Checker</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="spell-check-ui.js"></script>

    <style type="text/css">
      html, body { height: 100%; margin: 0px; padding: 0px; background-color: #fff;
      color: #000; }
      a:link, a:visited { color: #00f; text-decoration: none; }
      a:hover { color: #f00; text-decoration: underline; }

      table { background-color: ButtonFace; color: ButtonText;
      font-family: tahoma,verdana,sans-serif; font-size: 11px; }

      iframe { background-color: #fff; color: #000; }

      .controls { width: 13em; }
      .controls .sectitle { /* background-color: #736c6c; color: #fff;
      border-top: 1px solid #000; border-bottom: 1px solid #fff; */
      text-align: center;
      font-weight: bold; padding: 2px 4px; }
      .controls .secbody { margin-bottom: 10px; }

      button, select { font-family: tahoma,verdana,sans-serif; font-size: 11px; }
      button { width: 6em; padding: 0px; }

      input, select { font-family: fixed,"andale mono",monospace; }

      #v_currentWord { color: #f00; font-weight: bold; font-size: 120%; }
      #statusbar { padding: 7px 0px 0px 5px; }
      #status { font-weight: bold; }
    </style>

  </head>

  <body onload="initDocument()">

    <form style="display: none;" action="spell-check-logic.cgi"
        method="post" target="framecontent"
        accept-charset="utf-8"
        ><input type="hidden" name="content" id="f_content"
        /><input type="hidden" name="dictionary" id="f_dictionary"
        /><input type="hidden" name="init" id="f_init" value="1"
        /></form>

    <table style="height: 100%; width: 100%; border-collapse: collapse;" cellspacing="0" cellpadding="0">
      <tr>
        <td colspan="2" style="height: 1em; padding: 2px;">
          <div style="float: right; padding: 2px;"><span>Dictionary</span>
            <select id="v_dictionaries" style="width: 10em"></select>
            <button id="b_recheck">Re-check</button>
          </div>
          <span id="status">Please wait.  Calling spell checker.</span>
        </td>
      </tr>
      <tr>
        <td valign="top" class="controls">
          <div class="sectitle">Original word</div>
          <div class="secbody" id="v_currentWord" style="text-align: center">pliz weit ;-)</div>
          <div class="sectitle">Replace with</div>
          <div class="secbody">
            <input type="text" id="v_replacement" style="width: 94%; margin-left: 3%;" /><br />
            <div style="text-align: center; margin-top: 2px;">
              <button id="b_replace">Replace</button><button
                id="b_replall">Replace all</button><br /><button
                id="b_ignore">Ignore</button><button
                id="b_ignall">Ignore all</button>
            </div>
          </div>
          <div class="sectitle">Suggestions</div>
          <div class="secbody">
            <select size="11" style="width: 94%; margin-left: 3%;" id="v_suggestions"></select>
          </div>
        </td>

        <td>
          <iframe src="about:blank" width="100%" height="100%"
            id="i_framecontent" name="framecontent"></iframe>
        </td>
      </tr>
      <tr>
        <td style="height: 1em;" colspan="2">
          <div style="padding: 4px 2px 2px 2px; float: right;">
            <button id="b_ok">OK</button>
            <button id="b_cancel">Cancel</button>
          </div>
          <div id="statusbar"></div>
        </td>
      </tr>
    </table>

  </body>

</html>

Index: loncom/html/htmlarea/plugins/SpellChecker/spell-check-ui.js
+++ loncom/html/htmlarea/plugins/SpellChecker/spell-check-ui.js
// Spell Checker Plugin for HTMLArea-3.0
// Implementation by Mihai Bazon.  Sponsored by www.americanbible.org
//
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
// This notice MUST stay intact for use (see license.txt).
//
// A free WYSIWYG editor replacement for <textarea> fields.
// For full source code and docs, visit http://www.interactivetools.com/
//
// Version 3.0 developed by Mihai Bazon for InteractiveTools.
//	     http://students.infoiasi.ro/~mishoo
//
// $Id: spell-check-ui.js,v 1.1 2004/02/18 08:07:15 www Exp $

// internationalization file was already loaded in parent ;-)
var SpellChecker = window.opener.SpellChecker;
var i18n = SpellChecker.I18N;

var is_ie = window.opener.HTMLArea.is_ie;
var editor = SpellChecker.editor;
var frame = null;
var currentElement = null;
var wrongWords = null;
var modified = false;
var allWords = {};

function makeCleanDoc(leaveFixed) {
	// document.getElementById("status").innerHTML = 'Please wait: rendering valid HTML';
	for (var i in wrongWords) {
		var el = wrongWords[i];
		if (!(leaveFixed && /HA-spellcheck-fixed/.test(el.className))) {
			el.parentNode.insertBefore(el.firstChild, el);
			el.parentNode.removeChild(el.nextSibling);
			el.parentNode.removeChild(el);
		} else {
			el.className = "HA-spellcheck-fixed";
			el.parentNode.removeChild(el.nextSibling);
		}
	}
	// we should use innerHTML here, but IE6's implementation fucks up the
	// HTML to such extent that our poor Perl parser doesn't understand it
	// anymore.
	return window.opener.HTMLArea.getHTML(frame.contentWindow.document.body, leaveFixed);
};

function recheckClicked() {
	document.getElementById("status").innerHTML = i18n["Please wait: changing dictionary to"] + ': "' + document.getElementById("f_dictionary").value + '".';
	var field = document.getElementById("f_content");
	field.value = makeCleanDoc(true);
	field.form.submit();
};

function saveClicked() {
	if (modified) {
		editor.setHTML(makeCleanDoc(false));
	}
	window.close();
	return false;
};

function cancelClicked() {
	var ok = true;
	if (modified) {
		ok = confirm(i18n["QUIT_CONFIRMATION"]);
	}
	if (ok) {
		window.close();
	}
	return false;
};

function replaceWord(el) {
	var replacement = document.getElementById("v_replacement").value;
	modified = (el.innerHTML != replacement);
	if (el) {
		el.className = el.className.replace(/\s*HA-spellcheck-(hover|fixed)\s*/g, " ");
	}
	el.className += " HA-spellcheck-fixed";
	el.__msh_fixed = true;
	if (!modified) {
		return false;
	}
	el.innerHTML = replacement;
};

function replaceClicked() {
	replaceWord(currentElement);
	var start = currentElement.__msh_id;
	var index = start;
	do {
		++index;
		if (index == wrongWords.length) {
			index = 0;
		}
	} while ((index != start) && wrongWords[index].__msh_fixed);
	if (index == start) {
		index = 0;
		alert(i18n["Finished list of mispelled words"]);
	}
	wrongWords[index].onclick();
	return false;
};

function replaceAllClicked() {
	var replacement = document.getElementById("v_replacement").value;
	var ok = true;
	var spans = allWords[currentElement.__msh_origWord];
	if (spans.length == 0) {
		alert("An impossible condition just happened.  Call FBI.  ;-)");
	} else if (spans.length == 1) {
		replaceClicked();
		return false;
	}
	/*
	var message = "The word \"" + currentElement.__msh_origWord + "\" occurs " + spans.length + " times.\n";
	if (replacement == currentElement.__msh_origWord) {
		ok = confirm(message + "Ignore all occurrences?");
	} else {
		ok = confirm(message + "Replace all occurrences with \"" + replacement + "\"?");
	}
	*/
	if (ok) {
		for (var i in spans) {
			if (spans[i] != currentElement) {
				replaceWord(spans[i]);
			}
		}
		// replace current element the last, so that we jump to the next word ;-)
		replaceClicked();
	}
	return false;
};

function ignoreClicked() {
	document.getElementById("v_replacement").value = currentElement.__msh_origWord;
	replaceClicked();
	return false;
};

function ignoreAllClicked() {
	document.getElementById("v_replacement").value = currentElement.__msh_origWord;
	replaceAllClicked();
	return false;
};

function learnClicked() {
	alert("Not [yet] implemented");
	return false;
};

function internationalizeWindow() {
	var types = ["div", "span", "button"];
	for (var i in types) {
		var tag = types[i];
		var els = document.getElementsByTagName(tag);
		for (var j = els.length; --j >= 0;) {
			var el = els[j];
			if (el.childNodes.length == 1 && /\S/.test(el.innerHTML)) {
				var txt = el.innerHTML;
				if (typeof i18n[txt] != "undefined") {
					el.innerHTML = i18n[txt];
				}
			}
		}
	}
};

function initDocument() {
	internationalizeWindow();
	modified = false;
	frame = document.getElementById("i_framecontent");
	var field = document.getElementById("f_content");
	field.value = editor.getHTML();
	field.form.submit();
	document.getElementById("f_init").value = "0";

	// assign some global event handlers

	var select = document.getElementById("v_suggestions");
	select.onchange = function() {
		document.getElementById("v_replacement").value = this.value;
	};
	if (is_ie) {
		select.attachEvent("ondblclick", replaceClicked);
	} else {
		select.addEventListener("dblclick", replaceClicked, true);
	}

	document.getElementById("b_replace").onclick = replaceClicked;
	// document.getElementById("b_learn").onclick = learnClicked;
	document.getElementById("b_replall").onclick = replaceAllClicked;
	document.getElementById("b_ignore").onclick = ignoreClicked;
	document.getElementById("b_ignall").onclick = ignoreAllClicked;
	document.getElementById("b_recheck").onclick = recheckClicked;

	document.getElementById("b_ok").onclick = saveClicked;
	document.getElementById("b_cancel").onclick = cancelClicked;

	select = document.getElementById("v_dictionaries");
	select.onchange = function() {
		document.getElementById("f_dictionary").value = this.value;
	};
};

function wordClicked() {
	if (currentElement) {
		var a = allWords[currentElement.__msh_origWord];
		currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " ");
		for (var i in a) {
			var el = a[i];
			if (el != currentElement) {
				el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " ");
			}
		}
	}
	currentElement = this;
	this.className += " HA-spellcheck-current";
	var a = allWords[currentElement.__msh_origWord];
	for (var i in a) {
		var el = a[i];
		if (el != currentElement) {
			el.className += " HA-spellcheck-same";
		}
	}
	document.getElementById("b_replall").disabled = (a.length <= 1);
	document.getElementById("b_ignall").disabled = (a.length <= 1);
	var txt;
	if (a.length == 1) {
		txt = "one occurrence";
	} else if (a.length == 2) {
		txt = "two occurrences";
	} else {
		txt = a.length + " occurrences";
	}
	document.getElementById("statusbar").innerHTML = "Found " + txt +
		' for word "<b>' + currentElement.__msh_origWord + '</b>"';
	var select = document.getElementById("v_suggestions");
	for (var i = select.length; --i >= 0;) {
		select.remove(i);
	}
	var suggestions;
	suggestions = this.nextSibling.firstChild.data.split(/,/);
	for (var i = 0; i < suggestions.length; ++i) {
		var txt = suggestions[i];
		var option = document.createElement("option");
		option.value = txt;
		option.appendChild(document.createTextNode(txt));
		select.appendChild(option);
	}
	document.getElementById("v_currentWord").innerHTML = this.__msh_origWord;
	if (suggestions.length > 0) {
		select.selectedIndex = 0;
		select.onchange();
	} else {
		document.getElementById("v_replacement").value = this.innerHTML;
	}
	return false;
};

function wordMouseOver() {
	this.className += " HA-spellcheck-hover";
};

function wordMouseOut() {
	this.className = this.className.replace(/\s*HA-spellcheck-hover\s*/g, " ");
};

function finishedSpellChecking() {
	// initialization of global variables
	currentElement = null;
	wrongWords = null;
	allWords = {};

	document.getElementById("status").innerHTML = "HTMLArea Spell Checker (<a href='readme-tech.html' target='_blank' title='Technical information'>info</a>)";
	var doc = frame.contentWindow.document;
        var spans = doc.getElementsByTagName("span");
        var sps = [];
	var id = 0;
        for (var i = 0; i < spans.length; ++i) {
                var el = spans[i];
                if (/HA-spellcheck-error/.test(el.className)) {
                        sps.push(el);
			el.onclick = wordClicked;
			el.onmouseover = wordMouseOver;
			el.onmouseout = wordMouseOut;
			el.__msh_id = id++;
			var txt = (el.__msh_origWord = el.firstChild.data);
			el.__msh_fixed = false;
			if (typeof allWords[txt] == "undefined") {
				allWords[txt] = [el];
			} else {
				allWords[txt].push(el);
			}
                }
        }
	wrongWords = sps;
	if (sps.length == 0) {
		if (!modified) {
			alert(i18n["NO_ERRORS_CLOSING"]);
			window.close();
		} else {
			alert(i18n["NO_ERRORS"]);
		}
		return false;
	}
	(currentElement = sps[0]).onclick();
	var as = doc.getElementsByTagName("a");
	for (var i = as.length; --i >= 0;) {
		var a = as[i];
		a.onclick = function() {
			if (confirm(i18n["CONFIRM_LINK_CLICK"] + ":\n" +
				    this.href + "\n" + i18n["I will open it in a new page."])) {
				window.open(this.href);
			}
			return false;
		};
	}
	var dicts = doc.getElementById("HA-spellcheck-dictionaries");
	if (dicts) {
		dicts.parentNode.removeChild(dicts);
		dicts = dicts.innerHTML.split(/,/);
		var select = document.getElementById("v_dictionaries");
		for (var i = select.length; --i >= 0;) {
			select.remove(i);
		}
		for (var i = 0; i < dicts.length; ++i) {
			var txt = dicts[i];
			var option = document.createElement("option");
			option.value = txt;
			option.appendChild(document.createTextNode(txt));
			select.appendChild(option);
		}
	}
};

Index: loncom/html/htmlarea/plugins/SpellChecker/spell-checker.js
+++ loncom/html/htmlarea/plugins/SpellChecker/spell-checker.js
// Spell Checker Plugin for HTMLArea-3.0
// Implementation by Mihai Bazon.  Sponsored by www.americanbible.org
//
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
// This notice MUST stay intact for use (see license.txt).
//
// A free WYSIWYG editor replacement for <textarea> fields.
// For full source code and docs, visit http://www.interactivetools.com/
//
// Version 3.0 developed by Mihai Bazon for InteractiveTools.
//	     http://students.infoiasi.ro/~mishoo
//
// $Id: spell-checker.js,v 1.1 2004/02/18 08:07:15 www Exp $

function SpellChecker(editor) {
	this.editor = editor;

	var cfg = editor.config;
	var tt = SpellChecker.I18N;
	var bl = SpellChecker.btnList;
	var self = this;

	// register the toolbar buttons provided by this plugin
	var toolbar = [];
	for (var i in bl) {
		var btn = bl[i];
		if (!btn) {
			toolbar.push("separator");
		} else {
			var id = "SC-" + btn[0];
			cfg.registerButton(id, tt[id], "plugins/SpellChecker/img/" + btn[0] + ".gif", false,
					   function(editor, id) {
						   // dispatch button press event
						   self.buttonPress(editor, id);
					   }, btn[1]);
			toolbar.push(id);
		}
	}

	for (var i in toolbar) {
		cfg.toolbar[0].push(toolbar[i]);
	}
};

SpellChecker.btnList = [
	null, // separator
	["spell-check"]
	];

SpellChecker.prototype.buttonPress = function(editor, id) {
	switch (id) {
	    case "SC-spell-check":
		SpellChecker.editor = editor;
		SpellChecker.init = true;
		var uiurl = editor.config.editorURL + "plugins/SpellChecker/spell-check-ui.html";
		var win;
		if (HTMLArea.is_ie) {
			win = window.open(uiurl, "SC_spell_checker",
					  "toolbar=no,location=no,directories=no,status=no,menubar=no," +
					  "scrollbars=no,resizable=yes,width=600,height=400");
		} else {
			win = window.open(uiurl, "SC_spell_checker",
					  "toolbar=no,menubar=no,personalbar=no,width=600,height=400," +
					  "scrollbars=no,resizable=yes");
		}
		win.focus();
		break;
	}
};

// this needs to be global, it's accessed from spell-check-ui.html
SpellChecker.editor = null;

Index: loncom/html/htmlarea/plugins/SpellChecker/lang/en.js
+++ loncom/html/htmlarea/plugins/SpellChecker/lang/en.js
// I18N constants

// LANG: "en", ENCODING: UTF-8 | ISO-8859-1
// Author: Mihai Bazon, <mishoo@infoiasi.ro>

// FOR TRANSLATORS:
//
//   1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE
//      (at least a valid email address)
//
//   2. PLEASE TRY TO USE UTF-8 FOR ENCODING;
//      (if this is not possible, please include a comment
//       that states what encoding is necessary.)

SpellChecker.I18N = {
	"CONFIRM_LINK_CLICK"                    : "Please confirm that you want to open this link",
	"Cancel"                                : "Cancel",
	"Dictionary"                            : "Dictionary",
	"Finished list of mispelled words"      : "Finished list of mispelled words",
	"I will open it in a new page."         : "I will open it in a new page.",
	"Ignore all"                            : "Ignore all",
	"Ignore"                                : "Ignore",
	"NO_ERRORS"                             : "No mispelled words found with the selected dictionary.",
	"NO_ERRORS_CLOSING"                     : "Spell check complete, didn't find any mispelled words.  Closing now...",
	"OK"                                    : "OK",
	"Original word"                         : "Original word",
	"Please wait.  Calling spell checker."  : "Please wait.  Calling spell checker.",
	"Please wait: changing dictionary to"   : "Please wait: changing dictionary to",
	"QUIT_CONFIRMATION"                     : "This will drop changes and quit spell checker.  Please confirm.",
	"Re-check"                              : "Re-check",
	"Replace all"                           : "Replace all",
	"Replace with"                          : "Replace with",
	"Replace"                               : "Replace",
	"SC-spell-check"                        : "Spell-check",
	"Suggestions"                           : "Suggestions",
	"pliz weit ;-)"                         : "pliz weit ;-)"
};

Index: loncom/html/htmlarea/plugins/SpellChecker/lang/ro.js
+++ loncom/html/htmlarea/plugins/SpellChecker/lang/ro.js
// I18N constants

// LANG: "ro", ENCODING: UTF-8
// Author: Mihai Bazon, <mishoo@infoiasi.ro>

// FOR TRANSLATORS:
//
//   1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE
//      (at least a valid email address)
//
//   2. PLEASE TRY TO USE UTF-8 FOR ENCODING;
//      (if this is not possible, please include a comment
//       that states what encoding is necessary.)

SpellChecker.I18N = {
	"CONFIRM_LINK_CLICK"                    : "Vă rog confirmaţi că vreţi să deschideţi acest link",
	"Cancel"                                : "Anulează",
	"Dictionary"                            : "Dicţionar",
	"Finished list of mispelled words"      : "Am terminat lista de cuvinte greÅŸite",
	"I will open it in a new page."         : "O voi deschide într-o altă fereastră.",
	"Ignore all"                            : "Ignoră toate",
	"Ignore"                                : "Ignoră",
	"NO_ERRORS"                             : "Nu am găsit nici un cuvânt greşit cu acest dicţionar.",
	"NO_ERRORS_CLOSING"                     : "Am terminat, nu am detectat nici o greşeală.  Acum închid fereastra...",
	"OK"                                    : "OK",
	"Original word"                         : "Cuvântul original",
	"Please wait.  Calling spell checker."  : "Vă rog aşteptaţi.  Apelez spell-checker-ul.",
	"Please wait: changing dictionary to"   : "Vă rog aşteptaţi.  Schimb dicţionarul cu",
	"QUIT_CONFIRMATION"                     : "Doriţi să renunţaţi la modificări şi să închid spell-checker-ul?",
	"Re-check"                              : "Scanează",
	"Replace all"                           : "ÃŽnlocuieÅŸte toate",
	"Replace with"                          : "ÃŽnlocuieÅŸte cu",
	"Replace"                               : "ÃŽnlocuieÅŸte",
	"SC-spell-check"                        : "Detectează greşeli",
	"Suggestions"                           : "Sugestii",
	"pliz weit ;-)"                         : "va rog ashteptatzi ;-)"
};

Index: loncom/html/htmlarea/plugins/TableOperations/table-operations.js
+++ loncom/html/htmlarea/plugins/TableOperations/table-operations.js
// Table Operations Plugin for HTMLArea-3.0
// Implementation by Mihai Bazon.  Sponsored by http://www.bloki.com
//
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
// This notice MUST stay intact for use (see license.txt).
//
// A free WYSIWYG editor replacement for <textarea> fields.
// For full source code and docs, visit http://www.interactivetools.com/
//
// Version 3.0 developed by Mihai Bazon for InteractiveTools.
//	     http://students.infoiasi.ro/~mishoo
//
// $Id: table-operations.js,v 1.1 2004/02/18 08:07:16 www Exp $

// Object that will encapsulate all the table operations provided by
// HTMLArea-3.0 (except "insert table" which is included in the main file)
function TableOperations(editor) {
	this.editor = editor;

	var cfg = editor.config;
	var tt = TableOperations.I18N;
	var bl = TableOperations.btnList;
	var self = this;

	// register the toolbar buttons provided by this plugin
	var toolbar = ["linebreak"];
	for (var i in bl) {
		var btn = bl[i];
		if (!btn) {
			toolbar.push("separator");
		} else {
			var id = "TO-" + btn[0];
			cfg.registerButton(id, tt[id], "plugins/TableOperations/img/" + btn[0] + ".gif", false,
					   function(editor, id) {
						   // dispatch button press event
						   self.buttonPress(editor, id);
					   }, btn[1]);
			toolbar.push(id);
		}
	}

	// add a new line in the toolbar
	cfg.toolbar.push(toolbar);
};

/************************
 * UTILITIES
 ************************/

// retrieves the closest element having the specified tagName in the list of
// ancestors of the current selection/caret.
TableOperations.prototype.getClosest = function(tagName) {
	var editor = this.editor;
	var ancestors = editor.getAllAncestors();
	var ret = null;
	tagName = ("" + tagName).toLowerCase();
	for (var i in ancestors) {
		var el = ancestors[i];
		if (el.tagName.toLowerCase() == tagName) {
			ret = el;
			break;
		}
	}
	return ret;
};

// this function requires the file PopupDiv/PopupWin to be loaded from browser
TableOperations.prototype.dialogTableProperties = function() {
	var i18n = TableOperations.I18N;
	// retrieve existing values
	var table = this.getClosest("table");
	// this.editor.selectNodeContents(table);
	// this.editor.updateToolbar();

	var dialog = new PopupWin(this.editor, i18n["Table Properties"], function(dialog, params) {
		TableOperations.processStyle(params, table);
		for (var i in params) {
			var val = params[i];
			switch (i) {
			    case "f_caption":
				if (/\S/.test(val)) {
					// contains non white-space characters
					var caption = table.getElementsByTagName("caption")[0];
					if (!caption) {
						caption = dialog.editor._doc.createElement("caption");
						table.insertBefore(caption, table.firstChild);
					}
					caption.innerHTML = val;
				} else {
					// search for caption and delete it if found
					var caption = table.getElementsByTagName("caption")[0];
					if (caption) {
						caption.parentNode.removeChild(caption);
					}
				}
				break;
			    case "f_summary":
				table.summary = val;
				break;
			    case "f_width":
				table.style.width = ("" + val) + params.f_unit;
				break;
			    case "f_align":
				table.align = val;
				break;
			    case "f_spacing":
				table.cellSpacing = val;
				break;
			    case "f_padding":
				table.cellPadding = val;
				break;
			    case "f_borders":
				table.border = val;
				break;
			    case "f_frames":
				table.frame = val;
				break;
			    case "f_rules":
				table.rules = val;
				break;
			}
		}
		// various workarounds to refresh the table display (Gecko,
		// what's going on?! do not disappoint me!)
		dialog.editor.forceRedraw();
		dialog.editor.focusEditor();
		dialog.editor.updateToolbar();
		var save_collapse = table.style.borderCollapse;
		table.style.borderCollapse = "collapse";
		table.style.borderCollapse = "separate";
		table.style.borderCollapse = save_collapse;
	},

	// this function gets called when the dialog needs to be initialized
	function (dialog) {

		var f_caption = "";
		var capel = table.getElementsByTagName("caption")[0];
		if (capel) {
			f_caption = capel.innerHTML;
		}
		var f_summary = table.summary;
		var f_width = parseInt(table.style.width);
		isNaN(f_width) && (f_width = "");
		var f_unit = /%/.test(table.style.width) ? 'percent' : 'pixels';
		var f_align = table.align;
		var f_spacing = table.cellSpacing;
		var f_padding = table.cellPadding;
		var f_borders = table.border;
		var f_frames = table.frame;
		var f_rules = table.rules;

		function selected(val) {
			return val ? " selected" : "";
		};

		// dialog contents
		dialog.content.style.width = "400px";
		dialog.content.innerHTML = " \
<div class='title'\
 style='background: url(" + dialog.baseURL + dialog.editor.imgURL("table-prop.gif", "TableOperations") + ") #fff 98% 50% no-repeat'>" + i18n["Table Properties"] + "\
</div> \
<table style='width:100%'> \
  <tr> \
    <td> \
      <fieldset><legend>" + i18n["Description"] + "</legend> \
       <table style='width:100%'> \
        <tr> \
          <td class='label'>" + i18n["Caption"] + ":</td> \
          <td class='value'><input type='text' name='f_caption' value='" + f_caption + "'/></td> \
        </tr><tr> \
          <td class='label'>" + i18n["Summary"] + ":</td> \
          <td class='value'><input type='text' name='f_summary' value='" + f_summary + "'/></td> \
        </tr> \
       </table> \
      </fieldset> \
    </td> \
  </tr> \
  <tr><td id='--HA-layout'></td></tr> \
  <tr> \
    <td> \
      <fieldset><legend>" + i18n["Spacing and padding"] + "</legend> \
       <table style='width:100%'> \
"+//        <tr> \
//           <td class='label'>" + i18n["Width"] + ":</td> \
//           <td><input type='text' name='f_width' value='" + f_width + "' size='5' /> \
//             <select name='f_unit'> \
//               <option value='%'" + selected(f_unit == "percent") + ">" + i18n["percent"] + "</option> \
//               <option value='px'" + selected(f_unit == "pixels") + ">" + i18n["pixels"] + "</option> \
//             </select> &nbsp;&nbsp;" + i18n["Align"] + ": \
//             <select name='f_align'> \
//               <option value='left'" + selected(f_align == "left") + ">" + i18n["Left"] + "</option> \
//               <option value='center'" + selected(f_align == "center") + ">" + i18n["Center"] + "</option> \
//               <option value='right'" + selected(f_align == "right") + ">" + i18n["Right"] + "</option> \
//             </select> \
//           </td> \
//         </tr> \
"        <tr> \
          <td class='label'>" + i18n["Spacing"] + ":</td> \
          <td><input type='text' name='f_spacing' size='5' value='" + f_spacing + "' /> &nbsp;" + i18n["Padding"] + ":\
            <input type='text' name='f_padding' size='5' value='" + f_padding + "' /> &nbsp;&nbsp;" + i18n["pixels"] + "\
          </td> \
        </tr> \
       </table> \
      </fieldset> \
    </td> \
  </tr> \
  <tr> \
    <td> \
      <fieldset><legend>Frame and borders</legend> \
        <table width='100%'> \
          <tr> \
            <td class='label'>" + i18n["Borders"] + ":</td> \
            <td><input name='f_borders' type='text' size='5' value='" + f_borders + "' /> &nbsp;&nbsp;" + i18n["pixels"] + "</td> \
          </tr> \
          <tr> \
            <td class='label'>" + i18n["Frames"] + ":</td> \
            <td> \
              <select name='f_frames'> \
                <option value='void'" + selected(f_frames == "void") + ">" + i18n["No sides"] + "</option> \
                <option value='above'" + selected(f_frames == "above") + ">" + i18n["The top side only"] + "</option> \
                <option value='below'" + selected(f_frames == "below") + ">" + i18n["The bottom side only"] + "</option> \
                <option value='hsides'" + selected(f_frames == "hsides") + ">" + i18n["The top and bottom sides only"] + "</option> \
                <option value='vsides'" + selected(f_frames == "vsides") + ">" + i18n["The right and left sides only"] + "</option> \
                <option value='lhs'" + selected(f_frames == "lhs") + ">" + i18n["The left-hand side only"] + "</option> \
                <option value='rhs'" + selected(f_frames == "rhs") + ">" + i18n["The right-hand side only"] + "</option> \
                <option value='box'" + selected(f_frames == "box") + ">" + i18n["All four sides"] + "</option> \
              </select> \
            </td> \
          </tr> \
          <tr> \
            <td class='label'>" + i18n["Rules"] + ":</td> \
            <td> \
              <select name='f_rules'> \
                <option value='none'" + selected(f_rules == "none") + ">" + i18n["No rules"] + "</option> \
                <option value='rows'" + selected(f_rules == "rows") + ">" + i18n["Rules will appear between rows only"] + "</option> \
                <option value='cols'" + selected(f_rules == "cols") + ">" + i18n["Rules will appear between columns only"] + "</option> \
                <option value='all'" + selected(f_rules == "all") + ">" + i18n["Rules will appear between all rows and columns"] + "</option> \
              </select> \
            </td> \
          </tr> \
        </table> \
      </fieldset> \
    </td> \
  </tr> \
  <tr> \
    <td id='--HA-style'></td> \
  </tr> \
</table> \
";
		var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, table);
		var p = dialog.doc.getElementById("--HA-style");
		p.appendChild(st_prop);
		var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, table);
		p = dialog.doc.getElementById("--HA-layout");
		p.appendChild(st_layout);
		dialog.modal = true;
		dialog.addButtons("ok", "cancel");
		dialog.showAtElement(dialog.editor._iframe, "c");
	});
};

// this function requires the file PopupDiv/PopupWin to be loaded from browser
TableOperations.prototype.dialogRowCellProperties = function(cell) {
	var i18n = TableOperations.I18N;
	// retrieve existing values
	var element = this.getClosest(cell ? "td" : "tr");
	var table = this.getClosest("table");
	// this.editor.selectNodeContents(element);
	// this.editor.updateToolbar();

	var dialog = new PopupWin(this.editor, i18n[cell ? "Cell Properties" : "Row Properties"], function(dialog, params) {
		TableOperations.processStyle(params, element);
		for (var i in params) {
			var val = params[i];
			switch (i) {
			    case "f_align":
				element.align = val;
				break;
			    case "f_char":
				element.ch = val;
				break;
			    case "f_valign":
				element.vAlign = val;
				break;
			}
		}
		// various workarounds to refresh the table display (Gecko,
		// what's going on?! do not disappoint me!)
		dialog.editor.forceRedraw();
		dialog.editor.focusEditor();
		dialog.editor.updateToolbar();
		var save_collapse = table.style.borderCollapse;
		table.style.borderCollapse = "collapse";
		table.style.borderCollapse = "separate";
		table.style.borderCollapse = save_collapse;
	},

	// this function gets called when the dialog needs to be initialized
	function (dialog) {

		var f_align = element.align;
		var f_valign = element.vAlign;
		var f_char = element.ch;

		function selected(val) {
			return val ? " selected" : "";
		};

		// dialog contents
		dialog.content.style.width = "400px";
		dialog.content.innerHTML = " \
<div class='title'\
 style='background: url(" + dialog.baseURL + dialog.editor.imgURL(cell ? "cell-prop.gif" : "row-prop.gif", "TableOperations") + ") #fff 98% 50% no-repeat'>" + i18n[cell ? "Cell Properties" : "Row Properties"] + "</div> \
<table style='width:100%'> \
  <tr> \
    <td id='--HA-layout'> \
"+//      <fieldset><legend>" + i18n["Layout"] + "</legend> \
//        <table style='width:100%'> \
//         <tr> \
//           <td class='label'>" + i18n["Align"] + ":</td> \
//           <td> \
//             <select name='f_align'> \
//               <option value='left'" + selected(f_align == "left") + ">" + i18n["Left"] + "</option> \
//               <option value='center'" + selected(f_align == "center") + ">" + i18n["Center"] + "</option> \
//               <option value='right'" + selected(f_align == "right") + ">" + i18n["Right"] + "</option> \
//               <option value='char'" + selected(f_align == "char") + ">" + i18n["Char"] + "</option> \
//             </select> \
//             &nbsp;&nbsp;" + i18n["Char"] + ": \
//             <input type='text' style='font-family: monospace; text-align: center' name='f_char' size='1' value='" + f_char + "' /> \
//           </td> \
//         </tr><tr> \
//           <td class='label'>" + i18n["Vertical align"] + ":</td> \
//           <td> \
//             <select name='f_valign'> \
//               <option value='top'" + selected(f_valign == "top") + ">" + i18n["Top"] + "</option> \
//               <option value='middle'" + selected(f_valign == "middle") + ">" + i18n["Middle"] + "</option> \
//               <option value='bottom'" + selected(f_valign == "bottom") + ">" + i18n["Bottom"] + "</option> \
//               <option value='baseline'" + selected(f_valign == "baseline") + ">" + i18n["Baseline"] + "</option> \
//             </select> \
//           </td> \
//         </tr> \
//        </table> \
//       </fieldset> \
"    </td> \
  </tr> \
  <tr> \
    <td id='--HA-style'></td> \
  </tr> \
</table> \
";
		var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, element);
		var p = dialog.doc.getElementById("--HA-style");
		p.appendChild(st_prop);
		var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, element);
		p = dialog.doc.getElementById("--HA-layout");
		p.appendChild(st_layout);
		dialog.modal = true;
		dialog.addButtons("ok", "cancel");
		dialog.showAtElement(dialog.editor._iframe, "c");
	});
};

// this function gets called when some button from the TableOperations toolbar
// was pressed.
TableOperations.prototype.buttonPress = function(editor, button_id) {
	this.editor = editor;
	var mozbr = HTMLArea.is_gecko ? "<br />" : "";
	var i18n = TableOperations.I18N;

	// helper function that clears the content in a table row
	function clearRow(tr) {
		var tds = tr.getElementsByTagName("td");
		for (var i = tds.length; --i >= 0;) {
			var td = tds[i];
			td.rowSpan = 1;
			td.innerHTML = mozbr;
		}
	};

	function splitRow(td) {
		var n = parseInt("" + td.rowSpan);
		var nc = parseInt("" + td.colSpan);
		td.rowSpan = 1;
		tr = td.parentNode;
		var itr = tr.rowIndex;
		var trs = tr.parentNode.rows;
		var index = td.cellIndex;
		while (--n > 0) {
			tr = trs[++itr];
			var otd = editor._doc.createElement("td");
			otd.colSpan = td.colSpan;
			otd.innerHTML = mozbr;
			tr.insertBefore(otd, tr.cells[index]);
		}
		editor.forceRedraw();
		editor.updateToolbar();
	};

	function splitCol(td) {
		var nc = parseInt("" + td.colSpan);
		td.colSpan = 1;
		tr = td.parentNode;
		var ref = td.nextSibling;
		while (--nc > 0) {
			var otd = editor._doc.createElement("td");
			otd.rowSpan = td.rowSpan;
			otd.innerHTML = mozbr;
			tr.insertBefore(otd, ref);
		}
		editor.forceRedraw();
		editor.updateToolbar();
	};

	function splitCell(td) {
		var nc = parseInt("" + td.colSpan);
		splitCol(td);
		var items = td.parentNode.cells;
		var index = td.cellIndex;
		while (nc-- > 0) {
			splitRow(items[index++]);
		}
	};

	function selectNextNode(el) {
		var node = el.nextSibling;
		while (node && node.nodeType != 1) {
			node = node.nextSibling;
		}
		if (!node) {
			node = el.previousSibling;
			while (node && node.nodeType != 1) {
				node = node.previousSibling;
			}
		}
		if (!node) {
			node = el.parentNode;
		}
		editor.selectNodeContents(node);
	};

	switch (button_id) {
		// ROWS

	    case "TO-row-insert-above":
	    case "TO-row-insert-under":
		var tr = this.getClosest("tr");
		if (!tr) {
			break;
		}
		var otr = tr.cloneNode(true);
		clearRow(otr);
		tr.parentNode.insertBefore(otr, /under/.test(button_id) ? tr.nextSibling : tr);
		editor.forceRedraw();
		editor.focusEditor();
		break;
	    case "TO-row-delete":
		var tr = this.getClosest("tr");
		if (!tr) {
			break;
		}
		var par = tr.parentNode;
		if (par.rows.length == 1) {
			alert(i18n["not-del-last-row"]);
			break;
		}
		// set the caret first to a position that doesn't
		// disappear.
		selectNextNode(tr);
		par.removeChild(tr);
		editor.forceRedraw();
		editor.focusEditor();
		editor.updateToolbar();
		break;
	    case "TO-row-split":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		splitRow(td);
		break;

		// COLUMNS

	    case "TO-col-insert-before":
	    case "TO-col-insert-after":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		var rows = td.parentNode.parentNode.rows;
		var index = td.cellIndex;
		for (var i = rows.length; --i >= 0;) {
			var tr = rows[i];
			var ref = tr.cells[index + (/after/.test(button_id) ? 1 : 0)];
			var otd = editor._doc.createElement("td");
			otd.innerHTML = mozbr;
			tr.insertBefore(otd, ref);
		}
		editor.focusEditor();
		break;
	    case "TO-col-split":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		splitCol(td);
		break;
	    case "TO-col-delete":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		var index = td.cellIndex;
		if (td.parentNode.cells.length == 1) {
			alert(i18n["not-del-last-col"]);
			break;
		}
		// set the caret first to a position that doesn't disappear
		selectNextNode(td);
		var rows = td.parentNode.parentNode.rows;
		for (var i = rows.length; --i >= 0;) {
			var tr = rows[i];
			tr.removeChild(tr.cells[index]);
		}
		editor.forceRedraw();
		editor.focusEditor();
		editor.updateToolbar();
		break;

		// CELLS

	    case "TO-cell-split":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		splitCell(td);
		break;
	    case "TO-cell-insert-before":
	    case "TO-cell-insert-after":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		var tr = td.parentNode;
		var otd = editor._doc.createElement("td");
		otd.innerHTML = mozbr;
		tr.insertBefore(otd, /after/.test(button_id) ? td.nextSibling : td);
		editor.forceRedraw();
		editor.focusEditor();
		break;
	    case "TO-cell-delete":
		var td = this.getClosest("td");
		if (!td) {
			break;
		}
		if (td.parentNode.cells.length == 1) {
			alert(i18n["not-del-last-cell"]);
			break;
		}
		// set the caret first to a position that doesn't disappear
		selectNextNode(td);
		td.parentNode.removeChild(td);
		editor.forceRedraw();
		editor.updateToolbar();
		break;
	    case "TO-cell-merge":
		// !! FIXME: Mozilla specific !!
		var sel = editor._getSelection();
		var range, i = 0;
		var rows = [];
		var row = null;
		var cells = null;
		if (!HTMLArea.is_ie) {
			try {
				while (range = sel.getRangeAt(i++)) {
					var td = range.startContainer.childNodes[range.startOffset];
					if (td.parentNode != row) {
						row = td.parentNode;
						(cells) && rows.push(cells);
						cells = [];
					}
					cells.push(td);
				}
			} catch(e) {/* finished walking through selection */}
			rows.push(cells);
		} else {
			// Internet Explorer "browser"
			var td = this.getClosest("td");
			if (!td) {
				alert(i18n["Please click into some cell"]);
				break;
			}
			var tr = td.parentElement;
			var no_cols = prompt(i18n["How many columns would you like to merge?"], 2);
			if (!no_cols) {
				// cancelled
				break;
			}
			var no_rows = prompt(i18n["How many rows would you like to merge?"], 2);
			if (!no_rows) {
				// cancelled
				break;
			}
			var cell_index = td.cellIndex;
			while (no_rows-- > 0) {
				td = tr.cells[cell_index];
				cells = [td];
				for (var i = 1; i < no_cols; ++i) {
					td = td.nextSibling;
					if (!td) {
						break;
					}
					cells.push(td);
				}
				rows.push(cells);
				tr = tr.nextSibling;
				if (!tr) {
					break;
				}
			}
		}
		var HTML = "";
		for (i = 0; i < rows.length; ++i) {
			// i && (HTML += "<br />");
			var cells = rows[i];
			for (var j = 0; j < cells.length; ++j) {
				// j && (HTML += "&nbsp;");
				var cell = cells[j];
				HTML += cell.innerHTML;
				(i || j) && (cell.parentNode.removeChild(cell));
			}
		}
		var td = rows[0][0];
		td.innerHTML = HTML;
		td.rowSpan = rows.length;
		td.colSpan = rows[0].length;
		editor.selectNodeContents(td);
		editor.forceRedraw();
		editor.focusEditor();
		break;

		// PROPERTIES

	    case "TO-table-prop":
		this.dialogTableProperties();
		break;

	    case "TO-row-prop":
		this.dialogRowCellProperties(false);
		break;

	    case "TO-cell-prop":
		this.dialogRowCellProperties(true);
		break;

	    default:
		alert("Button [" + button_id + "] not yet implemented");
	}
};

// the list of buttons added by this plugin
TableOperations.btnList = [
	// table properties button
	["table-prop",       "table"],
	null,			// separator

	// ROWS
	["row-prop",         "tr"],
	["row-insert-above", "tr"],
	["row-insert-under", "tr"],
	["row-delete",       "tr"],
	["row-split",        "td[rowSpan!=1]"],
	null,

	// COLS
	["col-insert-before", "td"],
	["col-insert-after",  "td"],
	["col-delete",        "td"],
	["col-split",         "td[colSpan!=1]"],
	null,

	// CELLS
	["cell-prop",          "td"],
	["cell-insert-before", "td"],
	["cell-insert-after",  "td"],
	["cell-delete",        "td"],
	["cell-merge",         "tr"],
	["cell-split",         "td[colSpan!=1,rowSpan!=1]"]
	];



//// GENERIC CODE [style of any element; this should be moved into a separate
//// file as it'll be very useful]
//// BEGIN GENERIC CODE -----------------------------------------------------

TableOperations.getLength = function(value) {
	var len = parseInt(value);
	if (isNaN(len)) {
		len = "";
	}
	return len;
};

// Applies the style found in "params" to the given element.
TableOperations.processStyle = function(params, element) {
	var style = element.style;
	for (var i in params) {
		var val = params[i];
		switch (i) {
		    case "f_st_backgroundColor":
			style.backgroundColor = val;
			break;
		    case "f_st_color":
			style.color = val;
			break;
		    case "f_st_backgroundImage":
			if (/\S/.test(val)) {
				style.backgroundImage = "url(" + val + ")";
			} else {
				style.backgroundImage = "none";
			}
			break;
		    case "f_st_borderWidth":
			style.borderWidth = val;
			break;
		    case "f_st_borderStyle":
			style.borderStyle = val;
			break;
		    case "f_st_borderColor":
			style.borderColor = val;
			break;
		    case "f_st_borderCollapse":
			style.borderCollapse = val ? "collapse" : "";
			break;
		    case "f_st_width":
			if (/\S/.test(val)) {
				style.width = val + params["f_st_widthUnit"];
			} else {
				style.width = "";
			}
			break;
		    case "f_st_height":
			if (/\S/.test(val)) {
				style.height = val + params["f_st_heightUnit"];
			} else {
				style.height = "";
			}
			break;
		    case "f_st_textAlign":
			if (val == "char") {
				var ch = params["f_st_textAlignChar"];
				if (ch == '"') {
					ch = '\\"';
				}
				style.textAlign = '"' + ch + '"';
			} else {
				style.textAlign = val;
			}
			break;
		    case "f_st_verticalAlign":
			style.verticalAlign = val;
			break;
		    case "f_st_float":
			style.cssFloat = val;
			break;
// 		    case "f_st_margin":
// 			style.margin = val + "px";
// 			break;
// 		    case "f_st_padding":
// 			style.padding = val + "px";
// 			break;
		}
	}
};

// Returns an HTML element for a widget that allows color selection.  That is,
// a button that contains the given color, if any, and when pressed will popup
// the sooner-or-later-to-be-rewritten select_color.html dialog allowing user
// to select some color.  If a color is selected, an input field with the name
// "f_st_"+name will be updated with the color value in #123456 format.
TableOperations.createColorButton = function(doc, editor, color, name) {
	if (!color) {
		color = "";
	} else if (!/#/.test(color)) {
		color = HTMLArea._colorToRgb(color);
	}

	var df = doc.createElement("span");
 	var field = doc.createElement("input");
	field.type = "hidden";
	df.appendChild(field);
 	field.name = "f_st_" + name;
	field.value = color;
	var button = doc.createElement("span");
	button.className = "buttonColor";
	df.appendChild(button);
	var span = doc.createElement("span");
	span.className = "chooser";
	// span.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
	span.style.backgroundColor = color;
	button.appendChild(span);
	button.onmouseover = function() { if (!this.disabled) { this.className += " buttonColor-hilite"; }};
	button.onmouseout = function() { if (!this.disabled) { this.className = "buttonColor"; }};
	span.onclick = function() {
		if (this.parentNode.disabled) {
			return false;
		}
		editor._popupDialog("select_color.html", function(color) {
			if (color) {
				span.style.backgroundColor = "#" + color;
				field.value = "#" + color;
			}
		}, color);
	};
	var span2 = doc.createElement("span");
	span2.innerHTML = "&#x00d7;";
	span2.className = "nocolor";
	span2.title = TableOperations.I18N["Unset color"];
	button.appendChild(span2);
	span2.onmouseover = function() { if (!this.parentNode.disabled) { this.className += " nocolor-hilite"; }};
	span2.onmouseout = function() { if (!this.parentNode.disabled) { this.className = "nocolor"; }};
	span2.onclick = function() {
		span.style.backgroundColor = "";
		field.value = "";
	};
	return df;
};

TableOperations.createStyleLayoutFieldset = function(doc, editor, el) {
	var i18n = TableOperations.I18N;
	var fieldset = doc.createElement("fieldset");
	var legend = doc.createElement("legend");
	fieldset.appendChild(legend);
	legend.innerHTML = i18n["Layout"];
	var table = doc.createElement("table");
	fieldset.appendChild(table);
	table.style.width = "100%";
	var tbody = doc.createElement("tbody");
	table.appendChild(tbody);

	var tagname = el.tagName.toLowerCase();
	var tr, td, input, select, option, options, i;

	if (tagname != "td" && tagname != "tr" && tagname != "th") {
		tr = doc.createElement("tr");
		tbody.appendChild(tr);
		td = doc.createElement("td");
		td.className = "label";
		tr.appendChild(td);
		td.innerHTML = i18n["Float"] + ":";
		td = doc.createElement("td");
		tr.appendChild(td);
		select = doc.createElement("select");
		td.appendChild(select);
		select.name = "f_st_float";
		options = ["None", "Left", "Right"];
		for (i in options) {
			var Val = options[i];
			var val = options[i].toLowerCase();
			option = doc.createElement("option");
			option.innerHTML = i18n[Val];
			option.value = val;
			option.selected = (("" + el.style.cssFloat).toLowerCase() == val);
			select.appendChild(option);
		}
	}

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	td.className = "label";
	tr.appendChild(td);
	td.innerHTML = i18n["Width"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	input = doc.createElement("input");
	input.type = "text";
	input.value = TableOperations.getLength(el.style.width);
	input.size = "5";
	input.name = "f_st_width";
	input.style.marginRight = "0.5em";
	td.appendChild(input);
	select = doc.createElement("select");
	select.name = "f_st_widthUnit";
	option = doc.createElement("option");
	option.innerHTML = i18n["percent"];
	option.value = "%";
	option.selected = /%/.test(el.style.width);
	select.appendChild(option);
	option = doc.createElement("option");
	option.innerHTML = i18n["pixels"];
	option.value = "px";
	option.selected = /px/.test(el.style.width);
	select.appendChild(option);
	td.appendChild(select);

	select.style.marginRight = "0.5em";
	td.appendChild(doc.createTextNode(i18n["Text align"] + ":"));
	select = doc.createElement("select");
	select.style.marginLeft = select.style.marginRight = "0.5em";
	td.appendChild(select);
	select.name = "f_st_textAlign";
	options = ["Left", "Center", "Right", "Justify"];
	if (tagname == "td") {
		options.push("Char");
	}
	input = doc.createElement("input");
	input.name = "f_st_textAlignChar";
	input.size = "1";
	input.style.fontFamily = "monospace";
	td.appendChild(input);
	for (i in options) {
		var Val = options[i];
		var val = Val.toLowerCase();
		option = doc.createElement("option");
		option.value = val;
		option.innerHTML = i18n[Val];
		option.selected = (el.style.textAlign.toLowerCase() == val);
		select.appendChild(option);
	}
	function setCharVisibility(value) {
		input.style.visibility = value ? "visible" : "hidden";
		if (value) {
			input.focus();
			input.select();
		}
	};
	select.onchange = function() { setCharVisibility(this.value == "char"); };
	setCharVisibility(select.value == "char");

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	td.className = "label";
	tr.appendChild(td);
	td.innerHTML = i18n["Height"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	input = doc.createElement("input");
	input.type = "text";
	input.value = TableOperations.getLength(el.style.height);
	input.size = "5";
	input.name = "f_st_height";
	input.style.marginRight = "0.5em";
	td.appendChild(input);
	select = doc.createElement("select");
	select.name = "f_st_heightUnit";
	option = doc.createElement("option");
	option.innerHTML = i18n["percent"];
	option.value = "%";
	option.selected = /%/.test(el.style.height);
	select.appendChild(option);
	option = doc.createElement("option");
	option.innerHTML = i18n["pixels"];
	option.value = "px";
	option.selected = /px/.test(el.style.height);
	select.appendChild(option);
	td.appendChild(select);

	select.style.marginRight = "0.5em";
	td.appendChild(doc.createTextNode(i18n["Vertical align"] + ":"));
	select = doc.createElement("select");
	select.name = "f_st_verticalAlign";
	select.style.marginLeft = "0.5em";
	td.appendChild(select);
	options = ["Top", "Middle", "Bottom", "Baseline"];
	for (i in options) {
		var Val = options[i];
		var val = Val.toLowerCase();
		option = doc.createElement("option");
		option.value = val;
		option.innerHTML = i18n[Val];
		option.selected = (el.style.verticalAlign.toLowerCase() == val);
		select.appendChild(option);
	}

	return fieldset;
};

// Returns an HTML element containing the style attributes for the given
// element.  This can be easily embedded into any dialog; the functionality is
// also provided.
TableOperations.createStyleFieldset = function(doc, editor, el) {
	var i18n = TableOperations.I18N;
	var fieldset = doc.createElement("fieldset");
	var legend = doc.createElement("legend");
	fieldset.appendChild(legend);
	legend.innerHTML = i18n["CSS Style"];
	var table = doc.createElement("table");
	fieldset.appendChild(table);
	table.style.width = "100%";
	var tbody = doc.createElement("tbody");
	table.appendChild(tbody);

	var tr, td, input, select, option, options, i;

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	tr.appendChild(td);
	td.className = "label";
	td.innerHTML = i18n["Background"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	var df = TableOperations.createColorButton(doc, editor, el.style.backgroundColor, "backgroundColor");
	df.firstChild.nextSibling.style.marginRight = "0.5em";
	td.appendChild(df);
	td.appendChild(doc.createTextNode(i18n["Image URL"] + ": "));
	input = doc.createElement("input");
	input.type = "text";
	input.name = "f_st_backgroundImage";
	if (el.style.backgroundImage.match(/url\(\s*(.*?)\s*\)/)) {
		input.value = RegExp.$1;
	}
	// input.style.width = "100%";
	td.appendChild(input);

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	tr.appendChild(td);
	td.className = "label";
	td.innerHTML = i18n["FG Color"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);
	td.appendChild(TableOperations.createColorButton(doc, editor, el.style.color, "color"));

	// for better alignment we include an invisible field.
	input = doc.createElement("input");
	input.style.visibility = "hidden";
	input.type = "text";
	td.appendChild(input);

	tr = doc.createElement("tr");
	tbody.appendChild(tr);
	td = doc.createElement("td");
	tr.appendChild(td);
	td.className = "label";
	td.innerHTML = i18n["Border"] + ":";
	td = doc.createElement("td");
	tr.appendChild(td);

	var colorButton = TableOperations.createColorButton(doc, editor, el.style.borderColor, "borderColor");
	var btn = colorButton.firstChild.nextSibling;
	td.appendChild(colorButton);
	// borderFields.push(btn);
	btn.style.marginRight = "0.5em";

	select = doc.createElement("select");
	var borderFields = [];
	td.appendChild(select);
	select.name = "f_st_borderStyle";
	options = ["none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"];
	var currentBorderStyle = el.style.borderStyle;
	// Gecko reports "solid solid solid solid" for "border-style: solid".
	// That is, "top right bottom left" -- we only consider the first
	// value.
	(currentBorderStyle.match(/([^\s]*)\s/)) && (currentBorderStyle = RegExp.$1);
	for (i in options) {
		var val = options[i];
		option = doc.createElement("option");
		option.value = val;
		option.innerHTML = val;
		(val == currentBorderStyle) && (option.selected = true);
		select.appendChild(option);
	}
	select.style.marginRight = "0.5em";
	function setBorderFieldsStatus(value) {
		for (i in borderFields) {
			var el = borderFields[i];
			el.style.visibility = value ? "hidden" : "visible";
			if (!value && (el.tagName.toLowerCase() == "input")) {
				el.focus();
				el.select();
			}
		}
	};
	select.onchange = function() { setBorderFieldsStatus(this.value == "none"); };

	input = doc.createElement("input");
	borderFields.push(input);
	input.type = "text";
	input.name = "f_st_borderWidth";
	input.value = TableOperations.getLength(el.style.borderWidth);
	input.size = "5";
	td.appendChild(input);
	input.style.marginRight = "0.5em";
	var span = doc.createElement("span");
	span.innerHTML = i18n["pixels"];
	td.appendChild(span);
	borderFields.push(span);

	setBorderFieldsStatus(select.value == "none");

	if (el.tagName.toLowerCase() == "table") {
		// the border-collapse style is only for tables
		tr = doc.createElement("tr");
		tbody.appendChild(tr);
		td = doc.createElement("td");
		td.className = "label";
		tr.appendChild(td);
		input = doc.createElement("input");
		input.type = "checkbox";
		input.name = "f_st_borderCollapse";
		input.id = "f_st_borderCollapse";
		var val = (/collapse/i.test(el.style.borderCollapse));
		input.checked = val ? 1 : 0;
		td.appendChild(input);

		td = doc.createElement("td");
		tr.appendChild(td);
		var label = doc.createElement("label");
		label.htmlFor = "f_st_borderCollapse";
		label.innerHTML = i18n["Collapsed borders"];
		td.appendChild(label);
	}

// 	tr = doc.createElement("tr");
// 	tbody.appendChild(tr);
// 	td = doc.createElement("td");
// 	td.className = "label";
// 	tr.appendChild(td);
// 	td.innerHTML = i18n["Margin"] + ":";
// 	td = doc.createElement("td");
// 	tr.appendChild(td);
// 	input = doc.createElement("input");
// 	input.type = "text";
// 	input.size = "5";
// 	input.name = "f_st_margin";
// 	td.appendChild(input);
// 	input.style.marginRight = "0.5em";
// 	td.appendChild(doc.createTextNode(i18n["Padding"] + ":"));

// 	input = doc.createElement("input");
// 	input.type = "text";
// 	input.size = "5";
// 	input.name = "f_st_padding";
// 	td.appendChild(input);
// 	input.style.marginLeft = "0.5em";
// 	input.style.marginRight = "0.5em";
// 	td.appendChild(doc.createTextNode(i18n["pixels"]));

	return fieldset;
};

//// END GENERIC CODE -------------------------------------------------------

Index: loncom/html/htmlarea/plugins/TableOperations/lang/en.js
+++ loncom/html/htmlarea/plugins/TableOperations/lang/en.js
// I18N constants

// LANG: "en", ENCODING: UTF-8 | ISO-8859-1
// Author: Mihai Bazon, <mishoo@infoiasi.ro>

// FOR TRANSLATORS:
//
//   1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE
//      (at least a valid email address)
//
//   2. PLEASE TRY TO USE UTF-8 FOR ENCODING;
//      (if this is not possible, please include a comment
//       that states what encoding is necessary.)

TableOperations.I18N = {
	"Align":					  "Align",
	"All four sides":				  "All four sides",
	"Background":					  "Background",
	"Baseline":                                       "Baseline",
	"Border":					  "Border",
	"Borders":					  "Borders",
	"Bottom":                                         "Bottom",
	"CSS Style":					  "Style [CSS]",
	"Caption":					  "Caption",
	"Cell Properties":                                "Cell Properties",
	"Center":					  "Center",
	"Char":                                           "Char",
	"Collapsed borders":                              "Collapsed borders",
	"Color":					  "Color",
	"Description":					  "Description",
	"FG Color":					  "FG Color",
	"Float":                                          "Float",
	"Frames":					  "Frames",
	"Height":                                         "Height",
	"How many columns would you like to merge?":      "How many columns would you like to merge?",
	"How many rows would you like to merge?":         "How many rows would you like to merge?",
	"Image URL":					  "Image URL",
	"Justify":                                        "Justify",
	"Layout":					  "Layout",
	"Left":						  "Left",
	"Margin":                                         "Margin",
	"Middle":                                         "Middle",
	"No rules":					  "No rules",
	"No sides":					  "No sides",
	"None":                                           "None",
	"Padding":					  "Padding",
	"Please click into some cell":                    "Please click into some cell",
	"Right":					  "Right",
	"Row Properties":                                 "Row Properties",
	"Rules will appear between all rows and columns": "Rules will appear between all rows and columns",
	"Rules will appear between columns only":	  "Rules will appear between columns only",
	"Rules will appear between rows only":		  "Rules will appear between rows only",
	"Rules":					  "Rules",
	"Spacing and padding":                            "Spacing and padding",
	"Spacing":					  "Spacing",
	"Summary":					  "Summary",
	"TO-cell-delete":				  "Delete cell",
	"TO-cell-insert-after":				  "Insert cell after",
	"TO-cell-insert-before":			  "Insert cell before",
	"TO-cell-merge":				  "Merge cells",
	"TO-cell-prop":					  "Cell properties",
	"TO-cell-split":				  "Split cell",
	"TO-col-delete":				  "Delete column",
	"TO-col-insert-after":				  "Insert column after",
	"TO-col-insert-before":				  "Insert column before",
	"TO-col-split":					  "Split column",
	"TO-row-delete":				  "Delete row",
	"TO-row-insert-above":				  "Insert row before",
	"TO-row-insert-under":				  "Insert row after",
	"TO-row-prop":					  "Row properties",
	"TO-row-split":					  "Split row",
	"TO-table-prop":				  "Table properties",
	"Table Properties":				  "Table Properties",
	"Text align":                                     "Text align",
	"The bottom side only":				  "The bottom side only",
	"The left-hand side only":			  "The left-hand side only",
	"The right and left sides only":		  "The right and left sides only",
	"The right-hand side only":			  "The right-hand side only",
	"The top and bottom sides only":		  "The top and bottom sides only",
	"The top side only":				  "The top side only",
	"Top":                                            "Top",	
	"Unset color":                                    "Unset color",
	"Vertical align":                                 "Vertical align",
	"Width":					  "Width",
	"not-del-last-cell":				  "HTMLArea cowardly refuses to delete the last cell in row.",
	"not-del-last-col":				  "HTMLArea cowardly refuses to delete the last column in table.",
	"not-del-last-row":				  "HTMLArea cowardly refuses to delete the last row in table.",
	"percent":					  "percent",
	"pixels":					  "pixels"
};

Index: loncom/html/htmlarea/plugins/TableOperations/lang/fi.js
+++ loncom/html/htmlarea/plugins/TableOperations/lang/fi.js
TableOperations.I18N = {
	"Align":					  "Kohdistus",
	"All four sides":				  "Kaikki neljä sivua",
	"Background":					  "Tausta",
	"Baseline":                                       "Takaraja",
	"Border":					  "Reuna",
	"Borders":					  "Reunat",
	"Bottom":                                         "Alle",
	"CSS Style":					  "Tyyli [CSS]",
	"Caption":					  "Otsikko",
	"Cell Properties":                                "Solun asetukset",
	"Center":					  "Keskelle",
	"Char":                                           "Merkki",
	"Collapsed borders":                              "Luhistetut reunat",
	"Color":					  "Väri",
	"Description":					  "Kuvaus",
	"FG Color":					  "FG Väri",
	"Frames":					  "Kehykset",
	"Image URL":					  "Kuvan osoite",
	"Layout":					  "Sommittelu",
	"Left":						  "Vasen",
	"Margin":                                         "Marginaali",
	"Middle":                                         "Keskelle",
	"No rules":					  "Ei viivoja",
	"No sides":					  "Ei sivuja",
	"Padding":					  "Palstantäyte",
	"Right":					  "Oikea",
	"Row Properties":                                 "Rivin asetukset",
	"Rules will appear between all rows and columns": "Viivat jokaisen rivin ja sarakkeen välillä",
	"Rules will appear between columns only":	  "Viivat ainoastaan sarakkeiden välillä",
	"Rules will appear between rows only":		  "Viivat ainoastaan rivien välillä",
	"Rules":					  "Viivat",
	"Spacing":					  "Palstatila",
	"Summary":					  "Yhteenveto",
	"TO-cell-delete":				  "Poista solu",
	"TO-cell-insert-after":				  "Lisää solu perään",
	"TO-cell-insert-before":			  "Lisää solu ennen",
	"TO-cell-merge":				  "Yhdistä solut",
	"TO-cell-prop":					  "Solun asetukset",
	"TO-cell-split":				  "Jaa solu",
	"TO-col-delete":				  "Poista sarake",
	"TO-col-insert-after":				  "Lisää sarake perään",
	"TO-col-insert-before":				  "Lisää sarake ennen",
	"TO-col-split":					  "Jaa sarake",
	"TO-row-delete":				  "Poista rivi",
	"TO-row-insert-above":				  "Lisää rivi yläpuolelle",
	"TO-row-insert-under":				  "Lisää rivi alapuolelle",
	"TO-row-prop":					  "Rivin asetukset",
	"TO-row-split":					  "Jaa rivi",
	"TO-table-prop":				  "Taulukon asetukset",
	"Top":                                            "Ylös",	
	"Table Properties":				  "Taulukon asetukset",
	"The bottom side only":				  "Ainoastaan alapuolelle",
	"The left-hand side only":			  "Ainoastaan vasenreuna",
	"The right and left sides only":		  "Oikea- ja vasenreuna",
	"The right-hand side only":			  "Ainoastaan oikeareuna",
	"The top and bottom sides only":		  "Ylä- ja alapuoli.",
	"The top side only":				  "Ainoastaan yläpuoli",
	"Vertical align":                                 "Vertikaali kohdistus",
	"Width":					  "Leveys",
	"not-del-last-cell":				  "Ei voida poistaa viimeistä solua rivistä.",
	"not-del-last-col":				  "Ei voida poistaa viimeistä saraketta taulusta.",
	"not-del-last-row":				  "Ei voida poistaa viimeistä riviä taulusta.",
	"percent":					  "prosenttia",
	"pixels":					  "pikseliä"
};

Index: loncom/html/htmlarea/plugins/TableOperations/lang/ro.js
+++ loncom/html/htmlarea/plugins/TableOperations/lang/ro.js
// I18N constants

// LANG: "ro", ENCODING: UTF-8
// Author: Mihai Bazon, <mishoo@infoiasi.ro>

// FOR TRANSLATORS:
//
//   1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE
//      (at least a valid email address)
//
//   2. PLEASE TRY TO USE UTF-8 FOR ENCODING;
//      (if this is not possible, please include a comment
//       that states what encoding is necessary.)

TableOperations.I18N = {
	"Align":					  "Aliniere",
	"All four sides":				  "Toate părţile",
	"Background":					  "Fundal",
	"Baseline":                                       "Baseline",
	"Border":					  "Chenar",
	"Borders":					  "Chenare",
	"Bottom":                                         "Jos",
	"CSS Style":					  "Stil [CSS]",
	"Caption":					  "Titlu de tabel",
	"Cell Properties":                                "Proprietăţile celulei",
	"Center":					  "Centru",
	"Char":                                           "Caracter",
	"Collapsed borders":                              "Chenare asimilate",
	"Color":					  "Culoare",
	"Description":					  "Descriere",
	"FG Color":					  "Culoare text",
	"Float":                                          "Poziţie",
	"Frames":					  "Chenare",
	"Height":                                         "Înălţimea",
	"How many columns would you like to merge?":      "Câte coloane vrei să uneşti?",
	"How many rows would you like to merge?":         "Câte linii vrei să uneşti?",
	"Image URL":					  "URL-ul imaginii",
	"Justify":                                        "Justify",
	"Layout":					  "Aranjament",
	"Left":						  "Stânga",
	"Margin":                                         "Margine",
	"Middle":                                         "Mijloc",
	"No rules":					  "Fără linii",
	"No sides":					  "Fără părţi",
	"None":                                           "Nimic",
	"Padding":					  "Spaţiere",
	"Please click into some cell":                    "Vă rog să daţi click într-o celulă",
	"Right":					  "Dreapta",
	"Row Properties":                                 "Proprietăţile liniei",
	"Rules will appear between all rows and columns": "Vor apărea linii între toate rândurile şi coloanele",
	"Rules will appear between columns only":	  "Vor apărea doar linii verticale",
	"Rules will appear between rows only":		  "Vor apărea doar linii orizontale",
	"Rules":					  "Linii",
	"Spacing and padding":                            "Spaţierea",
	"Spacing":					  "ÃŽntre celule",
	"Summary":					  "Sumar",
	"TO-cell-delete":				  "Åžterge celula",
	"TO-cell-insert-after":				  "Inserează o celulă la dreapta",
	"TO-cell-insert-before":			  "Inserează o celulă la stânga",
	"TO-cell-merge":				  "UneÅŸte celulele",
	"TO-cell-prop":					  "Proprietăţile celulei",
	"TO-cell-split":				  "ÃŽmparte celula",
	"TO-col-delete":				  "Åžterge coloana",
	"TO-col-insert-after":				  "Inserează o coloană la dreapta",
	"TO-col-insert-before":				  "Inserează o coloană la stânga",
	"TO-col-split":					  "ÃŽmparte coloana",
	"TO-row-delete":				  "Şterge rândul",
	"TO-row-insert-above":				  "Inserează un rând înainte",
	"TO-row-insert-under":				  "Inserează un rând după",
	"TO-row-prop":					  "Proprietăţile rândului",
	"TO-row-split":					  "Împarte rândul",
	"TO-table-prop":				  "Proprietăţile tabelei",
	"Table Properties":				  "Proprietăţile tabelei",
	"Text align":                                     "Aliniere",
	"The bottom side only":				  "Doar partea de jos",
	"The left-hand side only":			  "Doar partea din stânga",
	"The right and left sides only":		  "Partea din stânga şi cea din dreapta",
	"The right-hand side only":			  "Doar partea din dreapta",
	"The top and bottom sides only":		  "Partea de sus si cea de jos",
	"The top side only":				  "Doar partea de sus",
	"Top":                                            "Sus",	
	"Unset color":                                    "Dezactivează culoarea",
	"Vertical align":                                 "Aliniere pe verticală",
	"Width":					  "Lăţime",
	"not-del-last-cell":				  "HTMLArea refuză cu laşitate să şteargă ultima celulă din rând.",
	"not-del-last-col":				  "HTMLArea refuză cu laşitate să şteargă ultima coloamă din tabela.",
	"not-del-last-row":				  "HTMLArea refuză cu laşitate să şteargă ultimul rând din tabela.",
	"percent":					  "procente",
	"pixels":					  "pixeli"
};

Index: loncom/html/htmlarea/popups/about.html
+++ loncom/html/htmlarea/popups/about.html
<html style="width: 380px; height: 250px;">
<head><title>About HTMLArea</title>
<script type="text/javascript" src="popup.js"></script>
<script type="text/javascript">
function closeAbout() {
  __dlg_close(null);
}
</script>
<style>
  html,body,textarea { font-family: tahoma,verdana,arial; font-size: 11px;
padding: 0px; margin: 0px; }
  tt { font-size: 120%; }
  body { padding: 0px; background: ButtonFace; color: ButtonText; }
  a:link, a:visited { color: #00f; }
  a:hover { color: #f00; }
  a:active { color: #f80; }
  button { font: 11px tahoma,verdana,sans-serif; }
</style></head>
<body onload="__dlg_init()">

<div style="background-color: #fff; color: #000; padding: 3px; border-bottom: 1px solid #000;">
<div style="font-family: 'arial black',arial,sans-serif; font-size: 28px;
letter-spacing: -1px;">
<span style="position: relative; top: -0.2em">H</span><span
style="position: relative; top: 0.1em">T</span><span
style="position: relative; top: -0.1em">M</span><span
style="position: relative; top: 0.2em">L</span> Area
3.0 <span style="position: relative; top: -0.6em; font-size: 50%; font-weight: normal">[ rev. beta ]</span></div>

<div style="text-align: right; font-size: 90%; margin-bottom: 1em">
Released on Aug 11, 2003 [21:30] GMT
</div>
</div>

<div style="margin: 1em">

<p>A free WYSIWYG editor replacement for <tt>&lt;textarea&gt;</tt> fields.</p>

<p>For full source code and docs, visit:<br />
<a href="http://www.interactivetools.com/products/htmlarea/" target="_blank"
>http://www.interactivetools.com/products/htmlarea/</a></p>

<p>Version 3.0 developed and maintained by <a href="http://students.infoiasi.ro/~mishoo/" target="_blank">mishoo</a>.</p>

<p>&copy; 2002, 2003 <a href="http://interactivetools.com" target="_blank">interactivetools.com</a>, inc. All Rights Reserved.</p>

</div>

<div style="text-align: right; padding: 0px 3px 3px 0px;">
<button type="button" onclick="closeAbout()">I agree it's cool</button>
</div>

</body></html>



Index: loncom/html/htmlarea/popups/blank.html
+++ loncom/html/htmlarea/popups/blank.html
<html>
</html>
Index: loncom/html/htmlarea/popups/custom2.html
+++ loncom/html/htmlarea/popups/custom2.html
<html style="width:300px; Height: 60px;">
 <head>
  <title>Select Phrase</title>
<script language="javascript">

var myTitle = window.dialogArguments;
document.title = myTitle;


function returnSelected() {
  var idx  = document.all.textPulldown.selectedIndex;
  var text = document.all.textPulldown[idx].text;

  window.returnValue = text;          // set return value
  window.close();                     // close dialog
}

</script>
</head>
<body bgcolor="#FFFFFF" topmargin=15 leftmargin=0>

<form method=get onSubmit="Set(document.all.ColorHex.value); return false;">
<div align=center>

<select name="textPulldown">
<option>The quick brown</option>
<option>fox jumps over</option>
<option>the lazy dog.</option>
</select>

<input type="button" value=" Go " onClick="returnSelected()">

</div>
</form>
</body></html>
Index: loncom/html/htmlarea/popups/editor_help.html
+++ loncom/html/htmlarea/popups/editor_help.html
<html>
 <head>
  <title>Editor Help</title>
  <style>
    body, td, p, div { font-family: arial; font-size: x-small; }
  </style>
 </head>
<body>

<h2>Editor Help<hr></h2>

Todo...


</body>
</html>
Index: loncom/html/htmlarea/popups/fullscreen.html
+++ loncom/html/htmlarea/popups/fullscreen.html
<html>
<head><title>Fullscreen Editor</title>
<style type="text/css">
@import url(../htmlarea.css);
html, body {	margin: 0px; border: 0px; background-color: buttonface; } </style>

<!--
<script type="text/javascript" src="../htmlarea.js"></script>
<script type="text/javascript" src="../htmlarea-lang-en.js"></script>
<script type="text/javascript" src="../dialog.js"></script>
-->

<script type="text/javascript">
// load same scripts that were present in the opener page
var scripts = opener.document.getElementsByTagName("script");
var head = document.getElementsByTagName("head")[0];
for (var i = 0; i < scripts.length; ++i) {
  var script = scripts[i];
  if (typeof script.src != "undefined" && /\S/.test(script.src)) {
    // document.write("<scr" + "ipt type=" + "\"script/javascript\"");
    // document.write(" src=\"../" + script.src + "\"></scr" + "ipt>");
    var new_script = document.createElement("script");
    if (/^http:/i.test(script.src)) {
      new_script.src = script.src;
    } else {
      new_script.src = "../" + script.src;
    }
    head.appendChild(new_script);
  }
}
</script>

<script type="text/javascript">

var parent_object  = null;
var editor         = null;      // to be initialized later [ function init() ]

/* ---------------------------------------------------------------------- *\
  Function    : 
  Description : 
\* ---------------------------------------------------------------------- */

function _CloseOnEsc(ev) {
  if (document.all) {
    // IE
    ev = window.event;
  }
  if (ev.keyCode == 27) {
    // update_parent();
    window.close();
    return;
  }
}

/* ---------------------------------------------------------------------- *\
  Function    : cloneObject
  Description : copy an object by value instead of by reference
  Usage       : var newObj = cloneObject(oldObj);
\* ---------------------------------------------------------------------- */

function cloneObject(obj) {
  var newObj          = new Object; 

  // check for array objects
  if (obj.constructor.toString().indexOf("function Array(") == 1) {
    newObj = obj.constructor();
  }

  // check for function objects (as usual, IE is fucked up)
  if (obj.constructor.toString().indexOf("function Function(") == 1) {
    newObj = obj; // just copy reference to it
  } else for (var n in obj) {
    var node = obj[n];
    if (typeof node == 'object') { newObj[n] = cloneObject(node); }
    else                         { newObj[n] = node; }
  }
  
  return newObj;
}

/* ---------------------------------------------------------------------- *\
  Function    : resize_editor
  Description : resize the editor when the user resizes the popup
\* ---------------------------------------------------------------------- */

function resize_editor() {  // resize editor to fix window
  var newHeight;
  if (document.all) {
    // IE
    newHeight = document.body.offsetHeight - editor._toolbar.offsetHeight;
    if (newHeight < 0) { newHeight = 0; }
  } else {
    // Gecko
    newHeight = window.innerHeight - editor._toolbar.offsetHeight;
  }
  if (editor.config.statusBar) {
    newHeight -= editor._statusBar.offsetHeight;
  }
  editor._textArea.style.height = editor._iframe.style.height = newHeight + "px";
}

/* ---------------------------------------------------------------------- *\
  Function    : init
  Description : run this code on page load
\* ---------------------------------------------------------------------- */

function init() {
  parent_object      = opener.HTMLArea._object;
  var config         = cloneObject( parent_object.config );
  config.editorURL   = "../";
  config.width       = "100%";
  config.height      = "auto";

  // change maximize button to minimize button
  config.btnList["popupeditor"] = [ 'Minimize Editor', 'images/fullscreen_minimize.gif', true,
                                    function() { window.close(); } ];

  // generate editor and resize it
  editor = new HTMLArea("editor", config);
  editor.generate();
  editor._iframe.style.width = "100%";
  editor._textArea.style.width = "100%";
  resize_editor();

  // set child window contents and event handlers, after a small delay
  setTimeout(function() {
    editor.setHTML(parent_object.getInnerHTML());

    // switch mode if needed
    if (parent_object._mode == "textmode") { editor.setMode("textmode"); }

    // continuously update parent editor window
    setInterval(update_parent, 500);

    // setup event handlers
    document.body.onkeypress = _CloseOnEsc;
    editor._doc.body.onkeypress = _CloseOnEsc;
    editor._textArea.onkeypress = _CloseOnEsc;
    window.onresize = resize_editor;
  }, 333);                      // give it some time to meet the new frame
}

/* ---------------------------------------------------------------------- *\
  Function    : update_parent
  Description : update parent window editor field with contents from child window
\* ---------------------------------------------------------------------- */

function update_parent() {
  // use the fast version
  parent_object.setHTML(editor.getInnerHTML());
}


</script>
</head>
<body scroll="no" onload="init()" onunload="update_parent()">

<form style="margin: 0px; border: 1px solid; border-color: threedshadow threedhighlight threedhighlight threedshadow;">
<textarea name="editor" id="editor" style="width:100%; height:300px">&nbsp;</textarea>
</form>

</body></html>

Index: loncom/html/htmlarea/popups/insert_image.html
+++ loncom/html/htmlarea/popups/insert_image.html
<html style="width: 398; height: 218">

<head>
  <title>Insert Image</title>

<script type="text/javascript" src="popup.js"></script>

<script type="text/javascript">
var preview_window = null;

function Init() {
  __dlg_init();
  document.getElementById("f_url").focus();
};

function onOK() {
  var required = {
    "f_url": "You must enter the URL",
    "f_alt": "Please enter the alternate text"
  };
  for (var i in required) {
    var el = document.getElementById(i);
    if (!el.value) {
      alert(required[i]);
      el.focus();
      return false;
    }
  }
  // pass data back to the calling window
  var fields = ["f_url", "f_alt", "f_align", "f_border",
                "f_horiz", "f_vert"];
  var param = new Object();
  for (var i in fields) {
    var id = fields[i];
    var el = document.getElementById(id);
    param[id] = el.value;
  }
  if (preview_window) {
    preview_window.close();
  }
  __dlg_close(param);
  return false;
};

function onCancel() {
  if (preview_window) {
    preview_window.close();
  }
  __dlg_close(null);
  return false;
};

function onPreview() {
  alert("FIXME: preview needs rewritten:\n  show the image inside this window instead of opening a new one.");
  var f_url = document.getElementById("f_url");
  var url = f_url.value;
  if (!url) {
    alert("You have to enter an URL first");
    f_url.focus();
    return false;
  }
  var img = new Image();
  img.src = url;
  var win = null;
  if (!document.all) {
    win = window.open("about:blank", "ha_imgpreview", "toolbar=no,menubar=no,personalbar=no,innerWidth=100,innerHeight=100,scrollbars=no,resizable=yes");
  } else {
    win = window.open("about:blank", "ha_imgpreview", "channelmode=no,directories=no,height=100,width=100,location=no,menubar=no,resizable=yes,scrollbars=no,toolbar=no");
  }
  preview_window = win;
  var doc = win.document;
  var body = doc.body;
  if (body) {
    body.innerHTML = "";
    body.style.padding = "0px";
    body.style.margin = "0px";
    var el = doc.createElement("img");
    el.src = url;

    var table = doc.createElement("table");
    body.appendChild(table);
    table.style.width = "100%";
    table.style.height = "100%";
    var tbody = doc.createElement("tbody");
    table.appendChild(tbody);
    var tr = doc.createElement("tr");
    tbody.appendChild(tr);
    var td = doc.createElement("td");
    tr.appendChild(td);
    td.style.textAlign = "center";

    td.appendChild(el);
    win.resizeTo(el.offsetWidth + 30, el.offsetHeight + 30);
  }
  win.focus();
  return false;
};
</script>

<style type="text/css">
html, body {
  background: ButtonFace;
  color: ButtonText;
  font: 11px Tahoma,Verdana,sans-serif;
  margin: 0px;
  padding: 0px;
}
body { padding: 5px; }
table {
  font: 11px Tahoma,Verdana,sans-serif;
}
form p {
  margin-top: 5px;
  margin-bottom: 5px;
}
.fl { width: 9em; float: left; padding: 2px 5px; text-align: right; }
.fr { width: 6em; float: left; padding: 2px 5px; text-align: right; }
fieldset { padding: 0px 10px 5px 5px; }
select, input, button { font: 11px Tahoma,Verdana,sans-serif; }
button { width: 70px; }
.space { padding: 2px; }

.title { background: #ddf; color: #000; font-weight: bold; font-size: 120%; padding: 3px 10px; margin-bottom: 10px;
border-bottom: 1px solid black; letter-spacing: 2px;
}
form { padding: 0px; margin: 0px; }
</style>

</head>

<body onload="Init()">

<div class="title">Insert Image</div>

<form action="" method="get">
<table border="0" width="100%" style="padding: 0px; margin: 0px">
  <tbody>

  <tr>
    <td style="width: 7em; text-align: right">Image URL:</td>
    <td><input type="text" name="url" id="f_url" style="width:75%"
      title="Enter the image URL here" />
      <button name="preview" onclick="return onPreview();"
      title="Preview the image in a new window">Preview</button>
    </td>
  </tr>
  <tr>
    <td style="width: 7em; text-align: right">Alternate text:</td>
    <td><input type="text" name="alt" id="f_alt" style="width:100%"
      title="For browsers that don't support images" /></td>
  </tr>

  </tbody>
</table>

<p />

<fieldset style="float: left; margin-left: 5px;">
<legend>Layout</legend>

<div class="space"></div>

<div class="fl">Alignment:</div>
<select size="1" name="align" id="f_align"
  title="Positioning of this image">
  <option value=""                             >Not set</option>
  <option value="left"                         >Left</option>
  <option value="right"                        >Right</option>
  <option value="texttop"                      >Texttop</option>
  <option value="absmiddle"                    >Absmiddle</option>
  <option value="baseline" selected="1"        >Baseline</option>
  <option value="absbottom"                    >Absbottom</option>
  <option value="bottom"                       >Bottom</option>
  <option value="middle"                       >Middle</option>
  <option value="top"                          >Top</option>
</select>

<p />

<div class="fl">Border thickness:</div>
<input type="text" name="border" id="f_border" size="5"
title="Leave empty for no border" />

<div class="space"></div>

</fieldset>

<fieldset style="float:right; margin-right: 5px;">
<legend>Spacing</legend>

<div class="space"></div>

<div class="fr">Horizontal:</div>
<input type="text" name="horiz" id="f_horiz" size="5"
title="Horizontal padding" />

<p />

<div class="fr">Vertical:</div>
<input type="text" name="vert" id="f_vert" size="5"
title="Vertical padding" />

<div class="space"></div>

</fieldset>

<div style="margin-top: 85px; text-align: right;">
<hr />
<button type="button" name="ok" onclick="return onOK();">OK</button>
<button type="button" name="cancel" onclick="return onCancel();">Cancel</button>
</div>

</form>

</body>
</html>

Index: loncom/html/htmlarea/popups/insert_table.html
+++ loncom/html/htmlarea/popups/insert_table.html
<html style="width: 398; height: 218">

<head>
  <title>Insert Table</title>

<script type="text/javascript" src="popup.js"></script>

<script type="text/javascript">

function Init() {
  __dlg_init();
  document.getElementById("f_rows").focus();
};

function onOK() {
  var required = {
    "f_rows": "You must enter a number of rows",
    "f_cols": "You must enter a number of columns"
  };
  for (var i in required) {
    var el = document.getElementById(i);
    if (!el.value) {
      alert(required[i]);
      el.focus();
      return false;
    }
  }
  var fields = ["f_rows", "f_cols", "f_width", "f_unit",
                "f_align", "f_border", "f_spacing", "f_padding"];
  var param = new Object();
  for (var i in fields) {
    var id = fields[i];
    var el = document.getElementById(id);
    param[id] = el.value;
  }
  __dlg_close(param);
  return false;
};

function onCancel() {
  __dlg_close(null);
  return false;
};

</script>

<style type="text/css">
html, body {
  background: ButtonFace;
  color: ButtonText;
  font: 11px Tahoma,Verdana,sans-serif;
  margin: 0px;
  padding: 0px;
}
body { padding: 5px; }
table {
  font: 11px Tahoma,Verdana,sans-serif;
}
form p {
  margin-top: 5px;
  margin-bottom: 5px;
}
.fl { width: 9em; float: left; padding: 2px 5px; text-align: right; }
.fr { width: 7em; float: left; padding: 2px 5px; text-align: right; }
fieldset { padding: 0px 10px 5px 5px; }
select, input, button { font: 11px Tahoma,Verdana,sans-serif; }
button { width: 70px; }
.space { padding: 2px; }

.title { background: #ddf; color: #000; font-weight: bold; font-size: 120%; padding: 3px 10px; margin-bottom: 10px;
border-bottom: 1px solid black; letter-spacing: 2px;
}
form { padding: 0px; margin: 0px; }
</style>

</head>

<body onload="Init()">

<div class="title">Insert Table</div>

<form action="" method="get">
<table border="0" style="padding: 0px; margin: 0px">
  <tbody>

  <tr>
    <td style="width: 4em; text-align: right">Rows:</td>
    <td><input type="text" name="rows" id="f_rows" size="5" title="Number of rows" value="2" /></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td style="width: 4em; text-align: right">Cols:</td>
    <td><input type="text" name="cols" id="f_cols" size="5" title="Number of columns" value="4" /></td>
    <td style="width: 4em; text-align: right">Width:</td>
    <td><input type="text" name="width" id="f_width" size="5" title="Width of the table" value="100" /></td>
    <td><select size="1" name="unit" id="f_unit" title="Width unit">
      <option value="%" selected="1"  >Percent</option>
      <option value="px"              >Pixels</option>
      <option value="em"              >Em</option>
    </select></td>
  </tr>

  </tbody>
</table>

<p />

<fieldset style="float: left; margin-left: 5px;">
<legend>Layout</legend>

<div class="space"></div>

<div class="fl">Alignment:</div>
<select size="1" name="align" id="f_align"
  title="Positioning of this image">
  <option value="" selected="1"                >Not set</option>
  <option value="left"                         >Left</option>
  <option value="right"                        >Right</option>
  <option value="texttop"                      >Texttop</option>
  <option value="absmiddle"                    >Absmiddle</option>
  <option value="baseline"                     >Baseline</option>
  <option value="absbottom"                    >Absbottom</option>
  <option value="bottom"                       >Bottom</option>
  <option value="middle"                       >Middle</option>
  <option value="top"                          >Top</option>
</select>

<p />

<div class="fl">Border thickness:</div>
<input type="text" name="border" id="f_border" size="5" value="1"
title="Leave empty for no border" />
<!--
<p />

<div class="fl">Collapse borders:</div>
<input type="checkbox" name="collapse" id="f_collapse" />
-->
<div class="space"></div>

</fieldset>

<fieldset style="float:right; margin-right: 5px;">
<legend>Spacing</legend>

<div class="space"></div>

<div class="fr">Cell spacing:</div>
<input type="text" name="spacing" id="f_spacing" size="5" value="1"
title="Space between adjacent cells" />

<p />

<div class="fr">Cell padding:</div>
<input type="text" name="padding" id="f_padding" size="5" value="1"
title="Space between content and border in cell" />

<div class="space"></div>

</fieldset>

<div style="margin-top: 85px; text-align: right;">
<hr />
<button type="button" name="ok" onclick="return onOK();">OK</button>
<button type="button" name="cancel" onclick="return onCancel();">Cancel</button>
</div>

</form>

</body>
</html>

Index: loncom/html/htmlarea/popups/old-fullscreen.html
+++ loncom/html/htmlarea/popups/old-fullscreen.html
<html>
<head><title>Fullscreen Editor</title>
<style type="text/css"> body {	margin: 0px; border: 0px; background-color: buttonface; } </style>

<script>

// if we pass the "window" object as a argument and then set opener to
// equal that we can refer to dialogWindows and popupWindows the same way
if (window.dialogArguments) { opener = window.dialogArguments; }

var _editor_url = "../";
document.write('<scr'+'ipt src="' +_editor_url+ 'editor.js" language="Javascript1.2"></scr'+'ipt>');

var parent_objname = location.search.substring(1,location.search.length);  // parent editor objname
var parent_config  = opener.document.all[parent_objname].config;

var config         = cloneObject( parent_config );
var objname        = 'editor'; // name of this editor

//  DOMViewerObj = config;
//  DOMViewerName = 'config';
//  window.open('/innerHTML/domviewer.htm');  

/* ---------------------------------------------------------------------- *\
  Function    : 
  Description : 
\* ---------------------------------------------------------------------- */

function _CloseOnEsc() {
  if (event.keyCode == 27) {
    update_parent();
    window.close();
    return;
  }
}

/* ---------------------------------------------------------------------- *\
  Function    : cloneObject
  Description : copy an object by value instead of by reference
  Usage       : var newObj = cloneObject(oldObj);
\* ---------------------------------------------------------------------- */

function cloneObject(obj) {
  var newObj          = new Object; 

  // check for array objects
  if (obj.constructor.toString().indexOf('function Array(') == 1) {
    newObj = obj.constructor();
  }

  for (var n in obj) {
    var node = obj[n];
    if (typeof node == 'object') { newObj[n] = cloneObject(node); }
    else                         { newObj[n] = node; }
  }
  
  return newObj;
}

/* ---------------------------------------------------------------------- *\
  Function    : resize_editor
  Description : resize the editor when the user resizes the popup
\* ---------------------------------------------------------------------- */

function resize_editor() {  // resize editor to fix window
  var editor = document.all['_editor_editor'];

  newWidth  = document.body.offsetWidth;
  newHeight = document.body.offsetHeight - editor.offsetTop;

  if (newWidth < 0) { newWidth = 0; }
  if (newHeight < 0) { newHeight = 0; }

  editor.style.width  = newWidth;
  editor.style.height = newHeight;
}

/* ---------------------------------------------------------------------- *\
  Function    : init
  Description : run this code on page load
\* ---------------------------------------------------------------------- */

function init() {
  // change maximize button to minimize button
  config.btnList["popupeditor"] = ['popupeditor', 'Minimize Editor',  'update_parent(); window.close();', 'fullscreen_minimize.gif'];

  // set htmlmode button to refer to THIS editor
  config.btnList["htmlmode"]    = ['HtmlMode',    'View HTML Source', 'editor_setmode(\'editor\')',  'ed_html.gif'];

  // change image url to be relative to current path
  config.imgURL = "../images/";
  
  // generate editor and resize it
  editor_generate('editor', config);
  resize_editor();

  // switch mode if needed
  if (parent_config.mode == 'textedit') { editor_setmode(objname, 'textedit'); }

  // set child window contents
  var parentHTML = opener.editor_getHTML(parent_objname);
  editor_setHTML(objname, parentHTML);

  // continuously update parent editor window
  window.setInterval(update_parent, 333);

  // setup event handlers
  document.body.onkeypress = _CloseOnEsc;
  window.onresize = resize_editor;
}

/* ---------------------------------------------------------------------- *\
  Function    : update_parent
  Description : update parent window editor field with contents from child window
\* ---------------------------------------------------------------------- */

function update_parent() {
  var childHTML = editor_getHTML(objname);
  opener.editor_setHTML(parent_objname, childHTML);
}


</script>
</head>
<body scroll="no" onload="init()" onunload="update_parent()">

<div style="margin: 0 0 0 0; border-width: 1; border-style: solid; border-color: threedshadow threedhighlight threedhighlight threedshadow; "></div>

<textarea name="editor" style="width:100%; height:300px"></textarea><br>

</body></html>
Index: loncom/html/htmlarea/popups/old_insert_image.html
+++ loncom/html/htmlarea/popups/old_insert_image.html
<!-- based on insimage.dlg -->

<!DOCTYPE HTML PUBLIC "-//W3C//DTD W3 HTML 3.2//EN">
<HTML  id=dlgImage STYLE="width: 432px; height: 194px; ">
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="MSThemeCompatible" content="Yes">
<TITLE>Insert Image</TITLE>
<style>
  html, body, button, div, input, select, fieldset { font-family: MS Shell Dlg; font-size: 8pt; position: absolute; };
</style>
<SCRIPT defer>

function _CloseOnEsc() {
  if (event.keyCode == 27) { window.close(); return; }
}

function _getTextRange(elm) {
  var r = elm.parentTextEdit.createTextRange();
  r.moveToElementText(elm);
  return r;
}

window.onerror = HandleError

function HandleError(message, url, line) {
  var str = "An error has occurred in this dialog." + "\n\n"
  + "Error: " + line + "\n" + message;
  alert(str);
  window.close();
  return true;
}

function Init() {
  var elmSelectedImage;
  var htmlSelectionControl = "Control";
  var globalDoc = window.dialogArguments;
  var grngMaster = globalDoc.selection.createRange();
  
  // event handlers  
  document.body.onkeypress = _CloseOnEsc;
  btnOK.onclick = new Function("btnOKClick()");

  txtFileName.fImageLoaded = false;
  txtFileName.intImageWidth = 0;
  txtFileName.intImageHeight = 0;

  if (globalDoc.selection.type == htmlSelectionControl) {
    if (grngMaster.length == 1) {
      elmSelectedImage = grngMaster.item(0);
      if (elmSelectedImage.tagName == "IMG") {
        txtFileName.fImageLoaded = true;
        if (elmSelectedImage.src) {
          txtFileName.value          = elmSelectedImage.src.replace(/^[^*]*(\*\*\*)/, "$1");  // fix placeholder src values that editor converted to abs paths
          txtFileName.intImageHeight = elmSelectedImage.height;
          txtFileName.intImageWidth  = elmSelectedImage.width;
          txtVertical.value          = elmSelectedImage.vspace;
          txtHorizontal.value        = elmSelectedImage.hspace;
          txtBorder.value            = elmSelectedImage.border;
          txtAltText.value           = elmSelectedImage.alt;
          selAlignment.value         = elmSelectedImage.align;
        }
      }
    }
  }
  txtFileName.value = txtFileName.value || "http://";
  txtFileName.focus();
}

function _isValidNumber(txtBox) {
  var val = parseInt(txtBox);
  if (isNaN(val) || val < 0 || val > 999) { return false; }
  return true;
}

function btnOKClick() {
  var elmImage;
  var intAlignment;
  var htmlSelectionControl = "Control";
  var globalDoc = window.dialogArguments;
  var grngMaster = globalDoc.selection.createRange();
  
  // error checking

  if (!txtFileName.value || txtFileName.value == "http://") { 
    alert("Image URL must be specified.");
    txtFileName.focus();
    return;
  }
  if (txtHorizontal.value && !_isValidNumber(txtHorizontal.value)) {
    alert("Horizontal spacing must be a number between 0 and 999.");
    txtHorizontal.focus();
    return;
  }
  if (txtBorder.value && !_isValidNumber(txtBorder.value)) {
    alert("Border thickness must be a number between 0 and 999.");
    txtBorder.focus();
    return;
  }
  if (txtVertical.value && !_isValidNumber(txtVertical.value)) {
    alert("Vertical spacing must be a number between 0 and 999.");
    txtVertical.focus();
    return;
  }

  // delete selected content and replace with image
  if (globalDoc.selection.type == htmlSelectionControl && !txtFileName.fImageLoaded) {
    grngMaster.execCommand('Delete');
    grngMaster = globalDoc.selection.createRange();
  }
    
  idstr = "\" id=\"556e697175657e537472696e67";     // new image creation ID
  if (!txtFileName.fImageLoaded) {
    grngMaster.execCommand("InsertImage", false, idstr);
    elmImage = globalDoc.all['556e697175657e537472696e67'];
    elmImage.removeAttribute("id");
    elmImage.removeAttribute("src");
    grngMaster.moveStart("character", -1);
  } else {
    elmImage = grngMaster.item(0);
    if (elmImage.src != txtFileName.value) {
      grngMaster.execCommand('Delete');
      grngMaster = globalDoc.selection.createRange();
      grngMaster.execCommand("InsertImage", false, idstr);
      elmImage = globalDoc.all['556e697175657e537472696e67'];
      elmImage.removeAttribute("id");
      elmImage.removeAttribute("src");
      grngMaster.moveStart("character", -1);
      txtFileName.fImageLoaded = false;
    }
    grngMaster = _getTextRange(elmImage);
  }

  if (txtFileName.fImageLoaded) {
    elmImage.style.width = txtFileName.intImageWidth;
    elmImage.style.height = txtFileName.intImageHeight;
  }

  if (txtFileName.value.length > 2040) {
    txtFileName.value = txtFileName.value.substring(0,2040);
  }
  
  elmImage.src = txtFileName.value;
  
  if (txtHorizontal.value != "") { elmImage.hspace = parseInt(txtHorizontal.value); }
  else                           { elmImage.hspace = 0; }

  if (txtVertical.value != "") { elmImage.vspace = parseInt(txtVertical.value); }
  else                         { elmImage.vspace = 0; }
  
  elmImage.alt = txtAltText.value;

  if (txtBorder.value != "") { elmImage.border = parseInt(txtBorder.value); }
  else                       { elmImage.border = 0; }

  elmImage.align = selAlignment.value;
  grngMaster.collapse(false);
  grngMaster.select();
  window.close();
}
</SCRIPT>
</HEAD>
<BODY id=bdy onload="Init()" style="background: threedface; color: windowtext;" scroll=no>

<DIV id=divFileName style="left: 0.98em; top: 1.2168em; width: 7em; height: 1.2168em; ">Image URL:</DIV>
<INPUT ID=txtFileName type=text style="left: 8.54em; top: 1.0647em; width: 21.5em;height: 2.1294em; " tabIndex=10 onfocus="select()">

<DIV id=divAltText style="left: 0.98em; top: 4.1067em; width: 6.58em; height: 1.2168em; ">Alternate Text:</DIV>
<INPUT type=text ID=txtAltText tabIndex=15 style="left: 8.54em; top: 3.8025em; width: 21.5em; height: 2.1294em; " onfocus="select()">

<FIELDSET id=fldLayout style="left: .9em; top: 7.1em; width: 17.08em; height: 7.6em;">
<LEGEND id=lgdLayout>Layout</LEGEND>
</FIELDSET>

<FIELDSET id=fldSpacing style="left: 18.9em; top: 7.1em; width: 11em; height: 7.6em;">
<LEGEND id=lgdSpacing>Spacing</LEGEND>
</FIELDSET>

<DIV id=divAlign style="left: 1.82em; top: 9.126em; width: 4.76em; height: 1.2168em; ">Alignment:</DIV>
<SELECT size=1 ID=selAlignment tabIndex=20 style="left: 10.36em; top: 8.8218em; width: 6.72em; height: 1.2168em; ">
<OPTION id=optNotSet value=""> Not set </OPTION>
<OPTION id=optLeft value=left> Left </OPTION>
<OPTION id=optRight value=right> Right </OPTION>
<OPTION id=optTexttop value=textTop> Texttop </OPTION>
<OPTION id=optAbsMiddle value=absMiddle> Absmiddle </OPTION>
<OPTION id=optBaseline value=baseline SELECTED> Baseline </OPTION>
<OPTION id=optAbsBottom value=absBottom> Absbottom </OPTION>
<OPTION id=optBottom value=bottom> Bottom </OPTION>
<OPTION id=optMiddle value=middle> Middle </OPTION>
<OPTION id=optTop value=top> Top </OPTION>
</SELECT>

<DIV id=divHoriz style="left: 19.88em; top: 9.126em; width: 4.76em; height: 1.2168em; ">Horizontal:</DIV>
<INPUT ID=txtHorizontal style="left: 24.92em; top: 8.8218em; width: 4.2em; height: 2.1294em; ime-mode: disabled;" type=text size=3 maxlength=3 value="" tabIndex=25 onfocus="select()">

<DIV id=divBorder style="left: 1.82em; top: 12.0159em; width: 8.12em; height: 1.2168em; ">Border Thickness:</DIV>
<INPUT ID=txtBorder style="left: 10.36em; top: 11.5596em; width: 6.72em; height: 2.1294em; ime-mode: disabled;" type=text size=3 maxlength=3 value="" tabIndex=21 onfocus="select()">

<DIV id=divVert style="left: 19.88em; top: 12.0159em; width: 3.64em; height: 1.2168em; ">Vertical:</DIV>
<INPUT ID=txtVertical style="left: 24.92em; top: 11.5596em; width: 4.2em; height: 2.1294em; ime-mode: disabled;" type=text size=3 maxlength=3 value="" tabIndex=30 onfocus="select()">

<BUTTON ID=btnOK style="left: 31.36em; top: 1.0647em; width: 7em; height: 2.2em; " type=submit tabIndex=40>OK</BUTTON>
<BUTTON ID=btnCancel style="left: 31.36em; top: 3.6504em; width: 7em; height: 2.2em; " type=reset tabIndex=45 onClick="window.close();">Cancel</BUTTON>

</BODY>
</HTML>
Index: loncom/html/htmlarea/popups/popup.js
+++ loncom/html/htmlarea/popups/popup.js
function __dlg_onclose() {
	if (!document.all) {
		opener.Dialog._return(null);
	}
};

function __dlg_init() {
	if (!document.all) {
		// init dialogArguments, as IE gets it
		window.dialogArguments = opener.Dialog._arguments;
		window.sizeToContent();
		window.sizeToContent();	// for reasons beyond understanding,
					// only if we call it twice we get the
					// correct size.
		window.addEventListener("unload", __dlg_onclose, true);
		// center on parent
		var px1 = opener.screenX;
		var px2 = opener.screenX + opener.outerWidth;
		var py1 = opener.screenY;
		var py2 = opener.screenY + opener.outerHeight;
		var x = (px2 - px1 - window.outerWidth) / 2;
		var y = (py2 - py1 - window.outerHeight) / 2;
		window.moveTo(x, y);
		var body = document.body;
		window.innerHeight = body.offsetHeight;
		window.innerWidth = body.offsetWidth;
	} else {
		var body = document.body;
		window.dialogHeight = body.offsetHeight + 50 + "px";
		window.dialogWidth = body.offsetWidth + "px";
	}
};

// closes the dialog and passes the return info upper.
function __dlg_close(val) {
	if (document.all) {	// IE
		window.returnValue = val;
	} else {
		opener.Dialog._return(val);
	}
	window.close();
};

Index: loncom/html/htmlarea/popups/select_color.html
+++ loncom/html/htmlarea/popups/select_color.html
<!-- note: this version of the color picker is optimized for IE 5.5+ only -->

<html style="width: 238px; height: 182px"><head><title>Select Color</title>

<script type="text/javascript" src="popup.js"></script>

<script type="text/javascript">

function _CloseOnEsc() {
  if (event.keyCode == 27) { window.close(); return; }
}

function Init() {                                                       // run on page load
  __dlg_init();    // <!-- this can be found in popup.js -->
  document.body.onkeypress = _CloseOnEsc;

  var color = window.dialogArguments;
  color = ValidateColor(color) || '000000';
  View(color);                                                          // set default color
}

function View(color) {                  // preview color
  document.getElementById("ColorPreview").style.backgroundColor = '#' + color;
  document.getElementById("ColorHex").value = '#' + color;
}

function Set(string) {                   // select color
  var color = ValidateColor(string);
  if (color == null) { alert("Invalid color code: " + string); }        // invalid color
  else {                                                                // valid color
    View(color);                          // show selected color
    __dlg_close(color);
  }
}

function ValidateColor(string) {                // return valid color code
  string = string || '';
  string = string + "";
  string = string.toUpperCase();
  var chars = '0123456789ABCDEF';
  var out   = '';

  for (var i=0; i<string.length; i++) {             // remove invalid color chars
    var schar = string.charAt(i);
    if (chars.indexOf(schar) != -1) { out += schar; }
  }

  if (out.length != 6) { return null; }            // check length
  return out;
}

</script>
</head>
<body style="background:ButtonFace; margin:0px; padding:0px" onload="Init()">

<form method="get" style="margin:0px; padding:0px" onSubmit="Set(document.getElementById('ColorHex').value); return false;">
<table border="0px" cellspacing="0px" cellpadding="4" width="100%">
 <tr>
  <td style="background:buttonface" valign=center><div style="background-color: #000000; padding: 1; height: 21px; width: 50px"><div id="ColorPreview" style="height: 100%; width: 100%"></div></div></td>
  <td style="background:buttonface" valign=center><input type="text" name="ColorHex"
    id="ColorHex" value="" size=15 style="font-size: 12px"></td>
  <td style="background:buttonface" width=100%></td>
 </tr>
</table>
</form>

<table border="0" cellspacing="1px" cellpadding="0px" width="100%" bgcolor="#000000" style="cursor: hand;">
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#003300 onMouseOver=View('003300') onClick=Set('003300') height="10px" width="10px"></td>
<td bgcolor=#006600 onMouseOver=View('006600') onClick=Set('006600') height="10px" width="10px"></td>
<td bgcolor=#009900 onMouseOver=View('009900') onClick=Set('009900') height="10px" width="10px"></td>
<td bgcolor=#00CC00 onMouseOver=View('00CC00') onClick=Set('00CC00') height="10px" width="10px"></td>
<td bgcolor=#00FF00 onMouseOver=View('00FF00') onClick=Set('00FF00') height="10px" width="10px"></td>
<td bgcolor=#330000 onMouseOver=View('330000') onClick=Set('330000') height="10px" width="10px"></td>
<td bgcolor=#333300 onMouseOver=View('333300') onClick=Set('333300') height="10px" width="10px"></td>
<td bgcolor=#336600 onMouseOver=View('336600') onClick=Set('336600') height="10px" width="10px"></td>
<td bgcolor=#339900 onMouseOver=View('339900') onClick=Set('339900') height="10px" width="10px"></td>
<td bgcolor=#33CC00 onMouseOver=View('33CC00') onClick=Set('33CC00') height="10px" width="10px"></td>
<td bgcolor=#33FF00 onMouseOver=View('33FF00') onClick=Set('33FF00') height="10px" width="10px"></td>
<td bgcolor=#660000 onMouseOver=View('660000') onClick=Set('660000') height="10px" width="10px"></td>
<td bgcolor=#663300 onMouseOver=View('663300') onClick=Set('663300') height="10px" width="10px"></td>
<td bgcolor=#666600 onMouseOver=View('666600') onClick=Set('666600') height="10px" width="10px"></td>
<td bgcolor=#669900 onMouseOver=View('669900') onClick=Set('669900') height="10px" width="10px"></td>
<td bgcolor=#66CC00 onMouseOver=View('66CC00') onClick=Set('66CC00') height="10px" width="10px"></td>
<td bgcolor=#66FF00 onMouseOver=View('66FF00') onClick=Set('66FF00') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#333333 onMouseOver=View('333333') onClick=Set('333333') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#000033 onMouseOver=View('000033') onClick=Set('000033') height="10px" width="10px"></td>
<td bgcolor=#003333 onMouseOver=View('003333') onClick=Set('003333') height="10px" width="10px"></td>
<td bgcolor=#006633 onMouseOver=View('006633') onClick=Set('006633') height="10px" width="10px"></td>
<td bgcolor=#009933 onMouseOver=View('009933') onClick=Set('009933') height="10px" width="10px"></td>
<td bgcolor=#00CC33 onMouseOver=View('00CC33') onClick=Set('00CC33') height="10px" width="10px"></td>
<td bgcolor=#00FF33 onMouseOver=View('00FF33') onClick=Set('00FF33') height="10px" width="10px"></td>
<td bgcolor=#330033 onMouseOver=View('330033') onClick=Set('330033') height="10px" width="10px"></td>
<td bgcolor=#333333 onMouseOver=View('333333') onClick=Set('333333') height="10px" width="10px"></td>
<td bgcolor=#336633 onMouseOver=View('336633') onClick=Set('336633') height="10px" width="10px"></td>
<td bgcolor=#339933 onMouseOver=View('339933') onClick=Set('339933') height="10px" width="10px"></td>
<td bgcolor=#33CC33 onMouseOver=View('33CC33') onClick=Set('33CC33') height="10px" width="10px"></td>
<td bgcolor=#33FF33 onMouseOver=View('33FF33') onClick=Set('33FF33') height="10px" width="10px"></td>
<td bgcolor=#660033 onMouseOver=View('660033') onClick=Set('660033') height="10px" width="10px"></td>
<td bgcolor=#663333 onMouseOver=View('663333') onClick=Set('663333') height="10px" width="10px"></td>
<td bgcolor=#666633 onMouseOver=View('666633') onClick=Set('666633') height="10px" width="10px"></td>
<td bgcolor=#669933 onMouseOver=View('669933') onClick=Set('669933') height="10px" width="10px"></td>
<td bgcolor=#66CC33 onMouseOver=View('66CC33') onClick=Set('66CC33') height="10px" width="10px"></td>
<td bgcolor=#66FF33 onMouseOver=View('66FF33') onClick=Set('66FF33') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#666666 onMouseOver=View('666666') onClick=Set('666666') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#000066 onMouseOver=View('000066') onClick=Set('000066') height="10px" width="10px"></td>
<td bgcolor=#003366 onMouseOver=View('003366') onClick=Set('003366') height="10px" width="10px"></td>
<td bgcolor=#006666 onMouseOver=View('006666') onClick=Set('006666') height="10px" width="10px"></td>
<td bgcolor=#009966 onMouseOver=View('009966') onClick=Set('009966') height="10px" width="10px"></td>
<td bgcolor=#00CC66 onMouseOver=View('00CC66') onClick=Set('00CC66') height="10px" width="10px"></td>
<td bgcolor=#00FF66 onMouseOver=View('00FF66') onClick=Set('00FF66') height="10px" width="10px"></td>
<td bgcolor=#330066 onMouseOver=View('330066') onClick=Set('330066') height="10px" width="10px"></td>
<td bgcolor=#333366 onMouseOver=View('333366') onClick=Set('333366') height="10px" width="10px"></td>
<td bgcolor=#336666 onMouseOver=View('336666') onClick=Set('336666') height="10px" width="10px"></td>
<td bgcolor=#339966 onMouseOver=View('339966') onClick=Set('339966') height="10px" width="10px"></td>
<td bgcolor=#33CC66 onMouseOver=View('33CC66') onClick=Set('33CC66') height="10px" width="10px"></td>
<td bgcolor=#33FF66 onMouseOver=View('33FF66') onClick=Set('33FF66') height="10px" width="10px"></td>
<td bgcolor=#660066 onMouseOver=View('660066') onClick=Set('660066') height="10px" width="10px"></td>
<td bgcolor=#663366 onMouseOver=View('663366') onClick=Set('663366') height="10px" width="10px"></td>
<td bgcolor=#666666 onMouseOver=View('666666') onClick=Set('666666') height="10px" width="10px"></td>
<td bgcolor=#669966 onMouseOver=View('669966') onClick=Set('669966') height="10px" width="10px"></td>
<td bgcolor=#66CC66 onMouseOver=View('66CC66') onClick=Set('66CC66') height="10px" width="10px"></td>
<td bgcolor=#66FF66 onMouseOver=View('66FF66') onClick=Set('66FF66') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#999999 onMouseOver=View('999999') onClick=Set('999999') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#000099 onMouseOver=View('000099') onClick=Set('000099') height="10px" width="10px"></td>
<td bgcolor=#003399 onMouseOver=View('003399') onClick=Set('003399') height="10px" width="10px"></td>
<td bgcolor=#006699 onMouseOver=View('006699') onClick=Set('006699') height="10px" width="10px"></td>
<td bgcolor=#009999 onMouseOver=View('009999') onClick=Set('009999') height="10px" width="10px"></td>
<td bgcolor=#00CC99 onMouseOver=View('00CC99') onClick=Set('00CC99') height="10px" width="10px"></td>
<td bgcolor=#00FF99 onMouseOver=View('00FF99') onClick=Set('00FF99') height="10px" width="10px"></td>
<td bgcolor=#330099 onMouseOver=View('330099') onClick=Set('330099') height="10px" width="10px"></td>
<td bgcolor=#333399 onMouseOver=View('333399') onClick=Set('333399') height="10px" width="10px"></td>
<td bgcolor=#336699 onMouseOver=View('336699') onClick=Set('336699') height="10px" width="10px"></td>
<td bgcolor=#339999 onMouseOver=View('339999') onClick=Set('339999') height="10px" width="10px"></td>
<td bgcolor=#33CC99 onMouseOver=View('33CC99') onClick=Set('33CC99') height="10px" width="10px"></td>
<td bgcolor=#33FF99 onMouseOver=View('33FF99') onClick=Set('33FF99') height="10px" width="10px"></td>
<td bgcolor=#660099 onMouseOver=View('660099') onClick=Set('660099') height="10px" width="10px"></td>
<td bgcolor=#663399 onMouseOver=View('663399') onClick=Set('663399') height="10px" width="10px"></td>
<td bgcolor=#666699 onMouseOver=View('666699') onClick=Set('666699') height="10px" width="10px"></td>
<td bgcolor=#669999 onMouseOver=View('669999') onClick=Set('669999') height="10px" width="10px"></td>
<td bgcolor=#66CC99 onMouseOver=View('66CC99') onClick=Set('66CC99') height="10px" width="10px"></td>
<td bgcolor=#66FF99 onMouseOver=View('66FF99') onClick=Set('66FF99') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#CCCCCC onMouseOver=View('CCCCCC') onClick=Set('CCCCCC') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#0000CC onMouseOver=View('0000CC') onClick=Set('0000CC') height="10px" width="10px"></td>
<td bgcolor=#0033CC onMouseOver=View('0033CC') onClick=Set('0033CC') height="10px" width="10px"></td>
<td bgcolor=#0066CC onMouseOver=View('0066CC') onClick=Set('0066CC') height="10px" width="10px"></td>
<td bgcolor=#0099CC onMouseOver=View('0099CC') onClick=Set('0099CC') height="10px" width="10px"></td>
<td bgcolor=#00CCCC onMouseOver=View('00CCCC') onClick=Set('00CCCC') height="10px" width="10px"></td>
<td bgcolor=#00FFCC onMouseOver=View('00FFCC') onClick=Set('00FFCC') height="10px" width="10px"></td>
<td bgcolor=#3300CC onMouseOver=View('3300CC') onClick=Set('3300CC') height="10px" width="10px"></td>
<td bgcolor=#3333CC onMouseOver=View('3333CC') onClick=Set('3333CC') height="10px" width="10px"></td>
<td bgcolor=#3366CC onMouseOver=View('3366CC') onClick=Set('3366CC') height="10px" width="10px"></td>
<td bgcolor=#3399CC onMouseOver=View('3399CC') onClick=Set('3399CC') height="10px" width="10px"></td>
<td bgcolor=#33CCCC onMouseOver=View('33CCCC') onClick=Set('33CCCC') height="10px" width="10px"></td>
<td bgcolor=#33FFCC onMouseOver=View('33FFCC') onClick=Set('33FFCC') height="10px" width="10px"></td>
<td bgcolor=#6600CC onMouseOver=View('6600CC') onClick=Set('6600CC') height="10px" width="10px"></td>
<td bgcolor=#6633CC onMouseOver=View('6633CC') onClick=Set('6633CC') height="10px" width="10px"></td>
<td bgcolor=#6666CC onMouseOver=View('6666CC') onClick=Set('6666CC') height="10px" width="10px"></td>
<td bgcolor=#6699CC onMouseOver=View('6699CC') onClick=Set('6699CC') height="10px" width="10px"></td>
<td bgcolor=#66CCCC onMouseOver=View('66CCCC') onClick=Set('66CCCC') height="10px" width="10px"></td>
<td bgcolor=#66FFCC onMouseOver=View('66FFCC') onClick=Set('66FFCC') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#FFFFFF onMouseOver=View('FFFFFF') onClick=Set('FFFFFF') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#0000FF onMouseOver=View('0000FF') onClick=Set('0000FF') height="10px" width="10px"></td>
<td bgcolor=#0033FF onMouseOver=View('0033FF') onClick=Set('0033FF') height="10px" width="10px"></td>
<td bgcolor=#0066FF onMouseOver=View('0066FF') onClick=Set('0066FF') height="10px" width="10px"></td>
<td bgcolor=#0099FF onMouseOver=View('0099FF') onClick=Set('0099FF') height="10px" width="10px"></td>
<td bgcolor=#00CCFF onMouseOver=View('00CCFF') onClick=Set('00CCFF') height="10px" width="10px"></td>
<td bgcolor=#00FFFF onMouseOver=View('00FFFF') onClick=Set('00FFFF') height="10px" width="10px"></td>
<td bgcolor=#3300FF onMouseOver=View('3300FF') onClick=Set('3300FF') height="10px" width="10px"></td>
<td bgcolor=#3333FF onMouseOver=View('3333FF') onClick=Set('3333FF') height="10px" width="10px"></td>
<td bgcolor=#3366FF onMouseOver=View('3366FF') onClick=Set('3366FF') height="10px" width="10px"></td>
<td bgcolor=#3399FF onMouseOver=View('3399FF') onClick=Set('3399FF') height="10px" width="10px"></td>
<td bgcolor=#33CCFF onMouseOver=View('33CCFF') onClick=Set('33CCFF') height="10px" width="10px"></td>
<td bgcolor=#33FFFF onMouseOver=View('33FFFF') onClick=Set('33FFFF') height="10px" width="10px"></td>
<td bgcolor=#6600FF onMouseOver=View('6600FF') onClick=Set('6600FF') height="10px" width="10px"></td>
<td bgcolor=#6633FF onMouseOver=View('6633FF') onClick=Set('6633FF') height="10px" width="10px"></td>
<td bgcolor=#6666FF onMouseOver=View('6666FF') onClick=Set('6666FF') height="10px" width="10px"></td>
<td bgcolor=#6699FF onMouseOver=View('6699FF') onClick=Set('6699FF') height="10px" width="10px"></td>
<td bgcolor=#66CCFF onMouseOver=View('66CCFF') onClick=Set('66CCFF') height="10px" width="10px"></td>
<td bgcolor=#66FFFF onMouseOver=View('66FFFF') onClick=Set('66FFFF') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#FF0000 onMouseOver=View('FF0000') onClick=Set('FF0000') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#990000 onMouseOver=View('990000') onClick=Set('990000') height="10px" width="10px"></td>
<td bgcolor=#993300 onMouseOver=View('993300') onClick=Set('993300') height="10px" width="10px"></td>
<td bgcolor=#996600 onMouseOver=View('996600') onClick=Set('996600') height="10px" width="10px"></td>
<td bgcolor=#999900 onMouseOver=View('999900') onClick=Set('999900') height="10px" width="10px"></td>
<td bgcolor=#99CC00 onMouseOver=View('99CC00') onClick=Set('99CC00') height="10px" width="10px"></td>
<td bgcolor=#99FF00 onMouseOver=View('99FF00') onClick=Set('99FF00') height="10px" width="10px"></td>
<td bgcolor=#CC0000 onMouseOver=View('CC0000') onClick=Set('CC0000') height="10px" width="10px"></td>
<td bgcolor=#CC3300 onMouseOver=View('CC3300') onClick=Set('CC3300') height="10px" width="10px"></td>
<td bgcolor=#CC6600 onMouseOver=View('CC6600') onClick=Set('CC6600') height="10px" width="10px"></td>
<td bgcolor=#CC9900 onMouseOver=View('CC9900') onClick=Set('CC9900') height="10px" width="10px"></td>
<td bgcolor=#CCCC00 onMouseOver=View('CCCC00') onClick=Set('CCCC00') height="10px" width="10px"></td>
<td bgcolor=#CCFF00 onMouseOver=View('CCFF00') onClick=Set('CCFF00') height="10px" width="10px"></td>
<td bgcolor=#FF0000 onMouseOver=View('FF0000') onClick=Set('FF0000') height="10px" width="10px"></td>
<td bgcolor=#FF3300 onMouseOver=View('FF3300') onClick=Set('FF3300') height="10px" width="10px"></td>
<td bgcolor=#FF6600 onMouseOver=View('FF6600') onClick=Set('FF6600') height="10px" width="10px"></td>
<td bgcolor=#FF9900 onMouseOver=View('FF9900') onClick=Set('FF9900') height="10px" width="10px"></td>
<td bgcolor=#FFCC00 onMouseOver=View('FFCC00') onClick=Set('FFCC00') height="10px" width="10px"></td>
<td bgcolor=#FFFF00 onMouseOver=View('FFFF00') onClick=Set('FFFF00') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#00FF00 onMouseOver=View('00FF00') onClick=Set('00FF00') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#990033 onMouseOver=View('990033') onClick=Set('990033') height="10px" width="10px"></td>
<td bgcolor=#993333 onMouseOver=View('993333') onClick=Set('993333') height="10px" width="10px"></td>
<td bgcolor=#996633 onMouseOver=View('996633') onClick=Set('996633') height="10px" width="10px"></td>
<td bgcolor=#999933 onMouseOver=View('999933') onClick=Set('999933') height="10px" width="10px"></td>
<td bgcolor=#99CC33 onMouseOver=View('99CC33') onClick=Set('99CC33') height="10px" width="10px"></td>
<td bgcolor=#99FF33 onMouseOver=View('99FF33') onClick=Set('99FF33') height="10px" width="10px"></td>
<td bgcolor=#CC0033 onMouseOver=View('CC0033') onClick=Set('CC0033') height="10px" width="10px"></td>
<td bgcolor=#CC3333 onMouseOver=View('CC3333') onClick=Set('CC3333') height="10px" width="10px"></td>
<td bgcolor=#CC6633 onMouseOver=View('CC6633') onClick=Set('CC6633') height="10px" width="10px"></td>
<td bgcolor=#CC9933 onMouseOver=View('CC9933') onClick=Set('CC9933') height="10px" width="10px"></td>
<td bgcolor=#CCCC33 onMouseOver=View('CCCC33') onClick=Set('CCCC33') height="10px" width="10px"></td>
<td bgcolor=#CCFF33 onMouseOver=View('CCFF33') onClick=Set('CCFF33') height="10px" width="10px"></td>
<td bgcolor=#FF0033 onMouseOver=View('FF0033') onClick=Set('FF0033') height="10px" width="10px"></td>
<td bgcolor=#FF3333 onMouseOver=View('FF3333') onClick=Set('FF3333') height="10px" width="10px"></td>
<td bgcolor=#FF6633 onMouseOver=View('FF6633') onClick=Set('FF6633') height="10px" width="10px"></td>
<td bgcolor=#FF9933 onMouseOver=View('FF9933') onClick=Set('FF9933') height="10px" width="10px"></td>
<td bgcolor=#FFCC33 onMouseOver=View('FFCC33') onClick=Set('FFCC33') height="10px" width="10px"></td>
<td bgcolor=#FFFF33 onMouseOver=View('FFFF33') onClick=Set('FFFF33') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#0000FF onMouseOver=View('0000FF') onClick=Set('0000FF') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#990066 onMouseOver=View('990066') onClick=Set('990066') height="10px" width="10px"></td>
<td bgcolor=#993366 onMouseOver=View('993366') onClick=Set('993366') height="10px" width="10px"></td>
<td bgcolor=#996666 onMouseOver=View('996666') onClick=Set('996666') height="10px" width="10px"></td>
<td bgcolor=#999966 onMouseOver=View('999966') onClick=Set('999966') height="10px" width="10px"></td>
<td bgcolor=#99CC66 onMouseOver=View('99CC66') onClick=Set('99CC66') height="10px" width="10px"></td>
<td bgcolor=#99FF66 onMouseOver=View('99FF66') onClick=Set('99FF66') height="10px" width="10px"></td>
<td bgcolor=#CC0066 onMouseOver=View('CC0066') onClick=Set('CC0066') height="10px" width="10px"></td>
<td bgcolor=#CC3366 onMouseOver=View('CC3366') onClick=Set('CC3366') height="10px" width="10px"></td>
<td bgcolor=#CC6666 onMouseOver=View('CC6666') onClick=Set('CC6666') height="10px" width="10px"></td>
<td bgcolor=#CC9966 onMouseOver=View('CC9966') onClick=Set('CC9966') height="10px" width="10px"></td>
<td bgcolor=#CCCC66 onMouseOver=View('CCCC66') onClick=Set('CCCC66') height="10px" width="10px"></td>
<td bgcolor=#CCFF66 onMouseOver=View('CCFF66') onClick=Set('CCFF66') height="10px" width="10px"></td>
<td bgcolor=#FF0066 onMouseOver=View('FF0066') onClick=Set('FF0066') height="10px" width="10px"></td>
<td bgcolor=#FF3366 onMouseOver=View('FF3366') onClick=Set('FF3366') height="10px" width="10px"></td>
<td bgcolor=#FF6666 onMouseOver=View('FF6666') onClick=Set('FF6666') height="10px" width="10px"></td>
<td bgcolor=#FF9966 onMouseOver=View('FF9966') onClick=Set('FF9966') height="10px" width="10px"></td>
<td bgcolor=#FFCC66 onMouseOver=View('FFCC66') onClick=Set('FFCC66') height="10px" width="10px"></td>
<td bgcolor=#FFFF66 onMouseOver=View('FFFF66') onClick=Set('FFFF66') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#FFFF00 onMouseOver=View('FFFF00') onClick=Set('FFFF00') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#990099 onMouseOver=View('990099') onClick=Set('990099') height="10px" width="10px"></td>
<td bgcolor=#993399 onMouseOver=View('993399') onClick=Set('993399') height="10px" width="10px"></td>
<td bgcolor=#996699 onMouseOver=View('996699') onClick=Set('996699') height="10px" width="10px"></td>
<td bgcolor=#999999 onMouseOver=View('999999') onClick=Set('999999') height="10px" width="10px"></td>
<td bgcolor=#99CC99 onMouseOver=View('99CC99') onClick=Set('99CC99') height="10px" width="10px"></td>
<td bgcolor=#99FF99 onMouseOver=View('99FF99') onClick=Set('99FF99') height="10px" width="10px"></td>
<td bgcolor=#CC0099 onMouseOver=View('CC0099') onClick=Set('CC0099') height="10px" width="10px"></td>
<td bgcolor=#CC3399 onMouseOver=View('CC3399') onClick=Set('CC3399') height="10px" width="10px"></td>
<td bgcolor=#CC6699 onMouseOver=View('CC6699') onClick=Set('CC6699') height="10px" width="10px"></td>
<td bgcolor=#CC9999 onMouseOver=View('CC9999') onClick=Set('CC9999') height="10px" width="10px"></td>
<td bgcolor=#CCCC99 onMouseOver=View('CCCC99') onClick=Set('CCCC99') height="10px" width="10px"></td>
<td bgcolor=#CCFF99 onMouseOver=View('CCFF99') onClick=Set('CCFF99') height="10px" width="10px"></td>
<td bgcolor=#FF0099 onMouseOver=View('FF0099') onClick=Set('FF0099') height="10px" width="10px"></td>
<td bgcolor=#FF3399 onMouseOver=View('FF3399') onClick=Set('FF3399') height="10px" width="10px"></td>
<td bgcolor=#FF6699 onMouseOver=View('FF6699') onClick=Set('FF6699') height="10px" width="10px"></td>
<td bgcolor=#FF9999 onMouseOver=View('FF9999') onClick=Set('FF9999') height="10px" width="10px"></td>
<td bgcolor=#FFCC99 onMouseOver=View('FFCC99') onClick=Set('FFCC99') height="10px" width="10px"></td>
<td bgcolor=#FFFF99 onMouseOver=View('FFFF99') onClick=Set('FFFF99') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#00FFFF onMouseOver=View('00FFFF') onClick=Set('00FFFF') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#9900CC onMouseOver=View('9900CC') onClick=Set('9900CC') height="10px" width="10px"></td>
<td bgcolor=#9933CC onMouseOver=View('9933CC') onClick=Set('9933CC') height="10px" width="10px"></td>
<td bgcolor=#9966CC onMouseOver=View('9966CC') onClick=Set('9966CC') height="10px" width="10px"></td>
<td bgcolor=#9999CC onMouseOver=View('9999CC') onClick=Set('9999CC') height="10px" width="10px"></td>
<td bgcolor=#99CCCC onMouseOver=View('99CCCC') onClick=Set('99CCCC') height="10px" width="10px"></td>
<td bgcolor=#99FFCC onMouseOver=View('99FFCC') onClick=Set('99FFCC') height="10px" width="10px"></td>
<td bgcolor=#CC00CC onMouseOver=View('CC00CC') onClick=Set('CC00CC') height="10px" width="10px"></td>
<td bgcolor=#CC33CC onMouseOver=View('CC33CC') onClick=Set('CC33CC') height="10px" width="10px"></td>
<td bgcolor=#CC66CC onMouseOver=View('CC66CC') onClick=Set('CC66CC') height="10px" width="10px"></td>
<td bgcolor=#CC99CC onMouseOver=View('CC99CC') onClick=Set('CC99CC') height="10px" width="10px"></td>
<td bgcolor=#CCCCCC onMouseOver=View('CCCCCC') onClick=Set('CCCCCC') height="10px" width="10px"></td>
<td bgcolor=#CCFFCC onMouseOver=View('CCFFCC') onClick=Set('CCFFCC') height="10px" width="10px"></td>
<td bgcolor=#FF00CC onMouseOver=View('FF00CC') onClick=Set('FF00CC') height="10px" width="10px"></td>
<td bgcolor=#FF33CC onMouseOver=View('FF33CC') onClick=Set('FF33CC') height="10px" width="10px"></td>
<td bgcolor=#FF66CC onMouseOver=View('FF66CC') onClick=Set('FF66CC') height="10px" width="10px"></td>
<td bgcolor=#FF99CC onMouseOver=View('FF99CC') onClick=Set('FF99CC') height="10px" width="10px"></td>
<td bgcolor=#FFCCCC onMouseOver=View('FFCCCC') onClick=Set('FFCCCC') height="10px" width="10px"></td>
<td bgcolor=#FFFFCC onMouseOver=View('FFFFCC') onClick=Set('FFFFCC') height="10px" width="10px"></td>
</tr>
<tr>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#FF00FF onMouseOver=View('FF00FF') onClick=Set('FF00FF') height="10px" width="10px"></td>
<td bgcolor=#000000 onMouseOver=View('000000') onClick=Set('000000') height="10px" width="10px"></td>
<td bgcolor=#9900FF onMouseOver=View('9900FF') onClick=Set('9900FF') height="10px" width="10px"></td>
<td bgcolor=#9933FF onMouseOver=View('9933FF') onClick=Set('9933FF') height="10px" width="10px"></td>
<td bgcolor=#9966FF onMouseOver=View('9966FF') onClick=Set('9966FF') height="10px" width="10px"></td>
<td bgcolor=#9999FF onMouseOver=View('9999FF') onClick=Set('9999FF') height="10px" width="10px"></td>
<td bgcolor=#99CCFF onMouseOver=View('99CCFF') onClick=Set('99CCFF') height="10px" width="10px"></td>
<td bgcolor=#99FFFF onMouseOver=View('99FFFF') onClick=Set('99FFFF') height="10px" width="10px"></td>
<td bgcolor=#CC00FF onMouseOver=View('CC00FF') onClick=Set('CC00FF') height="10px" width="10px"></td>
<td bgcolor=#CC33FF onMouseOver=View('CC33FF') onClick=Set('CC33FF') height="10px" width="10px"></td>
<td bgcolor=#CC66FF onMouseOver=View('CC66FF') onClick=Set('CC66FF') height="10px" width="10px"></td>
<td bgcolor=#CC99FF onMouseOver=View('CC99FF') onClick=Set('CC99FF') height="10px" width="10px"></td>
<td bgcolor=#CCCCFF onMouseOver=View('CCCCFF') onClick=Set('CCCCFF') height="10px" width="10px"></td>
<td bgcolor=#CCFFFF onMouseOver=View('CCFFFF') onClick=Set('CCFFFF') height="10px" width="10px"></td>
<td bgcolor=#FF00FF onMouseOver=View('FF00FF') onClick=Set('FF00FF') height="10px" width="10px"></td>
<td bgcolor=#FF33FF onMouseOver=View('FF33FF') onClick=Set('FF33FF') height="10px" width="10px"></td>
<td bgcolor=#FF66FF onMouseOver=View('FF66FF') onClick=Set('FF66FF') height="10px" width="10px"></td>
<td bgcolor=#FF99FF onMouseOver=View('FF99FF') onClick=Set('FF99FF') height="10px" width="10px"></td>
<td bgcolor=#FFCCFF onMouseOver=View('FFCCFF') onClick=Set('FFCCFF') height="10px" width="10px"></td>
<td bgcolor=#FFFFFF onMouseOver=View('FFFFFF') onClick=Set('FFFFFF') height="10px" width="10px"></td>
</tr>
</table>

</body></html>

--www1077091636--