editor.js
上传用户:junmaots
上传日期:2022-07-09
资源大小:2450k
文件大小:52k
源码类别:

Jsp/Servlet

开发平台:

Java

  1. // <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
  2. // 需要IE5.5以上的版本支持
  3. // write out styles for UI buttons
  4. document.write('<style type="text/css">n');
  5. document.write('.btn     { width: 22px; height: 22px; border: 1px solid buttonface; margin: 0; padding: 0; }n');
  6. document.write('.btnOver { width: 22px; height: 22px; border: 1px outset; }n');
  7. document.write('.btnDown { width: 22px; height: 22px; border: 1px inset; background-color: buttonhighlight; }n');
  8. document.write('.btnNA   { width: 22px; height: 22px; border: 1px solid buttonface; filter: alpha(opacity=25); }n');
  9. document.write('.cMenu     { background-color: threedface; color: menutext; cursor: Default; font-family: MS Sans Serif; font-size: 8pt; padding: 2 12 2 16; }');
  10. document.write('.cMenuOver { background-color: highlight; color: highlighttext; cursor: Default; font-family: MS Sans Serif; font-size: 8pt; padding: 2 12 2 16; }');
  11. document.write('.cMenuDivOuter { background-color: threedface; height: 9 }');
  12. document.write('.cMenuDivInner { margin: 0 4 0 4; border-width: 1; border-style: solid; border-color: threedshadow threedhighlight threedhighlight threedshadow; }');
  13. document.write('</style>n');
  14. /* ---------------------------------------------------------------------- *
  15.   Function    : editor_defaultConfig 系统默认的模式
  16.   Description : default configuration settings for wysiwyg editor
  17. * ---------------------------------------------------------------------- */
  18. function editor_defaultConfig(objname) {
  19. this.version = "2.03"
  20. this.width =  "auto";
  21. this.height = "auto";
  22. this.bodyStyle = 'background-color: #FFFFFF; font-family: "Verdana"; font-size: x-small;';
  23. this.imgURL = _editor_url + 'images/';
  24. this.debug  = 0;
  25. this.replaceNextlines = 0; // replace nextlines from spaces (on output)
  26. this.plaintextInput = 0;   // replace nextlines with breaks (on input)
  27. this.toolbar = [
  28. ['fontname'],
  29. ['fontsize'],
  30. //    ['fontstyle'],
  31. //    ['linebreak'],
  32. ['bold','italic','underline','separator'],
  33. //  ['strikethrough','subscript','superscript','separator'],
  34. ['justifyleft','justifycenter','justifyright','separator'],
  35. ['OrderedList','UnOrderedList','Outdent','Indent','separator'],
  36. ['forecolor','backcolor','separator'],
  37. ['HorizontalRule','Createlink','InsertImage','InsertTable','htmlmode','separator'],
  38. //  ['custom1','custom2','custom3','separator'],
  39. ['popupeditor','about']
  40. ];
  41. this.fontnames = {
  42. "Arial":           "arial, helvetica, sans-serif",
  43. "Courier New":     "courier new, courier, mono",
  44. "Georgia":         "Georgia, Times New Roman, Times, Serif",
  45. "Tahoma":          "Tahoma, Arial, Helvetica, sans-serif",
  46. "Times New Roman": "times new roman, times, serif",
  47. "Verdana":         "Verdana, Arial, Helvetica, sans-serif",
  48. "impact":          "impact",
  49. "WingDings":       "WingDings"
  50. };
  51. this.fontsizes = {
  52. "1 (8 pt)":  "1",
  53. "2 (10 pt)": "2",
  54. "3 (12 pt)": "3",
  55. "4 (14 pt)": "4",
  56. "5 (18 pt)": "5",
  57. "6 (24 pt)": "6",
  58. "7 (36 pt)": "7"
  59.   };
  60. //// this.stylesheet = "http://www.domain.com/sample.css"; // full URL to stylesheet
  61. this.fontstyles = [     // make sure these exist in the header of page the content is being display as well in or they won't work!
  62. //    { name: "headline",     className: "headline",  classStyle: "font-family: arial black, arial; font-size: 28px; letter-spacing: -2px;" },
  63. //    { name: "arial red",    className: "headline2", classStyle: "font-family: arial black, arial; font-size: 12px; letter-spacing: -2px; color:red" },
  64. //    { name: "verdana blue", className: "headline4", classStyle: "font-family: verdana; font-size: 18px; letter-spacing: -2px; color:blue" },
  65. ];
  66. this.btnList = {
  67. // buttonName:    commandID,               title,                onclick,                   image,
  68. "bold":           ['Bold',                 '加粗',               'editor_action(this.id)',  'ed_format_bold.gif'],
  69. "italic":         ['Italic',               '斜体',             'editor_action(this.id)',  'ed_format_italic.gif'],
  70. "underline":      ['Underline',            'Underline',          'editor_action(this.id)',  'ed_format_underline.gif'],
  71. "strikethrough":  ['StrikeThrough',        'Strikethrough',      'editor_action(this.id)',  'ed_format_strike.gif'],
  72. "subscript":      ['SubScript',            'Subscript',          'editor_action(this.id)',  'ed_format_sub.gif'],
  73. "superscript":    ['SuperScript',          'Superscript',        'editor_action(this.id)',  'ed_format_sup.gif'],
  74. "justifyleft":    ['JustifyLeft',          'Justify Left',       'editor_action(this.id)',  'ed_align_left.gif'],
  75. "justifycenter":  ['JustifyCenter',        'Justify Center',     'editor_action(this.id)',  'ed_align_center.gif'],
  76. "justifyright":   ['JustifyRight',         'Justify Right',      'editor_action(this.id)',  'ed_align_right.gif'],
  77. "orderedlist":    ['InsertOrderedList',    'Ordered List',       'editor_action(this.id)',  'ed_list_num.gif'],
  78. "unorderedlist":  ['InsertUnorderedList',  'Bulleted List',      'editor_action(this.id)',  'ed_list_bullet.gif'],
  79. "outdent":        ['Outdent',              'Decrease Indent',    'editor_action(this.id)',  'ed_indent_less.gif'],
  80. "indent":         ['Indent',               'Increase Indent',    'editor_action(this.id)',  'ed_indent_more.gif'],
  81. "forecolor":      ['ForeColor',            'Font Color',         'editor_action(this.id)',  'ed_color_fg.gif'],
  82. "backcolor":      ['BackColor',            'Background Color',   'editor_action(this.id)',  'ed_color_bg.gif'],
  83. "horizontalrule": ['InsertHorizontalRule', 'Horizontal Rule',    'editor_action(this.id)',  'ed_hr.gif'],
  84. "createlink":     ['CreateLink',           'Insert Web Link',    'editor_action(this.id)',  'ed_link.gif'],
  85. "insertimage":    ['InsertImage',          'Insert Image',       'editor_action(this.id)',  'ed_image.gif'],
  86. "inserttable":    ['InsertTable',          'Insert Table',       'editor_action(this.id)',  'insert_table.gif'],
  87. "htmlmode":       ['HtmlMode',             'View HTML Source',   'editor_setmode(''+objname+'')', 'ed_html.gif'],
  88. "popupeditor":    ['popupeditor',          'Enlarge Editor',     'editor_action(this.id)',  'fullscreen_maximize.gif'],
  89. "about":          ['about',                '关于当前编辑器',  'editor_about(''+objname+'')',  'ed_about.gif'],
  90. // Add custom buttons here:
  91. "custom1":           ['custom1',         'Purpose of button 1',  'editor_action(this.id)',  'ed_custom.gif'],
  92. "custom2":           ['custom2',         'Purpose of button 2',  'editor_action(this.id)',  'ed_custom.gif'],
  93. "custom3":           ['custom3',         'Purpose of button 3',  'editor_action(this.id)',  'ed_custom.gif'],
  94.    // end: custom buttons
  95. "help":           ['showhelp',             'Help using editor',  'editor_action(this.id)',  'ed_help.gif']
  96. };
  97. }
  98. /* ---------------------------------------------------------------------- *
  99.   Function    : editor_generate 设置编辑器的对象和内容
  100.   Description : replace textarea with wysiwyg editor
  101.   Usage       : editor_generate("textarea_id",[height],[width]);
  102.   Arguments   : objname - ID of textarea to replace
  103.                 w       - width of wysiwyg editor
  104.                 h       - height of wysiwyg editor
  105. * ---------------------------------------------------------------------- */
  106. function editor_generate(objname,userConfig) {
  107.   // Default Settings
  108.   var config = new editor_defaultConfig(objname);
  109.   if (userConfig) {
  110. for (var thisName in userConfig) {
  111.   if (userConfig[thisName]) {
  112.    config[thisName] = userConfig[thisName];
  113. }
  114. }
  115.   }
  116.   document.all[objname].config = config; // store config settings
  117.   // set size to specified size or size of original object
  118.   var obj    = document.all[objname];
  119.   if (!config.width || config.width == "auto") {
  120. if (obj.style.width) {   // use css style
  121. config.width = obj.style.width;
  122. }else if (obj.cols){  // col width + toolbar
  123. config.width = (obj.cols * 8) + 22;
  124. }else {  // default
  125. config.width = '100%';
  126. }
  127.   }
  128.   if (!config.height || config.height == "auto") {
  129. if(obj.style.height){  // use css style
  130. config.height = obj.style.height;
  131. }else if (obj.rows){  // row height
  132. config.height = obj.rows * 17
  133. }else{ // default
  134. config.height = '200';
  135. }
  136.   }
  137.   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>';
  138.   var tblClose = '</nobr></td></tr></table>n';
  139.   // build button toolbar
  140.   var toolbar = '';
  141.   var btnGroup, btnItem, aboutEditor;
  142.   for (var btnGroup in config.toolbar) {
  143.     // linebreak
  144.     if (config.toolbar[btnGroup].length == 1 &&
  145.         config.toolbar[btnGroup][0].toLowerCase() == "linebreak") {
  146.       toolbar += '<br clear="all">';
  147.       continue;
  148.     }
  149.     toolbar += tblOpen;
  150.     for (var btnItem in config.toolbar[btnGroup]) {
  151.       var btnName = config.toolbar[btnGroup][btnItem].toLowerCase();
  152.       // fontname
  153.       if (btnName == "fontname") {
  154.         toolbar += '<select id="_' +objname+ '_FontName" onChange="editor_action(this.id)" unselectable="on" style="margin: 1 2 0 2; font-size: 12px;">';
  155.         for (var fontname in config.fontnames) {
  156.           toolbar += '<option value="' +config.fontnames[fontname]+ '">' +fontname+ '</option>'
  157.         }
  158.         toolbar += '</select>';
  159.         continue;
  160.       }
  161.       // fontsize
  162.       if (btnName == "fontsize") {
  163.         toolbar += '<select id="_' +objname+ '_FontSize" onChange="editor_action(this.id)" unselectable="on" style="margin: 1 2 0 0; font-size: 12px;">';
  164.         for (var fontsize in config.fontsizes) {
  165.           toolbar += '<option value="' +config.fontsizes[fontsize]+ '">' +fontsize+ '</option>'
  166.         }
  167.         toolbar += '</select>n';
  168.         continue;
  169.       }
  170.       // font style
  171.       if (btnName == "fontstyle") {
  172.         toolbar += '<select id="_' +objname+ '_FontStyle" onChange="editor_action(this.id)" unselectable="on" style="margin: 1 2 0 0; font-size: 12px;">';
  173.         + '<option value="">Font Style</option>';
  174.         for (var i in config.fontstyles) {
  175.           var fontstyle = config.fontstyles[i];
  176.           toolbar += '<option value="' +fontstyle.className+ '">' +fontstyle.name+ '</option>'
  177.         }
  178.         toolbar += '</select>';
  179.         continue;
  180.       }
  181.       // separator
  182.       if (btnName == "separator") {
  183.         toolbar += '<span style="border: 1px inset; width: 1px; font-size: 16px; height: 16px; margin: 0 3 0 3"></span>';
  184.         continue;
  185.       }
  186.       // buttons
  187.       var btnObj = config.btnList[btnName];
  188.       if (btnName == 'linebreak') { alert("htmlArea error: 'linebreak' must be in a subgroup by itself, not with other buttons.nnhtmlArea wysiwyg editor not created."); return; }
  189.       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.nnhtmlArea wysiwyg editor not created."); return; }
  190.       var btnCmdID   = btnObj[0];
  191.       var btnTitle   = btnObj[1];
  192.       var btnOnClick = btnObj[2];
  193.       var btnImage   = btnObj[3];
  194.       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>';
  195.     } // end of button sub-group
  196.     toolbar += tblClose;
  197.   } // end of entire button set
  198.   // build editor
  199.   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'
  200.   + toolbar
  201.   + '</td></tr></table>n'
  202.   + '</td></tr></table></span>n'
  203.   + '<textarea ID="_' +objname + '_editor" style="width:' +config.width+ '; height:' +config.height+ '; margin-top: -1px; margin-bottom: -1px;" wrap=soft></textarea>';
  204.   // add context menu
  205.   editor += '<div id="_' +objname + '_cMenu" style="position: absolute; visibility: hidden;"></div>';
  206.   //  hide original textarea and insert htmlarea after it
  207.   if (!config.debug) { document.all[objname].style.display = "none"; }
  208.   if (config.plaintextInput) {     // replace nextlines with breaks
  209.     var contents = document.all[objname].value;
  210.     contents = contents.replace(/rn/g, '<br>');
  211.     contents = contents.replace(/n/g, '<br>');
  212.     contents = contents.replace(/r/g, '<br>');
  213.     document.all[objname].value = contents;
  214.   }
  215.   // insert wysiwyg
  216.   document.all[objname].insertAdjacentHTML('afterEnd', editor)
  217.   // convert htmlarea from textarea to wysiwyg editor
  218.   editor_setmode(objname, 'init');
  219.   // call filterOutput when user submits form
  220.   for (var idx=0; idx < document.forms.length; idx++) {
  221.     var r = document.forms[idx].attachEvent('onsubmit', function() { editor_filterOutput(objname); });
  222.     if (!r) { alert("Error attaching event to form!"); }
  223.   }
  224. return true;
  225. }
  226. /* ---------------------------------------------------------------------- *
  227.   Function    : editor_action
  228.   Description : perform an editor command on selected editor content
  229.   Usage       :
  230.   Arguments   : button_id - button id string with editor and action name
  231. * ---------------------------------------------------------------------- */
  232. function editor_action(button_id) {
  233.   // split up button name into "editorID" and "cmdID"
  234.   var BtnParts = Array();
  235.   BtnParts = button_id.split("_");
  236.   var objname    = button_id.replace(/^_(.*)_[^_]*$/, '$1');
  237.   var cmdID      = BtnParts[ BtnParts.length-1 ];
  238.   var button_obj = document.all[button_id];
  239.   var editor_obj = document.all["_" +objname + "_editor"];
  240.   var config     = document.all[objname].config;
  241.   // help popup
  242.   if (cmdID == 'showhelp') {
  243.     window.open(_editor_url + "popups/editor_help.html", 'EditorHelp');
  244.     return;
  245.   }
  246.   // popup editor
  247.   if (cmdID == 'popupeditor') {
  248.     window.open(_editor_url + "popups/fullscreen.html?"+objname,
  249.                 'FullScreen',
  250.                 'toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,width=640,height=480');
  251.     return;
  252.   }
  253.   // check editor mode (don't perform actions in textedit mode)
  254.   if (editor_obj.tagName.toLowerCase() == 'textarea') { return; }
  255.   var editdoc = editor_obj.contentWindow.document;
  256.   editor_focus(editor_obj);
  257.   // get index and value for pulldowns
  258.   var idx = button_obj.selectedIndex;
  259.   var val = (idx != null) ? button_obj[ idx ].value : null;
  260.   if (0) {}   // use else if for easy cutting and pasting
  261.   //
  262.   // CUSTOM BUTTONS START HERE
  263.   //
  264.   // Custom1
  265.   else if (cmdID == 'custom1') {
  266.     alert("Hello, I am custom button 1!");
  267.   }
  268.   // Custom2
  269.   else if (cmdID == 'custom2') {  // insert some text from a popup window
  270.     var myTitle = "This is a custom title";
  271.     var myText = showModalDialog(_editor_url + "popups/custom2.html",
  272.                                  myTitle,      // str or obj specified here can be read from dialog as "window.dialogArguments"
  273.                                  "resizable: yes; help: no; status: no; scroll: no; ");
  274.     if (myText) { editor_insertHTML(objname, myText); }
  275.   }
  276.   // Custom3
  277.   else if (cmdID == 'custom3') {  // insert some text
  278.     editor_insertHTML(objname, "It's easy to add buttons that insert text!");
  279.   }
  280.   //
  281.   // END OF CUSTOM BUTTONS
  282.   //
  283.   // FontName
  284.   else if (cmdID == 'FontName' && val) {
  285.     editdoc.execCommand(cmdID,0,val);
  286.   }
  287.   // FontSize
  288.   else if (cmdID == 'FontSize' && val) {
  289.     editdoc.execCommand(cmdID,0,val);
  290.   }
  291.   // FontStyle (change CSS className)
  292.   else if (cmdID == 'FontStyle' && val) {
  293.     editdoc.execCommand('RemoveFormat');
  294.     editdoc.execCommand('FontName',0,'636c6173734e616d6520706c616365686f6c646572');
  295.     var fontArray = editdoc.all.tags("FONT");
  296.     for (i=0; i<fontArray.length; i++) {
  297.       if (fontArray[i].face == '636c6173734e616d6520706c616365686f6c646572') {
  298.         fontArray[i].face = "";
  299.         fontArray[i].className = val;
  300.         fontArray[i].outerHTML = fontArray[i].outerHTML.replace(/face=['"]+/, "");
  301.         }
  302.     }
  303.     button_obj.selectedIndex =0;
  304.   }
  305.   // fgColor and bgColor
  306.   else if (cmdID == 'ForeColor' || cmdID == 'BackColor') {
  307.     var oldcolor = _dec_to_rgb(editdoc.queryCommandValue(cmdID));
  308.     var newcolor = showModalDialog(_editor_url + "popups/select_color.html", oldcolor, "resizable: no; help: no; status: no; scroll: no;");
  309.     if (newcolor != null) { editdoc.execCommand(cmdID, false, "#"+newcolor); }
  310.   }
  311.   // execute command for buttons - if we didn't catch the cmdID by here we'll assume it's a
  312.   // commandID and pass it to execCommand().   See http://msdn.microsoft.com/workshop/author/dhtml/reference/commandids.asp
  313.   else {
  314.     // subscript & superscript, disable one before enabling the other
  315.     if (cmdID.toLowerCase() == 'subscript' && editdoc.queryCommandState('superscript')) { editdoc.execCommand('superscript'); }
  316.     if (cmdID.toLowerCase() == 'superscript' && editdoc.queryCommandState('subscript')) { editdoc.execCommand('subscript'); }
  317.     // insert link
  318.     if (cmdID.toLowerCase() == 'createlink'){
  319.       editdoc.execCommand(cmdID,1);
  320.     }
  321.     // insert image
  322.     else if (cmdID.toLowerCase() == 'insertimage'){
  323.       showModalDialog(_editor_url + "popups/insert_image.html", editdoc, "resizable: no; help: no; status: no; scroll: no; ");
  324.     }
  325.     // insert table
  326.     else if (cmdID.toLowerCase() == 'inserttable'){
  327.       showModalDialog(_editor_url + "popups/insert_table.html?"+objname,
  328.                                  window,
  329.                                  "resizable: yes; help: no; status: no; scroll: no; ");
  330.     }
  331.     // all other commands microsoft Command Identifiers
  332.     else { editdoc.execCommand(cmdID); }
  333.   }
  334.   editor_event(objname);
  335. }
  336. /* ---------------------------------------------------------------------- *
  337.   Function    : editor_event
  338.   Description : called everytime an editor event occurs
  339.   Usage       : editor_event(objname, runDelay, eventName)
  340.   Arguments   : objname - ID of textarea to replace
  341.                 runDelay: -1 = run now, no matter what
  342.                           0  = run now, if allowed
  343.                         1000 = run in 1 sec, if allowed at that point
  344. * ---------------------------------------------------------------------- */
  345. function editor_event(objname,runDelay) {
  346.   var config = document.all[objname].config;
  347.   var editor_obj  = document.all["_" +objname+  "_editor"];       // html editor object
  348.   if (runDelay == null) { runDelay = 0; }
  349.   var editdoc;
  350.   var editEvent = editor_obj.contentWindow ? editor_obj.contentWindow.event : event;
  351.   // catch keypress events
  352.     if (editEvent && editEvent.keyCode) {
  353.       var ord       = editEvent.keyCode;    // ascii order of key pressed
  354.       var ctrlKey   = editEvent.ctrlKey;
  355.       var altKey    = editEvent.altKey;
  356.       var shiftKey  = editEvent.shiftKey;
  357.       if (ord == 16) { return; }  // ignore shift key by itself
  358.       if (ord == 17) { return; }  // ignore ctrl key by itself
  359.       if (ord == 18) { return; }  // ignore alt key by itself
  360.        // cancel ENTER key and insert <BR> instead
  361. //       if (ord == 13 && editEvent.type == 'keypress') {
  362. //         editEvent.returnValue = false;
  363. //         editor_insertHTML(objname, "<br>");
  364. //         return;
  365. //       }
  366.       if (ctrlKey && (ord == 122 || ord == 90)) {     // catch ctrl-z (UNDO)
  367. //      TODO: Add our own undo/redo functionality
  368. //        editEvent.cancelBubble = true;
  369.         return;
  370.       }
  371.       if ((ctrlKey && (ord == 121 || ord == 89)) ||
  372.           ctrlKey && shiftKey && (ord == 122 || ord == 90)) {     // catch ctrl-y, ctrl-shift-z (REDO)
  373. //      TODO: Add our own undo/redo functionality
  374.         return;
  375.       }
  376.     }
  377.   // setup timer for delayed updates (some events take time to complete)
  378.   if (runDelay > 0) { return setTimeout(function(){ editor_event(objname); }, runDelay); }
  379.   // don't execute more than 3 times a second (eg: too soon after last execution)
  380.   if (this.tooSoon == 1 && runDelay >= 0) { this.queue = 1; return; } // queue all but urgent events
  381.   this.tooSoon = 1;
  382.   setTimeout(function(){
  383.     this.tooSoon = 0;
  384.     if (this.queue) { editor_event(objname,-1); };
  385.     this.queue = 0;
  386.     }, 333);  // 1/3 second
  387.   editor_updateOutput(objname);
  388.   editor_updateToolbar(objname);
  389. }
  390. /* ---------------------------------------------------------------------- *
  391.   Function    : editor_updateToolbar
  392.   Description : update toolbar state
  393.   Usage       :
  394.   Arguments   : objname - ID of textarea to replace
  395.                 action  - enable, disable, or update (default action)
  396. * ---------------------------------------------------------------------- */
  397. function editor_updateToolbar(objname,action) {
  398.   var config = document.all[objname].config;
  399.   var editor_obj  = document.all["_" +objname+  "_editor"];
  400.   // disable or enable toolbar
  401.   if (action == "enable" || action == "disable") {
  402.     var tbItems = new Array('FontName','FontSize','FontStyle');                           // add pulldowns
  403.     for (var btnName in config.btnList) { tbItems.push(config.btnList[btnName][0]); } // add buttons
  404.     for (var idxN in tbItems) {
  405.       var cmdID = tbItems[idxN].toLowerCase();
  406.       var tbObj = document.all["_" +objname+ "_" +tbItems[idxN]];
  407.       if (cmdID == "htmlmode" || cmdID == "about" || cmdID == "showhelp" || cmdID == "popupeditor") { continue; } // don't change these buttons
  408.       if (tbObj == null) { continue; }
  409.       var isBtn = (tbObj.tagName.toLowerCase() == "button") ? true : false;
  410.       if (action == "enable")  { tbObj.disabled = false; if (isBtn) { tbObj.className = 'btn' }}
  411.       if (action == "disable") { tbObj.disabled = true;  if (isBtn) { tbObj.className = 'btnNA' }}
  412.     }
  413.     return;
  414.   }
  415.   // update toolbar state
  416.   if (editor_obj.tagName.toLowerCase() == 'textarea') { return; }   // don't update state in textedit mode
  417.   var editdoc = editor_obj.contentWindow.document;
  418.   // Set FontName pulldown
  419.   var fontname_obj = document.all["_" +objname+ "_FontName"];
  420.   if (fontname_obj) {
  421.     var fontname = editdoc.queryCommandValue('FontName');
  422.     if (fontname == null) { fontname_obj.value = null; }
  423.     else {
  424.       var found = 0;
  425.       for (i=0; i<fontname_obj.length; i++) {
  426.         if (fontname.toLowerCase() == fontname_obj[i].text.toLowerCase()) {
  427.           fontname_obj.selectedIndex = i;
  428.           found = 1;
  429.         }
  430.       }
  431.       if (found != 1) { fontname_obj.value = null; }     // for fonts not in list
  432.     }
  433.   }
  434.   // Set FontSize pulldown
  435.   var fontsize_obj = document.all["_" +objname+ "_FontSize"];
  436.   if (fontsize_obj) {
  437.     var fontsize = editdoc.queryCommandValue('FontSize');
  438.     if (fontsize == null) { fontsize_obj.value = null; }
  439.     else {
  440.       var found = 0;
  441.       for (i=0; i<fontsize_obj.length; i++) {
  442.         if (fontsize == fontsize_obj[i].value) { fontsize_obj.selectedIndex = i; found=1; }
  443.       }
  444.       if (found != 1) { fontsize_obj.value = null; }     // for sizes not in list
  445.     }
  446.   }
  447.   // Set FontStyle pulldown
  448.   var classname_obj = document.all["_" +objname+ "_FontStyle"];
  449.   if (classname_obj) {
  450.     var curRange = editdoc.selection.createRange();
  451.     // check element and element parents for class names
  452.     var pElement;
  453.     if (curRange.length) { pElement = curRange[0]; }              // control tange
  454.     else                 { pElement = curRange.parentElement(); } // text range
  455.     while (pElement && !pElement.className) { pElement = pElement.parentElement; }  // keep going up
  456.     var thisClass = pElement ? pElement.className.toLowerCase() : "";
  457.     if (!thisClass && classname_obj.value) { classname_obj.value = null; }
  458.     else {
  459.       var found = 0;
  460.       for (i=0; i<classname_obj.length; i++) {
  461.         if (thisClass == classname_obj[i].value.toLowerCase()) {
  462.           classname_obj.selectedIndex = i;
  463.           found=1;
  464.         }
  465.       }
  466.       if (found != 1) { classname_obj.value = null; }     // for classes not in list
  467.     }
  468.   }
  469.   // update button states
  470.   var IDList = Array('Bold','Italic','Underline','StrikeThrough','SubScript','SuperScript','JustifyLeft','JustifyCenter','JustifyRight','InsertOrderedList','InsertUnorderedList');
  471.   for (i=0; i<IDList.length; i++) {
  472.     var btnObj = document.all["_" +objname+ "_" +IDList[i]];
  473.     if (btnObj == null) { continue; }
  474.     var cmdActive = editdoc.queryCommandState( IDList[i] );
  475.     if (!cmdActive)  {                                  // option is OK
  476.       if (btnObj.className != 'btn') { btnObj.className = 'btn'; }
  477.       if (btnObj.disabled  != false) { btnObj.disabled = false; }
  478.     } else if (cmdActive)  {                            // option already applied or mixed content
  479.       if (btnObj.className != 'btnDown') { btnObj.className = 'btnDown'; }
  480.       if (btnObj.disabled  != false)   { btnObj.disabled = false; }
  481.     }
  482.   }
  483. }
  484. /* ---------------------------------------------------------------------- *
  485.   Function    : editor_updateOutput
  486.   Description : update hidden output field with data from wysiwg
  487. * ---------------------------------------------------------------------- */
  488. function editor_updateOutput(objname) {
  489.   var config     = document.all[objname].config;
  490.   var editor_obj  = document.all["_" +objname+  "_editor"];       // html editor object
  491.   var editEvent = editor_obj.contentWindow ? editor_obj.contentWindow.event : event;
  492.   var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');
  493.   var editdoc = isTextarea ? null : editor_obj.contentWindow.document;
  494.   // get contents of edit field
  495.   var contents;
  496.   if (isTextarea) { contents = editor_obj.value; }
  497.   else            { contents = editdoc.body.innerHTML; }
  498.   // check if contents has changed since the last time we ran this routine
  499.   if (config.lastUpdateOutput && config.lastUpdateOutput == contents) { return; }
  500.   else { config.lastUpdateOutput = contents; }
  501.   // update hidden output field
  502.   document.all[objname].value = contents;
  503. }
  504. /* ---------------------------------------------------------------------- *
  505.   Function    : editor_filterOutput
  506.   Description :
  507. * ---------------------------------------------------------------------- */
  508. function editor_filterOutput(objname) {
  509.   editor_updateOutput(objname);
  510.   var contents = document.all[objname].value;
  511.   var config   = document.all[objname].config;
  512.   // ignore blank contents
  513.   if (contents.toLowerCase() == '<p>&nbsp;</p>') { contents = ""; }
  514.   // filter tag - this code is run for each HTML tag matched
  515.   var filterTag = function(tagBody,tagName,tagAttr) {
  516.     tagName = tagName.toLowerCase();
  517.     var closingTag = (tagBody.match(/^<//)) ? true : false;
  518.     // fix placeholder URLS - remove absolute paths that IE adds
  519.     if (tagName == 'img') { tagBody = tagBody.replace(/(srcs*=s*.)[^*]*(***)/, "$1$2"); }
  520.     if (tagName == 'a')   { tagBody = tagBody.replace(/(hrefs*=s*.)[^*]*(***)/, "$1$2"); }
  521.     // add additional tag filtering here
  522.     // convert to vbCode
  523. //    if      (tagName == 'b' || tagName == 'strong') {
  524. //      if (closingTag) { tagBody = "[/b]"; } else { tagBody = "[b]"; }
  525. //    }
  526. //    else if (tagName == 'i' || tagName == 'em') {
  527. //      if (closingTag) { tagBody = "[/i]"; } else { tagBody = "[i]"; }
  528. //    }
  529. //    else if (tagName == 'u') {
  530. //      if (closingTag) { tagBody = "[/u]"; } else { tagBody = "[u]"; }
  531. //    }
  532. //    else {
  533. //      tagBody = ""; // disallow all other tags!
  534. //    }
  535.     return tagBody;
  536.   };
  537.   // match tags and call filterTag
  538.   RegExp.lastIndex = 0;
  539.     var matchTag = /</?(w+)((?:[^'">]*|'[^']*'|"[^"]*")*)>/g;   // this will match tags, but still doesn't handle container tags (textarea, comments, etc)
  540.   contents = contents.replace(matchTag, filterTag);
  541.   // remove nextlines from output (if requested)
  542.   if (config.replaceNextlines) {
  543.     contents = contents.replace(/rn/g, ' ');
  544.     contents = contents.replace(/n/g, ' ');
  545.     contents = contents.replace(/r/g, ' ');
  546.   }
  547.   // update output with filtered content
  548.   document.all[objname].value = contents;
  549. }
  550. /* ---------------------------------------------------------------------- *
  551.   Function    : editor_setmode
  552.   Description : change mode between WYSIWYG and HTML editor
  553.   Usage       : editor_setmode(objname, mode);
  554.   Arguments   : objname - button id string with editor and action name
  555.                 mode      - init, textedit, or wysiwyg
  556. * ---------------------------------------------------------------------- */
  557. function editor_setmode(objname, mode) {
  558.   var config     = document.all[objname].config;
  559.   var editor_obj = document.all["_" +objname + "_editor"];
  560.   // wait until document is fully loaded
  561.   if (document.readyState != 'complete') {
  562.     setTimeout(function() { editor_setmode(objname,mode) }, 25);
  563.     return;
  564.   }
  565.   // define different editors
  566.   var TextEdit   = '<textarea ID="_' +objname + '_editor" style="width:' +editor_obj.style.width+ '; height:' +editor_obj.style.height+ '; margin-top: -1px; margin-bottom: -1px;"></textarea>';
  567.   var RichEdit   = '<iframe ID="_' +objname+ '_editor"    style="width:' +editor_obj.style.width+ '; height:' +editor_obj.style.height+ ';"></iframe>';
  568.  // src="' +_editor_url+ 'popups/blank.html"
  569.   //
  570.   // Switch to TEXTEDIT mode
  571.   //
  572.   if (mode == "textedit" || editor_obj.tagName.toLowerCase() == 'iframe') {
  573.     config.mode = "textedit";
  574.     var editdoc = editor_obj.contentWindow.document;
  575.     var contents = editdoc.body.createTextRange().htmlText;
  576.     editor_obj.outerHTML = TextEdit;
  577.     editor_obj = document.all["_" +objname + "_editor"];
  578.     editor_obj.value = contents;
  579.     editor_event(objname);
  580.     editor_updateToolbar(objname, "disable");  // disable toolbar items
  581.     // set event handlers
  582.     editor_obj.onkeydown   = function() { editor_event(objname); }
  583.     editor_obj.onkeypress  = function() { editor_event(objname); }
  584.     editor_obj.onkeyup     = function() { editor_event(objname); }
  585.     editor_obj.onmouseup   = function() { editor_event(objname); }
  586.     editor_obj.ondrop      = function() { editor_event(objname, 100); }     // these events fire before they occur
  587.     editor_obj.oncut       = function() { editor_event(objname, 100); }
  588.     editor_obj.onpaste     = function() { editor_event(objname, 100); }
  589.     editor_obj.onblur      = function() { editor_event(objname, -1); }
  590.     editor_updateOutput(objname);
  591.     editor_focus(editor_obj);
  592.   }
  593.   //
  594.   // Switch to WYSIWYG mode
  595.   //
  596.   else {
  597.     config.mode = "wysiwyg";
  598.     var contents = editor_obj.value;
  599.     if (mode == 'init') { contents = document.all[objname].value; } // on init use original textarea content
  600.     // create editor
  601.     editor_obj.outerHTML = RichEdit;
  602.     editor_obj = document.all["_" +objname + "_editor"];
  603.     // get iframe document object
  604.     // create editor contents (and default styles for editor)
  605.     var html = "";
  606.     html += '<html><head>n';
  607.     if (config.stylesheet) {
  608.       html += '<link href="' +config.stylesheet+ '" rel="stylesheet" type="text/css">n';
  609.     }
  610.     html += '<style>n';
  611.     html += 'body {' +config.bodyStyle+ '} n';
  612.     for (var i in config.fontstyles) {
  613.       var fontstyle = config.fontstyles[i];
  614.       if (fontstyle.classStyle) {
  615.         html += '.' +fontstyle.className+ ' {' +fontstyle.classStyle+ '}n';
  616.       }
  617.     }
  618.     html += '</style>n'
  619.       + '</head>n'
  620.       + '<body contenteditable="true" topmargin=1 leftmargin=1'
  621. // still working on this
  622. //      + ' oncontextmenu="parent.editor_cMenu_generate(window,'' +objname+ '');"'
  623.       +'>'
  624.       + contents
  625.       + '</body>n'
  626.       + '</html>n';
  627.     // write to editor window
  628.     var editdoc = editor_obj.contentWindow.document;
  629.     editdoc.open();
  630.     editdoc.write(html);
  631.     editdoc.close();
  632.     editor_updateToolbar(objname, "enable");  // enable toolbar items
  633.     // store objname under editdoc
  634.     editdoc.objname = objname;
  635.     // set event handlers
  636.     editdoc.onkeydown      = function() { editor_event(objname); }
  637.     editdoc.onkeypress     = function() { editor_event(objname); }
  638.     editdoc.onkeyup        = function() { editor_event(objname); }
  639.     editdoc.onmouseup      = function() { editor_event(objname); }
  640.     editdoc.body.ondrop    = function() { editor_event(objname, 100); }     // these events fire before they occur
  641.     editdoc.body.oncut     = function() { editor_event(objname, 100); }
  642.     editdoc.body.onpaste   = function() { editor_event(objname, 100); }
  643.     editdoc.body.onblur    = function() { editor_event(objname, -1); }
  644.     // bring focus to editor
  645.     if (mode != 'init') {             // don't focus on page load, only on mode switch
  646.       editor_focus(editor_obj);
  647.     }
  648.   }
  649.   // Call update UI
  650.   if (mode != 'init') {             // don't update UI on page load, only on mode switch
  651.     editor_event(objname);
  652.   }
  653. }
  654. /* ---------------------------------------------------------------------- *
  655.   Function    : editor_focus
  656.   Description : bring focus to the editor
  657.   Usage       : editor_focus(editor_obj);
  658.   Arguments   : editor_obj - editor object
  659. * ---------------------------------------------------------------------- */
  660. function editor_focus(editor_obj) {
  661.   // check editor mode
  662.   if (editor_obj.tagName.toLowerCase() == 'textarea') {         // textarea
  663.     var myfunc = function() { editor_obj.focus(); };
  664.     setTimeout(myfunc,100);                                     // doesn't work all the time without delay
  665.   }
  666.   else {                                                        // wysiwyg
  667.     var editdoc = editor_obj.contentWindow.document;            // get iframe editor document object
  668.     var editorRange = editdoc.body.createTextRange();           // editor range
  669.     var curRange    = editdoc.selection.createRange();          // selection range
  670.     if (curRange.length == null &&                              // make sure it's not a controlRange
  671.         !editorRange.inRange(curRange)) {                       // is selection in editor range
  672.       editorRange.collapse();                                   // move to start of range
  673.       editorRange.select();                                     // select
  674.       curRange = editorRange;
  675.     }
  676.   }
  677. }
  678. /* ---------------------------------------------------------------------- *
  679.   Function    : editor_about
  680.   Description : display "about this editor" popup
  681. * ---------------------------------------------------------------------- */
  682. function editor_about(objname) {
  683.   showModalDialog(_editor_url + "popups/about.html", window, "resizable: yes; help: no; status: no; scroll: no; ");
  684. }
  685. /* ---------------------------------------------------------------------- *
  686.   Function    : _dec_to_rgb
  687.   Description : convert dec color value to rgb hex
  688.   Usage       : var hex = _dec_to_rgb('65535');   // returns FFFF00
  689.   Arguments   : value   - dec value
  690. * ---------------------------------------------------------------------- */
  691. function _dec_to_rgb(value) {
  692.   var hex_string = "";
  693.   for (var hexpair = 0; hexpair < 3; hexpair++) {
  694.     var myByte = value & 0xFF;            // get low byte
  695.     value >>= 8;                        // drop low byte
  696.     var nybble2 = myByte & 0x0F;          // get low nybble (4 bits)
  697.     var nybble1 = (myByte >> 4) & 0x0F;   // get high nybble
  698.     hex_string += nybble1.toString(16); // convert nybble to hex
  699.     hex_string += nybble2.toString(16); // convert nybble to hex
  700.   }
  701.   return hex_string.toUpperCase();
  702. }
  703. /* ---------------------------------------------------------------------- *
  704.   Function    : editor_insertHTML
  705.   Description : insert string at current cursor position in editor.  If
  706.                 two strings are specifed, surround selected text with them.
  707.   Usage       : editor_insertHTML(objname, str1, [str2], reqSelection)
  708.   Arguments   : objname - ID of textarea
  709.                 str1 - HTML or text to insert
  710.                 str2 - HTML or text to insert (optional argument)
  711.                 reqSelection - (1 or 0) give error if no text selected
  712. * ---------------------------------------------------------------------- */
  713. function editor_insertHTML(objname, str1,str2, reqSel) {
  714.   var config     = document.all[objname].config;
  715.   var editor_obj = document.all["_" +objname + "_editor"];    // editor object
  716.   if (str1 == null) { str1 = ''; }
  717.   if (str2 == null) { str2 = ''; }
  718.   // for non-wysiwyg capable browsers just add to end of textbox
  719.   if (document.all[objname] && editor_obj == null) {
  720.     document.all[objname].focus();
  721.     document.all[objname].value = document.all[objname].value + str1 + str2;
  722.     return;
  723.   }
  724.   // error checking
  725.   if (editor_obj == null) { return alert("Unable to insert HTML.  Invalid object name '" +objname+ "'."); }
  726.   editor_focus(editor_obj);
  727.   var tagname = editor_obj.tagName.toLowerCase();
  728.   var sRange;
  729.  // insertHTML for wysiwyg iframe
  730.   if (tagname == 'iframe') {
  731.     var editdoc = editor_obj.contentWindow.document;
  732.     sRange  = editdoc.selection.createRange();
  733.     var sHtml   = sRange.htmlText;
  734.     // check for control ranges
  735.     if (sRange.length) { return alert("Unable to insert HTML.  Try highlighting content instead of selecting it."); }
  736.     // insert HTML
  737.     var oldHandler = window.onerror;
  738.     window.onerror = function() { alert("Unable to insert HTML for current selection."); return true; } // partial table selections cause errors
  739.     if (sHtml.length) {                                 // if content selected
  740.       if (str2) { sRange.pasteHTML(str1 +sHtml+ str2) } // surround
  741.       else      { sRange.pasteHTML(str1); }             // overwrite
  742.     } else {                                            // if insertion point only
  743.       if (reqSel) { return alert("Unable to insert HTML.  You must select something first."); }
  744.       sRange.pasteHTML(str1 + str2);                    // insert strings
  745.     }
  746.     window.onerror = oldHandler;
  747.   }
  748.   // insertHTML for plaintext textarea
  749.   else if (tagname == 'textarea') {
  750.     editor_obj.focus();
  751.     sRange  = document.selection.createRange();
  752.     var sText   = sRange.text;
  753.     // insert HTML
  754.     if (sText.length) {                                 // if content selected
  755.       if (str2) { sRange.text = str1 +sText+ str2; }  // surround
  756.       else      { sRange.text = str1; }               // overwrite
  757.     } else {                                            // if insertion point only
  758.       if (reqSel) { return alert("Unable to insert HTML.  You must select something first."); }
  759.       sRange.text = str1 + str2;                        // insert strings
  760.     }
  761.   }
  762.   else { alert("Unable to insert HTML.  Unknown object tag type '" +tagname+ "'."); }
  763.   // move to end of new content
  764.   sRange.collapse(false); // move to end of range
  765.   sRange.select();        // re-select
  766. }
  767. /* ---------------------------------------------------------------------- *
  768.   Function    : editor_getHTML
  769.   Description : return HTML contents of editor (in either wywisyg or html mode)
  770.   Usage       : var myHTML = editor_getHTML('objname');
  771. * ---------------------------------------------------------------------- */
  772. function editor_getHTML(objname) {
  773.   var editor_obj = document.all["_" +objname + "_editor"];
  774.   var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');
  775.   if (isTextarea) { return editor_obj.value; }
  776.   else            { return editor_obj.contentWindow.document.body.innerHTML; }
  777. }
  778. /* ---------------------------------------------------------------------- *
  779.   Function    : editor_setHTML
  780.   Description : set HTML contents of editor (in either wywisyg or html mode)
  781.   Usage       : editor_setHTML('objname',"<b>html</b> <u>here</u>");
  782. * ---------------------------------------------------------------------- */
  783. function editor_setHTML(objname, html) {
  784.   var editor_obj = document.all["_" +objname + "_editor"];
  785.   var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');
  786.   if (isTextarea) { editor_obj.value = html; }
  787.   else            { editor_obj.contentWindow.document.body.innerHTML = html; }
  788. }
  789. /* ---------------------------------------------------------------------- *
  790.   Function    : editor_appendHTML
  791.   Description : append HTML contents to editor (in either wywisyg or html mode)
  792.   Usage       : editor_appendHTML('objname',"<b>html</b> <u>here</u>");
  793. * ---------------------------------------------------------------------- */
  794. function editor_appendHTML(objname, html) {
  795.   var editor_obj = document.all["_" +objname + "_editor"];
  796.   var isTextarea = (editor_obj.tagName.toLowerCase() == 'textarea');
  797.   if (isTextarea) { editor_obj.value += html; }
  798.   else            { editor_obj.contentWindow.document.body.innerHTML += html; }
  799. }
  800. /* ---------------------------------------------------------------- */
  801. function _isMouseOver(obj,event) {       // determine if mouse is over object
  802.   var mouseX    = event.clientX;
  803.   var mouseY    = event.clientY;
  804.   var objTop    = obj.offsetTop;
  805.   var objBottom = obj.offsetTop + obj.offsetHeight;
  806.   var objLeft   = obj.offsetLeft;
  807.   var objRight  = obj.offsetLeft + obj.offsetWidth;
  808.   if (mouseX >= objLeft && mouseX <= objRight &&
  809.       mouseY >= objTop  && mouseY <= objBottom) { return true; }
  810.   return false;
  811. }
  812. /* ---------------------------------------------------------------- */
  813. function editor_cMenu_generate(editorWin,objname) {
  814.   var parentWin = window;
  815.   editorWin.event.returnValue = false;  // cancel default context menu
  816.   // define content menu options
  817.   var cMenuOptions = [ // menu name, shortcut displayed, javascript code
  818.     ['Cut', 'Ctrl-X', function() {}],
  819.     ['Copy', 'Ctrl-C', function() {}],
  820.     ['Paste', 'Ctrl-C', function() {}],
  821.     ['Delete', 'DEL', function() {}],
  822.     ['---', null, null],
  823.     ['Select All', 'Ctrl-A', function() {}],
  824.     ['Clear All', '', function() {}],
  825.     ['---', null, null],
  826.     ['About this editor...', '', function() {
  827.       alert("about this editor");
  828.     }]];
  829.     editor_cMenu.options = cMenuOptions; // save options
  830.   // generate context menu
  831.   var cMenuHeader = ''
  832.     + '<div id="_'+objname+'_cMenu" onblur="editor_cMenu(this);" oncontextmenu="return false;" onselectstart="return false"'
  833.     + '  style="position: absolute; visibility: hidden; cursor: default; width: 167px; background-color: threedface;'
  834.     + '         border: solid 1px; border-color: threedlightshadow threeddarkshadow threeddarkshadow threedlightshadow;">'
  835.     + '<table border=0 cellspacing=0 cellpadding=0 width="100%" style="width: 167px; background-color: threedface; border: solid 1px; border-color: threedhighlight threedshadow threedshadow threedhighlight;">'
  836.     + ' <tr><td colspan=2 height=1></td></tr>';
  837.   var cMenuList = '';
  838.   var cMenuFooter = ''
  839.     + ' <tr><td colspan=2 height=1></td></tr>'
  840.     + '</table></div>';
  841.   for (var menuIdx in editor_cMenu.options) {
  842.     var menuName = editor_cMenu.options[menuIdx][0];
  843.     var menuKey  = editor_cMenu.options[menuIdx][1];
  844.     var menuCode = editor_cMenu.options[menuIdx][2];
  845.     // separator
  846.     if (menuName == "---" || menuName == "separator") {
  847.       cMenuList += ' <tr><td colspan=2 class="cMenuDivOuter"><div class="cMenuDivInner"></div></td></tr>';
  848.     }
  849.     // menu option
  850.     else {
  851.       cMenuList += '<tr class="cMenu" onMouseOver="editor_cMenu(this)" onMouseOut="editor_cMenu(this)" onClick="editor_cMenu(this, '' +menuIdx+ '','' +objname+ '')">';
  852.       if (menuKey) { cMenuList += ' <td align=left class="cMenu">' +menuName+ '</td><td align=right class="cMenu">' +menuKey+ '</td>'; }
  853.       else         { cMenuList += ' <td colspan=2 class="cMenu">' +menuName+ '</td>'; }
  854.       cMenuList += '</tr>';
  855.     }
  856.   }
  857.   var cMenuHTML = cMenuHeader + cMenuList + cMenuFooter;
  858.   document.all['_'+objname+'_cMenu'].outerHTML = cMenuHTML;
  859.   editor_cMenu_setPosition(parentWin, editorWin, objname);
  860.   parentWin['_'+objname+'_cMenu'].style.visibility = 'visible';
  861.   parentWin['_'+objname+'_cMenu'].focus();
  862. }
  863. /* ---------------------------------------------------------------- */
  864. function editor_cMenu_setPosition(parentWin, editorWin, objname) {      // set object position that won't overlap window edge
  865.   var event    = editorWin.event;
  866.   var cMenuObj = parentWin['_'+objname+'_cMenu'];
  867.   var mouseX   = event.clientX + parentWin.document.all['_'+objname+'_editor'].offsetLeft;
  868.   var mouseY   = event.clientY + parentWin.document.all['_'+objname+'_editor'].offsetTop;
  869.   var cMenuH   = cMenuObj.offsetHeight;
  870.   var cMenuW   = cMenuObj.offsetWidth;
  871.   var pageH    = document.body.clientHeight + document.body.scrollTop;
  872.   var pageW    = document.body.clientWidth + document.body.scrollLeft;
  873.   // set horzontal position
  874.   if (mouseX + 5 + cMenuW > pageW) { var left = mouseX - cMenuW - 5; } // too far right
  875.   else                            { var left = mouseX + 5; }
  876.   // set vertical position
  877.   if (mouseY + 5 + cMenuH > pageH) { var top = mouseY - cMenuH + 5; } // too far down
  878.   else                            { var top = mouseY + 5; }
  879.   cMenuObj.style.top = top;
  880.   cMenuObj.style.left = left;
  881. }
  882. /* ---------------------------------------------------------------- */
  883. function editor_cMenu(obj,menuIdx,objname) {
  884.   var action = event.type;
  885.   if      (action == "mouseover" && !obj.disabled && obj.tagName.toLowerCase() == 'tr') {
  886.     obj.className = 'cMenuOver';
  887.     for (var i=0; i < obj.cells.length; i++) { obj.cells[i].className = 'cMenuOver'; }
  888.   }
  889.   else if (action == "mouseout" && !obj.disabled && obj.tagName.toLowerCase() == 'tr')  {
  890.     obj.className = 'cMenu';
  891.     for (var i=0; i < obj.cells.length; i++) { obj.cells[i].className = 'cMenu'; }
  892.   }
  893.   else if (action == "click" && !obj.disabled) {
  894.     document.all['_'+objname+'_cMenu'].style.visibility = "hidden";
  895.     var menucode = editor_cMenu.options[menuIdx][2];
  896.     menucode();
  897.   }
  898.   else if (action == "blur") {
  899.     if (!_isMouseOver(obj,event)) { obj.style.visibility = 'hidden'; }
  900.     else {
  901.       if (obj.style.visibility != "hidden") { obj.focus(); }
  902.     }
  903.   }
  904.   else { alert("editor_cMenu, unknown action: " + action); }
  905. }
  906. /* ---------------------------------------------------------------------- */
  907. //创建以新的配置的对象
  908. function newConfig(contentName)
  909. {
  910. var config = new Object();    // 创建一个新的配置对象
  911. config.width = "800px";
  912. config.height = "400px";
  913. config.bodyStyle = 'background-color: white; font-family: "Verdana"; font-size: x-small;';
  914. config.debug = 0;
  915. // NOTE:  You can remove any of these blocks and use the default config!
  916. config.toolbar = [
  917. ['fontname'],
  918. ['fontsize'],
  919. ['fontstyle'],
  920. ['linebreak'],
  921. ['bold','italic','underline','separator'],
  922. //  ['strikethrough','subscript','superscript','separator'],
  923. ['justifyleft','justifycenter','justifyright','separator'],
  924. ['OrderedList','UnOrderedList','Outdent','Indent','separator'],
  925. ['forecolor','backcolor','separator'],
  926. // ['HorizontalRule','Createlink','InsertImage','htmlmode','separator'],
  927. // ['about','help','popupeditor'],
  928. ];
  929. // 配置对象的字体
  930. config.fontnames = {
  931. "宋体":       "宋体",
  932. "Arial":           "arial, helvetica, sans-serif",
  933. "Courier New":     "courier new, courier, mono",
  934. "Georgia":         "Georgia, Times New Roman, Times, Serif",
  935. "Tahoma":          "Tahoma, Arial, Helvetica, sans-serif",
  936. "Times New Roman": "times new roman, times, serif",
  937. "Verdana":         "Verdana, Arial, Helvetica, sans-serif",
  938. "impact":          "impact",
  939. "WingDings":       "WingDings"
  940. };
  941. // 配置字体的大小
  942. config.fontsizes = {
  943. "1 (8 pt)":  "1",
  944. "2 (10 pt)": "2",
  945. "3 (12 pt)": "3",
  946. "4 (14 pt)": "4",
  947. "5 (18 pt)": "5",
  948. "6 (24 pt)": "6",
  949. "7 (36 pt)": "7"
  950.    };
  951. // 配置字体的样式
  952. //// config.stylesheet = "http://www.domain.com/sample.css";
  953.    // 配置字体的样式
  954. config.fontstyles = [   // make sure classNames are defined in the page the content is being display as well in or they won't work!
  955.    { name: "headline",     className: "headline",  classStyle: "font-family: arial black, arial; font-size: 28px; letter-spacing: -2px;" },
  956.    { name: "arial red",    className: "headline2", classStyle: "font-family: arial black, arial; font-size: 12px; letter-spacing: -2px; color:red" },
  957.    { name: "verdana blue", className: "headline4", classStyle: "font-family: verdana; font-size: 18px; letter-spacing: -2px; color:blue" }
  958. // leave classStyle blank if it's defined in config.stylesheet (above), like this:
  959. //  { name: "verdana blue", className: "headline4", classStyle: "" }
  960. ];
  961. // 设置对象,和对象的样式
  962.     editor_generate(contentName,config); // 指定输入区域的样式
  963. }
  964. //创建以新的配置的对象:信息修改部分
  965. function update_newConfig()
  966. {
  967. var config = new Object();    // 创建一个新的配置对象
  968. config.width = "800px";
  969. config.height = "400px";
  970. config.bodyStyle = 'background-color: white; font-family: "Verdana"; font-size: x-small;';
  971. config.debug = 0;
  972. // NOTE:  You can remove any of these blocks and use the default config!
  973. config.toolbar = [
  974. ['fontname'],
  975. ['fontsize'],
  976. ['fontstyle'],
  977. ['linebreak'],
  978. ['bold','italic','underline','separator'],
  979. //  ['strikethrough','subscript','superscript','separator'],
  980. ['justifyleft','justifycenter','justifyright','separator'],
  981. ['OrderedList','UnOrderedList','Outdent','Indent','separator'],
  982. ['forecolor','backcolor','separator'],
  983. // ['HorizontalRule','Createlink','InsertImage','htmlmode','separator'],
  984. ['about','help','popupeditor'],
  985. ];
  986. // 配置对象的字体
  987. config.fontnames = {
  988. "宋体":       "宋体",
  989. "Arial":           "arial, helvetica, sans-serif",
  990. "Courier New":     "courier new, courier, mono",
  991. "Georgia":         "Georgia, Times New Roman, Times, Serif",
  992. "Tahoma":          "Tahoma, Arial, Helvetica, sans-serif",
  993. "Times New Roman": "times new roman, times, serif",
  994. "Verdana":         "Verdana, Arial, Helvetica, sans-serif",
  995. "impact":          "impact",
  996. "WingDings":       "WingDings"
  997. };
  998. // 配置字体的大小
  999. config.fontsizes = {
  1000. "1 (8 pt)":  "1",
  1001. "2 (10 pt)": "2",
  1002. "3 (12 pt)": "3",
  1003. "4 (14 pt)": "4",
  1004. "5 (18 pt)": "5",
  1005. "6 (24 pt)": "6",
  1006. "7 (36 pt)": "7"
  1007.    };
  1008. // 配置字体的样式
  1009. //// config.stylesheet = "http://www.domain.com/sample.css";
  1010.    // 配置字体的样式
  1011. config.fontstyles = [   // make sure classNames are defined in the page the content is being display as well in or they won't work!
  1012.    { name: "headline",     className: "headline",  classStyle: "font-family: arial black, arial; font-size: 28px; letter-spacing: -2px;" },
  1013.    { name: "arial red",    className: "headline2", classStyle: "font-family: arial black, arial; font-size: 12px; letter-spacing: -2px; color:red" },
  1014.    { name: "verdana blue", className: "headline4", classStyle: "font-family: verdana; font-size: 18px; letter-spacing: -2px; color:blue" }
  1015. // leave classStyle blank if it's defined in config.stylesheet (above), like this:
  1016. //  { name: "verdana blue", className: "headline4", classStyle: "" }
  1017. ];
  1018. // 设置对象,和对象的样式
  1019.     editor_generate('content',config); // 指定中文输入区域的样式
  1020. }
  1021. //浏览器版本的控制
  1022. function browserControl()
  1023. {
  1024.     _editor_url = ""; // 当前文件的绝对的路径
  1025.     var win_ie_ver = parseFloat(navigator.appVersion.split("MSIE")[1]);  // 获得IE浏览器的版本号
  1026.     /*
  1027.      *  判断其他浏览器的方式
  1028.      */
  1029.     if (navigator.userAgent.indexOf('Mac')        >= 0) { win_ie_ver = 0; }
  1030.     if (navigator.userAgent.indexOf('Windows CE') >= 0) { win_ie_ver = 0; }
  1031.     if (navigator.userAgent.indexOf('Opera')      >= 0) { win_ie_ver = 0; }
  1032.                     // 这里是判断浏览器,需要IE5.5以上的版本支持
  1033.     if (win_ie_ver >= 5.5) {
  1034. // document.write('<scr'+'ipt src="' +_editor_url+ 'js/editor.js" language="Javascript1.2"></scr'+'ipt>');
  1035.     } else {
  1036.             alert("不支持当前浏览器的版本");
  1037.             document.write('<scr'+'ipt>function editor_generate() { return false; }</scr'+'ipt>');
  1038.     }
  1039. // -->
  1040. }