//// htmlArea v2.03 - 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///// write out styles for UI buttonsdocument.write('<style type="text/css">\n');document.write('.btn     { width: 22px; height: 22px; border: 1px solid buttonface; margin: 0; padding: 0; }\n');document.write('.btnOver { width: 22px; height: 22px; border: 1px outset; }\n');document.write('.btnDown { width: 22px; height: 22px; border: 1px inset; background-color: buttonhighlight; }\n');document.write('.btnNA   { width: 22px; height: 22px; border: 1px solid buttonface; filter: alpha(opacity=25); }\n');document.write('.cMenu     { background-color: threedface; color: menutext; cursor: Default; font-family: MS Sans Serif; font-size: 8pt; padding: 2 12 2 16; }');document.write('.cMenuOver { background-color: highlight; color: highlighttext; cursor: Default; font-family: MS Sans Serif; font-size: 8pt; padding: 2 12 2 16; }');document.write('.cMenuDivOuter { background-color: threedface; height: 9 }');document.write('.cMenuDivInner { margin: 0 4 0 4; border-width: 1; border-style: solid; border-color: threedshadow threedhighlight threedhighlight threedshadow; }');document.write('</style>\n');/* ---------------------------------------------------------------------- *\  Function    : editor_defaultConfig  Description : default configuration settings for wysiwyg editor\* ---------------------------------------------------------------------- */function editor_defaultConfig(objname) {this.version = "2.03"this.width =  "auto";this.height = "auto";this.bodyStyle = 'background-color: #FFFFFF; font-family: "Verdana"; font-size: x-small;';this.imgURL = _editor_url + 'images/';this.debug  = 0;this.replaceNextlines = 0; // replace nextlines from spaces (on output)this.plaintextInput = 0;   // replace nextlines with breaks (on input)this.toolbar = [    ['fontname'],    ['fontsize'],//    ['fontstyle'],//    ['linebreak'],    ['bold','italic','underline','separator'],//  ['strikethrough','subscript','superscript','separator'],    ['justifyleft','justifycenter','justifyright','separator'],    ['OrderedList','UnOrderedList','Outdent','Indent','separator'],    ['forecolor','backcolor','separator'],    ['HorizontalRule','Createlink','InsertImage','InsertTable','htmlmode','separator'],//  ['custom1','custom2','custom3','separator'],    ['popupeditor','about']];this.fontnames = {    "Arial":           "arial, helvetica, sans-serif",    "Courier New":     "courier new, courier, mono",    "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.fontsizes = {    "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.stylesheet = "http://www.domain.com/sample.css"; // full URL to stylesheetthis.fontstyles = [     // make sure these exist in the header of page the content is being display as well in or they won't work!//    { name: "headline",     className: "headline",  classStyle: "font-family: arial black, arial; font-size: 28px; letter-spacing: -2px;" },//    { name: "arial red",    className: "headline2", classStyle: "font-family: arial black, arial; font-size: 12px; letter-spacing: -2px; color:red" },//    { name: "verdana blue", className: "headline4", classStyle: "font-family: verdana; font-size: 18px; letter-spacing: -2px; color:blue" },];this.btnList = {    // buttonName:    commandID,               title,                onclick,                   image,                 "bold":           ['Bold',                 'Bold',               'editor_action(this.id)',  'ed_format_bold.gif'],    "italic":         ['Italic',               'Italic',             'editor_action(this.id)',  'ed_format_italic.gif'],    "underline":      ['Underline',            'Underline',          'editor_action(this.id)',  'ed_format_underline.gif'],    "strikethrough":  ['StrikeThrough',        'Strikethrough',      'editor_action(this.id)',  'ed_format_strike.gif'],    "subscript":      ['SubScript',            'Subscript',          'editor_action(this.id)',  'ed_format_sub.gif'],    "superscript":    ['SuperScript',          'Superscript',        'editor_action(this.id)',  'ed_format_sup.gif'],    "justifyleft":    ['JustifyLeft',          'Justify Left',       'editor_action(this.id)',  'ed_align_left.gif'],    "justifycenter":  ['JustifyCenter',        'Justify Center',     'editor_action(this.id)',  'ed_align_center.gif'],    "justifyright":   ['JustifyRight',         'Justify Right',      'editor_action(this.id)',  'ed_align_right.gif'],    "orderedlist":    ['InsertOrderedList',    'Ordered List',       'editor_action(this.id)',  'ed_list_num.gif'],    "unorderedlist":  ['InsertUnorderedList',  'Bulleted List',      'editor_action(this.id)',  'ed_list_bullet.gif'],    "outdent":        ['Outdent',              'Decrease Indent',    'editor_action(this.id)',  'ed_indent_less.gif'],    "indent":         ['Indent',               'Increase Indent',    'editor_action(this.id)',  'ed_indent_more.gif'],    "forecolor":      ['ForeColor',            'Font Color',         'editor_action(this.id)',  'ed_color_fg.gif'],    "backcolor":      ['BackColor',            'Background Color',   'editor_action(this.id)',  'ed_color_bg.gif'],    "horizontalrule": ['InsertHorizontalRule', 'Horizontal Rule',    'editor_action(this.id)',  'ed_hr.gif'],    "createlink":     ['CreateLink',           'Insert Web Link',    'editor_action(this.id)',  'ed_link.gif'],    "insertimage":    ['InsertImage',          'Insert Image',       'editor_action(this.id)',  'ed_image.gif'],    "inserttable":    ['InsertTable',          'Insert Table',       'editor_action(this.id)',  'insert_table.gif'],    "htmlmode":       ['HtmlMode',             'View HTML Source',   'editor_setmode(\''+objname+'\')', 'ed_html.gif'],    "popupeditor":    ['popupeditor',          'Enlarge Editor',     'editor_action(this.id)',  'fullscreen_maximize.gif'],    "about":          ['about',                'About this editor',  'editor_about(\''+objname+'\')',  'ed_about.gif'],    // Add custom buttons here:    "custom1":           ['custom1',         'Purpose of button 1',  'editor_action(this.id)',  'ed_custom.gif'],    "custom2":           ['custom2',         'Purpose of button 2',  'editor_action(this.id)',  'ed_custom.gif'],    "custom3":           ['custom3',         'Purpose of button 3',  'editor_action(this.id)',  'ed_custom.gif'],   // end: custom buttons    "help":           ['showhelp',             'Help using editor',  'editor_action(this.id)',  'ed_help.gif']};}/* ---------------------------------------------------------------------- *\  Function    : editor_generate  Description : replace textarea with wysiwyg editor  Usage       : editor_generate("textarea_id",[height],[width]);  Arguments   : objname - ID of textarea to replace                w       - width of wysiwyg editor                h       - height of wysiwyg editor\* ---------------------------------------------------------------------- */function editor_generate(objname,userConfig) {  // Default Settings  var config = new editor_defaultConfig(objname);  if (userConfig) {     for (var thisName in userConfig) {      if (userConfig[thisName]) { config[thisName] = userConfig[thisName]; }    }  }  document.all[objname].config = config;                  // store config settings  // set size to specified size or size of original object  var obj    = document.all[objname];  if (!config.width || config.width == "auto") {    if      (obj.style.width) { config.width = obj.style.width; }      // use css style    else if (obj.cols)        { config.width = (obj.cols * 8) + 22; }  // col width + toolbar    else                      { config.width = '100%'; }               // default  }  if (!config.height || config.height == "auto") {    if      (obj.style.height) { config.height = obj.style.height; }   // use css style    else if (obj.rows)         { config.height = obj.rows * 17 }       // row height    else                       { config.height = '200'; }              // default  }  var tblOpen  = '<table border=0 cellspacing=0 cellpadding=0 style="float: left;"  unselectable="on"><tr><td style="border: none; padding: 1 0 0 0"><nobr>';  var tblClose = '</nobr></td></tr></table>\n';  // build button toolbar  var toolbar = '';  var btnGroup, btnItem, aboutEditor;  for (var btnGroup in config.toolbar) {    // linebreak    if (config.toolbar[btnGroup].length == 1 &&        config.toolbar[btnGroup][0].toLowerCase() == "linebreak") {      toolbar += '<br clear="all">';      continue;    }    toolbar += tblOpen;    for (var btnItem in config.toolbar[btnGroup]) {      var btnName = config.toolbar[btnGroup][btnItem].toLowerCase();      // fontname      if (btnName == "fontname") {        toolbar += '<select id="_' +objname+ '_FontName" onChange="editor_action(this.id)" unselectable="on" style="margin: 1 2 0 2; font-size: 12px;">';        for (var fontname in config.fontnames) {          toolbar += '<option value="' +config.fontnames[fontname]+ '">' +fontname+ '</option>'        }        toolbar += '</select>';        continue;      }      // fontsize      if (btnName == "fontsize") {        toolbar += '<select id="_' +objname+ '_FontSize" onChange="editor_action(this.id)" unselectable="on" style="margin: 1 2 0 0; font-size: 12px;">';        for (var fontsize in config.fontsizes) {          toolbar += '<option value="' +config.fontsizes[fontsize]+ '">' +fontsize+ '</option>'        }        toolbar += '</select>\n';        continue;      }      // font style      if (btnName == "fontstyle") {        toolbar += '<select id="_' +objname+ '_FontStyle" onChange="editor_action(this.id)" unselectable="on" style="margin: 1 2 0 0; font-size: 12px;">';        + '<option value="">Font Style</option>';        for (var i in config.fontstyles) {          var fontstyle = config.fontstyles[i];          toolbar += '<option value="' +fontstyle.className+ '">' +fontstyle.name+ '</option>'        }        toolbar += '</select>';        continue;      }      // separator      if (btnName == "separator") {        toolbar += '<span style="border: 1px inset; width: 1px; font-size: 16px; height: 16px; margin: 0 3 0 3"></span>';        continue;      }      // buttons      var btnObj = config.btnList[btnName];      if (btnName == 'linebreak') { alert("htmlArea error: 'linebreak' must be in a subgroup by itself, not with other buttons.\n\nhtmlArea wysiwyg editor not created."); return; }      if (!btnObj) { alert("htmlArea error: button '" +btnName+ "' not found in button list when creating the wysiwyg editor for '"+objname+"'.\nPlease make sure you entered the button name correctly.\n\nhtmlArea wysiwyg editor not created."); return; }      var btnCmdID   = btnObj[0];      var btnTitle   = btnObj[1];      var btnOnClick = btnObj[2];      var btnImage   = btnObj[3];      toolbar += '<button title="' +btnTitle+ '" id="_' +objname+ '_' +btnCmdID+ '" class="btn" onClick="' +btnOnClick+ '" onmouseover="if(this.className==\'btn\'){this.className=\'btnOver\'}" onmouseout="if(this.className==\'btnOver\'){this.className=\'btn\'}" unselectable="on"><img src="' +config.imgURL + btnImage+ '" border=0 unselectable="on"></button>';    } // end of button sub-group    toolbar += tblClose;  } // end of entire button set  // build editor  var editor = '<span id="_editor_toolbar"><table border=0 cellspacing=0 cellpadding=0 bgcolor="buttonface" style="padding: 1 0 0 2" width=' + config.width + ' unselectable="on"><tr><td>\n'  + toolbar  + '</td></tr></table>\n'  + '</td></tr></table></span>\n'  + '<textarea ID="_' +objname + '_editor" style="width:' +config.width+ '; height:' +config.height+ '; margin-top: -1px; margin-bottom: -1px;" wrap=soft></textarea>';  // add context menu  editor += '<div id="_' +objname + '_cMenu" style="position: absolute; visibility: hidden;"></div>';  //  hide original textarea and insert htmlarea after it  if (!config.debug) { document.all[objname].style.display = "none"; }  if (config.plaintextInput) {     // replace nextlines with breaks    var contents = document.all[objname].value;    contents = contents.replace(/\r\n/g, '<br>');    contents = contents.replace(/\n/g, '<br>');    contents = contents.replace(/\r/g, '<br>');    document.all[objname].value = contents;  }  // insert wysiwyg  document.all[objname].insertAdjacentHTML('afterEnd', editor)  // convert htmlarea from textarea to wysiwyg editor  editor_setmode(objname, 'init');  // call filterOutput when user submits form  for (var idx=0; idx < document.forms.length; idx++) {    var r = document.forms[idx].attachEvent('onsubmit', function() { editor_filterOutput(objname); });    if (!r) { alert("Error attaching event to form!"); }  }return true;}/* ---------------------------------------------------------------------- *\  Function    : editor_action  Description : perform an editor command on selected editor content  Usage       :  Arguments   : button_id - button id string with editor and action name\* ---------------------------------------------------------------------- */function editor_action(button_id) {  // split up button name into "editorID" and "cmdID"  var BtnParts = Array();  BtnParts = button_id.split("_");  var objname    = button_id.replace(/^_(.*)_[^_]*$/, '$1');  var cmdID      = BtnParts[ BtnParts.length-1 ];  var button_obj = document.all[button_id];  var editor_obj = document.all["_" +objname + "_editor"];  var config     = document.all[objname].config;  // help popup  if (cmdID == 'showhelp') {    window.open(_editor_url + "popups/editor_help.html", 'EditorHelp');    return;  }  // popup editor  if (cmdID == 'popupeditor') {    window.open(_editor_url + "popups/fullscreen.html?"+objname,                'FullScreen',                'toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,width=640,height=480');    return;  }  // check editor mode (don't perform actions in textedit mode)  if (editor_obj.tagName.toLowerCase() == 'textarea') { return; }  var editdoc = editor_obj.contentWindow.document;  editor_focus(editor_obj);  // get index and value for pulldowns  var idx = button_obj.selectedIndex;  var val = (idx != null) ? button_obj[ idx ].value : null;  if (0) {}   // use else if for easy cutting and pasting  //  // CUSTOM BUTTONS START HERE  //  // Custom1  else if (cmdID == 'custom1') {    alert("Hello, I am custom button 1!");  }  // Custom2  else if (cmdID == 'custom2') {  // insert some text from a popup window    var myTitle = "This is a custom title";    var myText = showModalDialog(_editor_url + "popups/custom2.html",                                 myTitle,      // str or obj specified here can be read from dialog as "window.dialogArguments"                                 "resizable: yes; help: no; status: no; scroll: no; ");    if (myText) { editor_insertHTML(objname, myText); }  }  // Custom3  else if (cmdID == 'custom3') {  // insert some text    editor_insertHTML(objname, "It's easy to add buttons that insert text!");  }  //  // END OF CUSTOM BUTTONS  //  // FontName  else if (cmdID == 'FontName' && val) {    editdoc.execCommand(cmdID,0,val);  }  // FontSize  else if (cmdID == 'FontSize' && val) {    editdoc.execCommand(cmdID,0,val);  }  // FontStyle (change CSS className)  else if (cmdID == 'FontStyle' && val) {    editdoc.execCommand('RemoveFormat');    editdoc.execCommand('FontName',0,'636c6173734e616d6520706c616365686f6c646572');    var fontArray = editdoc.all.tags("FONT");    for (i=0; i<fontArray.length; i++) {      if (fontArray[i].face == '636c6173734e616d6520706c616365686f6c646572') {        fontArray[i].face = "";        fontArray[i].className = val;        fontArray[i].outerHTML = fontArray[i].outerHTML.replace(/face=['"]+/, "");        }    }    button_obj.selectedIndex =0;  }  // fgColor and bgColor  else if (cmdID == 'ForeColor' || cmdID == 'BackColor') {    var oldcolor = _dec_to_rgb(editdoc.queryCommandValue(cmdID));    var newcolor = showModalDialog(_editor_url + "popups/select_color.html", oldcolor, "resizable: no; help: no; status: no; scroll: no;");    if (newcolor != null) { editdoc.execCommand(cmdID, false, "#"+newcolor); }  }  // execute command for buttons - if we didn't catch the cmdID by here we'll assume it's a  // commandID and pass it to execCommand().   See http://msdn.microsoft.com/workshop/author/dhtml/reference/commandids.asp  else {    // subscript & superscript, disable one before enabling the other    if (cmdID.toLowerCase() == 'subscript' && editdoc.queryCommandState('superscript')) { editdoc.execCommand('superscript'); }    if (cmdID.toLowerCase() == 'superscript' && editdoc.queryCommandState('subscript')) { editdoc.execCommand('subscript'); }    // insert link    if (cmdID.toLowerCase() == 'createlink'){      editdoc.execCommand(cmdID,1);    }    // insert image    else if (cmdID.toLowerCase() == 'insertimage'){      showModalDialog(_editor_url + "popups/insert_image.html", editdoc, "resizable: no; help: no; status: no; scroll: no; ");    }    // insert table    else if (cmdID.toLowerCase() == 'inserttable'){      showModalDialog(_editor_url + "popups/insert_table.html?"+objname,                                 window,                                 "resizable: yes; help: no; status: no; scroll: no; ");    }    // all other commands microsoft Command Identifiers    else { editdoc.execCommand(cmdID); }  }  editor_event(objname);}/* ---------------------------------------------------------------------- *\  Function    : editor_event  Description : called everytime an editor event occurs  Usage       : editor_event(objname, runDelay, eventName)  Arguments   : objname - ID of textarea to replace                runDelay: -1 = run now, no matter what                          0  = run now, if allowed                        1000 = run in 1 sec, if allowed at that point\* ---------------------------------------------------------------------- */function editor_event(objname,runDelay) {  var config = document.all[objname].config;  var editor_obj  = document.all["_" +objname+  "_editor"];       // html editor object  if (runDelay == null) { runDelay = 0; }  var editdoc;  var editEvent = editor_obj.contentWindow ? editor_obj.contentWindow.event : event;  // catch keypress events    if (editEvent && editEvent.keyCode) {      var ord       = editEvent.keyCode;    // ascii order of key pressed      var ctrlKey   = editEvent.ctrlKey;      var altKey    = editEvent.altKey;      var shiftKey  = editEvent.shiftKey;      if (ord == 16) { return; }  // ignore shift key by itself      if (ord == 17) { return; }  // ignore ctrl key by itself      if (ord == 18) { return; }  // ignore alt key by itself       // cancel ENTER key and insert <BR> instead//       if (ord == 13 && editEvent.type == 'keypress') {//         editEvent.returnValue = false;//         editor_insertHTML(objname, "<br>");//         return;//       }      if (ctrlKey && (ord == 122 || ord == 90)) {     // catch ctrl-z (UNDO)//      TODO: Add our own undo/redo functionality//        editEvent.cancelBubble = true;        return;      }      if ((ctrlKey && (ord == 121 || ord == 89)) ||          ctrlKey && shiftKey && (ord == 122 || ord == 90)) {     // catch ctrl-y, ctrl-shift-z (REDO)//      TODO: Add our own undo/redo functionality        return;      }    }  // setup timer for delayed updates (some events take time to complete)  if (runDelay > 0) { return setTimeout(function(){ editor_event(objname); }, runDelay); }  // don't execute more than 3 times a second (eg: too soon after last execution)  if (this.tooSoon == 1 && runDelay >= 0) { this.queue = 1; return; } // queue all but urgent events  this.tooSoon = 1;  setTimeout(function(){    this.tooSoon = 0;    if (this.queue) { editor_event(objname,-1); };    this.queue = 0;    }, 333);  // 1/3 second  editor_updateOutput(objname);  editor_updateToolbar(objname);}/* ---------------------------------------------------------------------- *\  Function    : editor_updateToolbar  Description : update toolbar state  Usage       :  Arguments   : objname - ID of textarea to replace                action  - enable, disable, or update (default action)\* ---------------------------------------------------------------------- */function editor_updateToolbar(objname,action) {  var config = document.all[objname].config;  var editor_obj  = document.all["_" +objname+  "_editor"];  // disable or enable toolbar  if (action == "enable" || action == "disable") {    var tbItems = new Array('FontName','FontSize','FontStyle');                           // add pulldowns    for (var btnName in config.btnList) { tbItems.push(config.btnList[btnName][0]); } // add buttons    for (var idxN in tbItems) {      var cmdID = tbItems[idxN].toLowerCase();      var tbObj = document.all["_" +objname+ "_" +tbItems[idxN]];      if (cmdID == "htmlmode" || cmdID == "about" || cmdID == "showhelp" || cmdID == "popupeditor") { continue; } // don't change these buttons      if (tbObj == null) { continue; }      var isBtn = (tbObj.tagName.toLowerCase() == "button") ? true : false;      if (action == "enable")  { tbObj.disabled = false; if (isBtn) { tbObj.className = 'btn' }}      if (action == "disable") { tbObj.disabled = true;  if (isBtn) { tbObj.className = 'btnNA' }}    }    return;  }  // update toolbar state  if (editor_obj.tagName.toLowerCase() == 'textarea') { return; }   // don't update state in textedit mode  var editdoc = editor_obj.contentWindow.document;  // Set FontName pulldown  var fontname_obj = document.all["_" +objname+ "_FontName"];  if (fontname_obj) {    var fontname = editdoc.queryCommandValue('FontName');    if (fontname == null) { fontname_obj.value = null; }    else {      var found = 0;      for (i=0; i<fontname_obj.length; i++) {        if (fontname.toLowerCase() == fontname_obj[i].text.toLowerCase()) {          fontname_obj.selectedIndex = i;          found = 1;        }      }      if (found != 1) { fontname_obj.value = null; }     // for fonts not in list    }  }  // Set FontSize pulldown  var fontsize_obj = document.all["_" +objname+ "_FontSize"];  if (fontsize_obj) {    var fontsize = editdoc.queryCommandValue('FontSize');    if (fontsize == null) { fontsize_obj.value = null; }    else {      var found = 0;      for (i=0; i<fontsize_obj.length; i++) {        if (fontsize == fontsize_obj[i].value) { fontsize_obj.selectedIndex = i; found=1; }      }      if (found != 1) { fontsize_obj.value = null; }     // for sizes not in list    }  }  // Set FontStyle pulldown  var classname_obj = document.all["_" +objname+ "_FontStyle"];  if (classname_obj) {    var curRange = editdoc.selection.createRange();    // check element and element parents for class names    var pElement;    if (curRange.length) { pElement = curRange[0]; }              // control tange    else                 { pElement = curRange.parentElement(); } // text range    while (pElement && !pElement.className) { pElement = pElement.parentElement; }  // keep going up    var thisClass = pElement ? pElement.className.toLowerCase() : "";    if (!thisClass && classname_obj.value) { classname_obj.value = null; }    else {      var found = 0;      for (i=0; i<classname_obj.length; i++) {        if (thisClass == classname_obj[i].value.toLowerCase()) {          classname_obj.selectedIndex = i;          found=1;        }      }      if (found != 1) { classname_obj.value = null; }     // for classes not in list    }  }  // update button states  var IDList = Array('Bold','Italic','Underline','StrikeThrough','SubScript','SuperScript','JustifyLeft','JustifyCenter','JustifyRight','InsertOrderedList','InsertUnorderedList');  for (i=0; i<IDList.length; i++) {    var btnObj = document.all["_" +objname+ "_" +IDList[i]];    if (btnObj == null) { continue; }    var cmdActive = editdoc.queryCommandState( IDList[i] );    if (!cmdActive)  {                                  // option is OK      if (btnObj.className != 'btn') { btnObj.className = 'btn'; }      if (btnObj.disabled  != false) { btnObj.disabled = false; }    } else if (cmdActive)  {                            // option already applied or mixed content      if (btnObj.className != 'btnDown') { btnObj.className = 'btnDown'; }      if (btnObj.disabled  != false)   { btnObj.disabled = false; }    }  }}/* ---------------------------------------------------------------------- *\  Function    : editor_updateOutput  Description : update hidden output field with data from wysiwg\* ---------------------------------------------------------------------- */function editor_updateOutput(objname) {  var config     = document.all[objname].config;  var editor_obj  = document.all["_" +objname+  "_editor"];       // html editor object  var editEvent = editor_obj.contentWindow ? editor_obj.contentWindow.event : event;  var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');  var editdoc = isTextarea ? null : editor_obj.contentWindow.document;  // get contents of edit field  var contents;  if (isTextarea) { contents = editor_obj.value; }  else            { contents = editdoc.body.innerHTML; }  // check if contents has changed since the last time we ran this routine  if (config.lastUpdateOutput && config.lastUpdateOutput == contents) { return; }  else { config.lastUpdateOutput = contents; }  // update hidden output field  document.all[objname].value = contents;}/* ---------------------------------------------------------------------- *\  Function    : editor_filterOutput  Description :\* ---------------------------------------------------------------------- */function editor_filterOutput(objname) {  editor_updateOutput(objname);  var contents = document.all[objname].value;  var config   = document.all[objname].config;  // ignore blank contents  if (contents.toLowerCase() == '<p>&nbsp;</p>') { contents = ""; }  // filter tag - this code is run for each HTML tag matched  var filterTag = function(tagBody,tagName,tagAttr) {    tagName = tagName.toLowerCase();    var closingTag = (tagBody.match(/^<\//)) ? true : false;    // fix placeholder URLS - remove absolute paths that IE adds    if (tagName == 'img') { tagBody = tagBody.replace(/(src\s*=\s*.)[^*]*(\*\*\*)/, "$1$2"); }    if (tagName == 'a')   { tagBody = tagBody.replace(/(href\s*=\s*.)[^*]*(\*\*\*)/, "$1$2"); }    // add additional tag filtering here    // convert to vbCode//    if      (tagName == 'b' || tagName == 'strong') {//      if (closingTag) { tagBody = "[/b]"; } else { tagBody = "[b]"; }//    }//    else if (tagName == 'i' || tagName == 'em') {//      if (closingTag) { tagBody = "[/i]"; } else { tagBody = "[i]"; }//    }//    else if (tagName == 'u') {//      if (closingTag) { tagBody = "[/u]"; } else { tagBody = "[u]"; }//    }//    else {//      tagBody = ""; // disallow all other tags!//    }    return tagBody;  };  // match tags and call filterTag  RegExp.lastIndex = 0;    var matchTag = /<\/?(\w+)((?:[^'">]*|'[^']*'|"[^"]*")*)>/g;   // this will match tags, but still doesn't handle container tags (textarea, comments, etc)  contents = contents.replace(matchTag, filterTag);  // remove nextlines from output (if requested)  if (config.replaceNextlines) {     contents = contents.replace(/\r\n/g, ' ');    contents = contents.replace(/\n/g, ' ');    contents = contents.replace(/\r/g, ' ');  }  // update output with filtered content  document.all[objname].value = contents;}/* ---------------------------------------------------------------------- *\  Function    : editor_setmode  Description : change mode between WYSIWYG and HTML editor  Usage       : editor_setmode(objname, mode);  Arguments   : objname - button id string with editor and action name                mode      - init, textedit, or wysiwyg\* ---------------------------------------------------------------------- */function editor_setmode(objname, mode) {  var config     = document.all[objname].config;  var editor_obj = document.all["_" +objname + "_editor"];  // wait until document is fully loaded  if (document.readyState != 'complete') {    setTimeout(function() { editor_setmode(objname,mode) }, 25);    return;  }  // define different editors  var TextEdit   = '<textarea ID="_' +objname + '_editor" style="width:' +editor_obj.style.width+ '; height:' +editor_obj.style.height+ '; margin-top: -1px; margin-bottom: -1px;"></textarea>';  var RichEdit   = '<iframe ID="_' +objname+ '_editor"    style="width:' +editor_obj.style.width+ '; height:' +editor_obj.style.height+ ';"></iframe>'; // src="' +_editor_url+ 'popups/blank.html"  //  // Switch to TEXTEDIT mode  //  if (mode == "textedit" || editor_obj.tagName.toLowerCase() == 'iframe') {    config.mode = "textedit";    var editdoc = editor_obj.contentWindow.document;    var contents = editdoc.body.createTextRange().htmlText;    editor_obj.outerHTML = TextEdit;    editor_obj = document.all["_" +objname + "_editor"];    editor_obj.value = contents;    editor_event(objname);    editor_updateToolbar(objname, "disable");  // disable toolbar items    // set event handlers    editor_obj.onkeydown   = function() { editor_event(objname); }    editor_obj.onkeypress  = function() { editor_event(objname); }    editor_obj.onkeyup     = function() { editor_event(objname); }    editor_obj.onmouseup   = function() { editor_event(objname); }    editor_obj.ondrop      = function() { editor_event(objname, 100); }     // these events fire before they occur    editor_obj.oncut       = function() { editor_event(objname, 100); }    editor_obj.onpaste     = function() { editor_event(objname, 100); }    editor_obj.onblur      = function() { editor_event(objname, -1); }    editor_updateOutput(objname);    editor_focus(editor_obj);  }  //  // Switch to WYSIWYG mode  //  else {    config.mode = "wysiwyg";    var contents = editor_obj.value;    if (mode == 'init') { contents = document.all[objname].value; } // on init use original textarea content    // create editor    editor_obj.outerHTML = RichEdit;    editor_obj = document.all["_" +objname + "_editor"];    // get iframe document object    // create editor contents (and default styles for editor)    var html = "";    html += '<html><head>\n';    if (config.stylesheet) {      html += '<link href="' +config.stylesheet+ '" rel="stylesheet" type="text/css">\n';    }    html += '<style>\n';    html += 'body {' +config.bodyStyle+ '} \n';    for (var i in config.fontstyles) {      var fontstyle = config.fontstyles[i];      if (fontstyle.classStyle) {        html += '.' +fontstyle.className+ ' {' +fontstyle.classStyle+ '}\n';      }    }    html += '</style>\n'      + '</head>\n'      + '<body contenteditable="true" topmargin=1 leftmargin=1'// still working on this//      + ' oncontextmenu="parent.editor_cMenu_generate(window,\'' +objname+ '\');"'      +'>'      + contents      + '</body>\n'      + '</html>\n';    // write to editor window    var editdoc = editor_obj.contentWindow.document;    editdoc.open();    editdoc.write(html);    editdoc.close();    editor_updateToolbar(objname, "enable");  // enable toolbar items    // store objname under editdoc    editdoc.objname = objname;    // set event handlers    editdoc.onkeydown      = function() { editor_event(objname); }    editdoc.onkeypress     = function() { editor_event(objname); }    editdoc.onkeyup        = function() { editor_event(objname); }    editdoc.onmouseup      = function() { editor_event(objname); }    editdoc.body.ondrop    = function() { editor_event(objname, 100); }     // these events fire before they occur    editdoc.body.oncut     = function() { editor_event(objname, 100); }    editdoc.body.onpaste   = function() { editor_event(objname, 100); }    editdoc.body.onblur    = function() { editor_event(objname, -1); }    // bring focus to editor    if (mode != 'init') {             // don't focus on page load, only on mode switch      editor_focus(editor_obj);    }  }  // Call update UI  if (mode != 'init') {             // don't update UI on page load, only on mode switch    editor_event(objname);  }}/* ---------------------------------------------------------------------- *\  Function    : editor_focus  Description : bring focus to the editor  Usage       : editor_focus(editor_obj);  Arguments   : editor_obj - editor object\* ---------------------------------------------------------------------- */function editor_focus(editor_obj) {  // check editor mode  if (editor_obj.tagName.toLowerCase() == 'textarea') {         // textarea    var myfunc = function() { editor_obj.focus(); };    setTimeout(myfunc,100);                                     // doesn't work all the time without delay  }  else {                                                        // wysiwyg    var editdoc = editor_obj.contentWindow.document;            // get iframe editor document object    var editorRange = editdoc.body.createTextRange();           // editor range    var curRange    = editdoc.selection.createRange();          // selection range    if (curRange.length == null &&                              // make sure it's not a controlRange        !editorRange.inRange(curRange)) {                       // is selection in editor range      editorRange.collapse();                                   // move to start of range      editorRange.select();                                     // select      curRange = editorRange;    }  }}/* ---------------------------------------------------------------------- *\  Function    : editor_about  Description : display "about this editor" popup\* ---------------------------------------------------------------------- */function editor_about(objname) {  showModalDialog(_editor_url + "popups/about.html", window, "resizable: yes; help: no; status: no; scroll: no; ");}/* ---------------------------------------------------------------------- *\  Function    : _dec_to_rgb  Description : convert dec color value to rgb hex  Usage       : var hex = _dec_to_rgb('65535');   // returns FFFF00  Arguments   : value   - dec value\* ---------------------------------------------------------------------- */function _dec_to_rgb(value) {  var hex_string = "";  for (var hexpair = 0; hexpair < 3; hexpair++) {    var myByte = value & 0xFF;            // get low byte    value >>= 8;                        // drop low byte    var nybble2 = myByte & 0x0F;          // get low nybble (4 bits)    var nybble1 = (myByte >> 4) & 0x0F;   // get high nybble    hex_string += nybble1.toString(16); // convert nybble to hex    hex_string += nybble2.toString(16); // convert nybble to hex  }  return hex_string.toUpperCase();}/* ---------------------------------------------------------------------- *\  Function    : editor_insertHTML  Description : insert string at current cursor position in editor.  If                two strings are specifed, surround selected text with them.  Usage       : editor_insertHTML(objname, str1, [str2], reqSelection)  Arguments   : objname - ID of textarea                str1 - HTML or text to insert                str2 - HTML or text to insert (optional argument)                reqSelection - (1 or 0) give error if no text selected\* ---------------------------------------------------------------------- */function editor_insertHTML(objname, str1,str2, reqSel) {  var config     = document.all[objname].config;  var editor_obj = document.all["_" +objname + "_editor"];    // editor object  if (str1 == null) { str1 = ''; }  if (str2 == null) { str2 = ''; }  // for non-wysiwyg capable browsers just add to end of textbox  if (document.all[objname] && editor_obj == null) {    document.all[objname].focus();    document.all[objname].value = document.all[objname].value + str1 + str2;    return;  }  // error checking  if (editor_obj == null) { return alert("Unable to insert HTML.  Invalid object name '" +objname+ "'."); }  editor_focus(editor_obj);  var tagname = editor_obj.tagName.toLowerCase();  var sRange; // insertHTML for wysiwyg iframe  if (tagname == 'iframe') {    var editdoc = editor_obj.contentWindow.document;    sRange  = editdoc.selection.createRange();    var sHtml   = sRange.htmlText;    // check for control ranges    if (sRange.length) { return alert("Unable to insert HTML.  Try highlighting content instead of selecting it."); }    // insert HTML    var oldHandler = window.onerror;    window.onerror = function() { alert("Unable to insert HTML for current selection."); return true; } // partial table selections cause errors    if (sHtml.length) {                                 // if content selected      if (str2) { sRange.pasteHTML(str1 +sHtml+ str2) } // surround      else      { sRange.pasteHTML(str1); }             // overwrite    } else {                                            // if insertion point only      if (reqSel) { return alert("Unable to insert HTML.  You must select something first."); }      sRange.pasteHTML(str1 + str2);                    // insert strings    }    window.onerror = oldHandler;  }  // insertHTML for plaintext textarea  else if (tagname == 'textarea') {    editor_obj.focus();    sRange  = document.selection.createRange();    var sText   = sRange.text;    // insert HTML    if (sText.length) {                                 // if content selected      if (str2) { sRange.text = str1 +sText+ str2; }  // surround      else      { sRange.text = str1; }               // overwrite    } else {                                            // if insertion point only      if (reqSel) { return alert("Unable to insert HTML.  You must select something first."); }      sRange.text = str1 + str2;                        // insert strings    }  }  else { alert("Unable to insert HTML.  Unknown object tag type '" +tagname+ "'."); }  // move to end of new content  sRange.collapse(false); // move to end of range  sRange.select();        // re-select}/* ---------------------------------------------------------------------- *\  Function    : editor_getHTML  Description : return HTML contents of editor (in either wywisyg or html mode)  Usage       : var myHTML = editor_getHTML('objname');\* ---------------------------------------------------------------------- */function editor_getHTML(objname) {  var editor_obj = document.all["_" +objname + "_editor"];  var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');  if (isTextarea) { return editor_obj.value; }  else            { return editor_obj.contentWindow.document.body.innerHTML; }}/* ---------------------------------------------------------------------- *\  Function    : editor_setHTML  Description : set HTML contents of editor (in either wywisyg or html mode)  Usage       : editor_setHTML('objname',"<b>html</b> <u>here</u>");\* ---------------------------------------------------------------------- */function editor_setHTML(objname, html) {  var editor_obj = document.all["_" +objname + "_editor"];  var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');  if (isTextarea) { editor_obj.value = html; }  else            { editor_obj.contentWindow.document.body.innerHTML = html; }}/* ---------------------------------------------------------------------- *\  Function    : editor_appendHTML  Description : append HTML contents to editor (in either wywisyg or html mode)  Usage       : editor_appendHTML('objname',"<b>html</b> <u>here</u>");\* ---------------------------------------------------------------------- */function editor_appendHTML(objname, html) {  var editor_obj = document.all["_" +objname + "_editor"];  var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');  if (isTextarea) { editor_obj.value += html; }  else            { editor_obj.contentWindow.document.body.innerHTML += html; }}/* ---------------------------------------------------------------- */function _isMouseOver(obj,event) {       // determine if mouse is over object  var mouseX    = event.clientX;  var mouseY    = event.clientY;  var objTop    = obj.offsetTop;  var objBottom = obj.offsetTop + obj.offsetHeight;  var objLeft   = obj.offsetLeft;  var objRight  = obj.offsetLeft + obj.offsetWidth;  if (mouseX >= objLeft && mouseX <= objRight &&      mouseY >= objTop  && mouseY <= objBottom) { return true; }  return false;}/* ---------------------------------------------------------------- */function editor_cMenu_generate(editorWin,objname) {  var parentWin = window;  editorWin.event.returnValue = false;  // cancel default context menu  // define content menu options  var cMenuOptions = [ // menu name, shortcut displayed, javascript code    ['Cut', 'Ctrl-X', function() {}],    ['Copy', 'Ctrl-C', function() {}],    ['Paste', 'Ctrl-C', function() {}],    ['Delete', 'DEL', function() {}],    ['---', null, null],    ['Select All', 'Ctrl-A', function() {}],    ['Clear All', '', function() {}],    ['---', null, null],    ['About this editor...', '', function() {      alert("about this editor");    }]];    editor_cMenu.options = cMenuOptions; // save options  // generate context menu  var cMenuHeader = ''    + '<div id="_'+objname+'_cMenu" onblur="editor_cMenu(this);" oncontextmenu="return false;" onselectstart="return false"'    + '  style="position: absolute; visibility: hidden; cursor: default; width: 167px; background-color: threedface;'    + '         border: solid 1px; border-color: threedlightshadow threeddarkshadow threeddarkshadow threedlightshadow;">'    + '<table border=0 cellspacing=0 cellpadding=0 width="100%" style="width: 167px; background-color: threedface; border: solid 1px; border-color: threedhighlight threedshadow threedshadow threedhighlight;">'    + ' <tr><td colspan=2 height=1></td></tr>';  var cMenuList = '';  var cMenuFooter = ''    + ' <tr><td colspan=2 height=1></td></tr>'    + '</table></div>';  for (var menuIdx in editor_cMenu.options) {    var menuName = editor_cMenu.options[menuIdx][0];    var menuKey  = editor_cMenu.options[menuIdx][1];    var menuCode = editor_cMenu.options[menuIdx][2];    // separator    if (menuName == "---" || menuName == "separator") {      cMenuList += ' <tr><td colspan=2 class="cMenuDivOuter"><div class="cMenuDivInner"></div></td></tr>';    }    // menu option    else {      cMenuList += '<tr class="cMenu" onMouseOver="editor_cMenu(this)" onMouseOut="editor_cMenu(this)" onClick="editor_cMenu(this, \'' +menuIdx+ '\',\'' +objname+ '\')">';      if (menuKey) { cMenuList += ' <td align=left class="cMenu">' +menuName+ '</td><td align=right class="cMenu">' +menuKey+ '</td>'; }      else         { cMenuList += ' <td colspan=2 class="cMenu">' +menuName+ '</td>'; }      cMenuList += '</tr>';    }  }  var cMenuHTML = cMenuHeader + cMenuList + cMenuFooter;  document.all['_'+objname+'_cMenu'].outerHTML = cMenuHTML;  editor_cMenu_setPosition(parentWin, editorWin, objname);  parentWin['_'+objname+'_cMenu'].style.visibility = 'visible';  parentWin['_'+objname+'_cMenu'].focus();}/* ---------------------------------------------------------------- */function editor_cMenu_setPosition(parentWin, editorWin, objname) {      // set object position that won't overlap window edge  var event    = editorWin.event;  var cMenuObj = parentWin['_'+objname+'_cMenu'];  var mouseX   = event.clientX + parentWin.document.all['_'+objname+'_editor'].offsetLeft;  var mouseY   = event.clientY + parentWin.document.all['_'+objname+'_editor'].offsetTop;  var cMenuH   = cMenuObj.offsetHeight;  var cMenuW   = cMenuObj.offsetWidth;  var pageH    = document.body.clientHeight + document.body.scrollTop;  var pageW    = document.body.clientWidth + document.body.scrollLeft;  // set horzontal position  if (mouseX + 5 + cMenuW > pageW) { var left = mouseX - cMenuW - 5; } // too far right  else                            { var left = mouseX + 5; }  // set vertical position  if (mouseY + 5 + cMenuH > pageH) { var top = mouseY - cMenuH + 5; } // too far down  else                            { var top = mouseY + 5; }  cMenuObj.style.top = top;  cMenuObj.style.left = left;}/* ---------------------------------------------------------------- */function editor_cMenu(obj,menuIdx,objname) {  var action = event.type;  if      (action == "mouseover" && !obj.disabled && obj.tagName.toLowerCase() == 'tr') {    obj.className = 'cMenuOver';    for (var i=0; i < obj.cells.length; i++) { obj.cells[i].className = 'cMenuOver'; }  }  else if (action == "mouseout" && !obj.disabled && obj.tagName.toLowerCase() == 'tr')  {    obj.className = 'cMenu';    for (var i=0; i < obj.cells.length; i++) { obj.cells[i].className = 'cMenu'; }  }  else if (action == "click" && !obj.disabled) {    document.all['_'+objname+'_cMenu'].style.visibility = "hidden";    var menucode = editor_cMenu.options[menuIdx][2];    menucode();  }  else if (action == "blur") {    if (!_isMouseOver(obj,event)) { obj.style.visibility = 'hidden'; }    else {      if (obj.style.visibility != "hidden") { obj.focus(); }    }  }  else { alert("editor_cMenu, unknown action: " + action); }}/* ---------------------------------------------------------------------- */