rte.js
上传用户:simon2hong
上传日期:2021-11-18
资源大小:16746k
文件大小:18k
源码类别:

OA系统

开发平台:

C#

  1. // Internal (private) properties.  
  2. // RichEditor is the global RichEditor object (function) of which there is only
  3. // 1 instance.
  4. RichEditor.txtView = true;         // WYSIWYG mode.  false == View Source
  5. // initEditor(): Initialise the editor (called on window load, see below)
  6. function initEditor()
  7. {
  8. // Apply style data if supplied
  9. if (!public_description.styleData) {
  10.   public_description.put_styleData(null);
  11. }
  12. // Apply default editor options
  13. var strDefaults = 'dragdrop=no;source=yes';
  14. strDefaults += ';history=' + (document.queryCommandSupported('Undo') ? 'yes' : 'no');
  15. applyOptions(strDefaults);
  16. // Prepare the editable region
  17. loading.style.display = 'none';
  18.   doc.contentEditable = "true";
  19.   editor.style.visibility = 'visible';
  20.   if(parent.document.all("IMG_ATTACHMENT_ID"))
  21.      document.all("IMG_ATTACHMENT_ID").value=parent.document.all("IMG_ATTACHMENT_ID").value;
  22.   if(parent.document.all("IMG_ATTACHMENT_NAME"))
  23.      document.all("IMG_ATTACHMENT_NAME").value=parent.document.all("IMG_ATTACHMENT_NAME").value;
  24.   
  25. // OZ - 12-06-2002
  26. // Put focus into the document (required when no HTML is supplied via docHtml property)
  27. doc.focus();
  28. }
  29. // checkRange(): make sure our pretend document (the content editable
  30. // DIV with id of "doc") has focus and that a text range exists (which
  31. // is what execCommand() operates on).
  32. function checkRange()
  33. {
  34.    RichEditor.selectedImage = null;
  35.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  36.    doc.focus();
  37.    if (document.selection.type == "None") {
  38.       document.selection.createRange();
  39.    }
  40. var r = document.selection.createRange();
  41.    DBG(1, 'RANGE Bounding('
  42.             + 'top='+r.boundingHeight
  43.             + ', left='+r.boundingHeight
  44.             + ', width='+r.boundingWidth
  45.             + ', height='+r.boundingHeight + ')'
  46.          + ', Offset('
  47.             + 'top='+r.offsetTop
  48.             + ', left='+r.offsetLeft + ')'
  49.          + ', Text=(' + r.text + ')'
  50.          + ', HTML=(' + r.htmlText + ')'
  51.       );
  52. }
  53. // post(): Called in response to clicking the post button in the
  54. // toolbar. It fires an event in the container named post, passing the
  55. // HTML of our newly edited document as the data argument.
  56. function post()
  57. {
  58.    //DBG(1, 'Raise "post" event');
  59.    //window.external.raiseEvent("post", doc.innerHTML);
  60.    //alert(doc.innerHTML);
  61.    return doc.innerHTML;
  62. }
  63. // insert(): called in response to clicking the insert table, image,
  64. // smily icons in the toolbar.  Loads up an appropriate dialog to
  65. // prompt for information, the dialog then returns the HTML code or
  66. // NULL.  We paste the HTML code into the document.
  67. function insert(what)
  68. {
  69.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  70.    DBG(1, 'insert' + what + ')');
  71.    // Chose action based on what is being inserted.
  72.    switch(what)
  73.    {
  74.    case "table":
  75.       strPage = "dlg_ins_table.html";
  76.       strAttr = "status:no;dialogWidth:340px;dialogHeight:360px;help:no";
  77.       break;
  78.    case "smile":
  79.       strPage = "dlg_ins_smile.html";
  80.       strAttr = "status:no;dialogWidth:300px;dialogHeight:350px;help:no";
  81.       break;
  82.    case "char":
  83.       strPage = "dlg_ins_char.html";
  84.       strAttr = "status:no;dialogWidth:450px;dialogHeight:290px;help:no";
  85.       break;
  86.    case "image":
  87.       strPage = "dlg_ins_image.html";
  88.       strAttr = "status:no;dialogWidth:400px;dialogHeight:210px;help:no";' '
  89.       break;
  90.    case "about":
  91.       strPage = "dlg_about.html";
  92.       strAttr = "status:no;dialogWidth:250px;dialogHeight:130px;help:no";' '
  93.       break;
  94.    }
  95.    // run the dialog that implements this type of element
  96.    html = showModalDialog(strPage, window, strAttr);
  97.    // and insert any result into the document.
  98.    if (html) {
  99.       insertHtml(html);
  100.    }
  101. }
  102. // insertHtml(): Insert the supplied HTML into the current position
  103. // within the document.
  104. function insertHtml(html)
  105. {
  106.    doc.focus();
  107.    var sel = document.selection.createRange();
  108.    // don't try to insert HTML into a control selection (ie. image or table)
  109.    if (document.selection.type == 'Control') {
  110.       return;
  111.    }
  112.    
  113.    sel.pasteHTML(html);
  114. }
  115. // doStyle(): called to handle the simple style commands such a bold,
  116. // italic etc.  These require no special handling, just a call to
  117. // execCommand().  We also call reset so that the toolbar represents
  118. // the state of the current text.
  119. //
  120. // 2002-07-30 Updated based on patch submitted by Michael Keck (mkkeck) 
  121. //
  122. function doStyle(s){ 
  123.    if(!RichEditor.txtView) return; 
  124.    /* Disabled in View Source mode */ 
  125.    DBG(1, 'doStyle(' + s + ')'); 
  126.    checkRange(); 
  127.    if(s!='InsertHorizontalRule'){ 
  128.       /* what command string? */ 
  129.       document.execCommand(s); 
  130.    } else if( s=='InsertHorizontalRule') { 
  131.       /* if s=='InsertHorizontalRule then use this command */ 
  132.       document.execCommand(s,false, null); 
  133.       /* Note: 
  134.       In your source view the <HR> has an ID like this 
  135.       <HR id=null> 
  136.       */ 
  137.    } 
  138.    reset(); 
  139. // link(): called to insert a hyperlink.  It will use the selected text
  140. // if there is some, or the URL entered if not.  If clicked when over a
  141. // link, that link is allowed to be edited.
  142. function link(on)
  143. {
  144.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  145.    var strURL = "http://";
  146.    var strText;
  147.    // First, pick up the current selection.
  148.    doc.focus();
  149.    var r = document.selection.createRange();
  150.    var el = r.parentElement();
  151.    // Is this aready a link?
  152.    if (el && el.nodeName == "A") {
  153.       r.moveToElementText(el);
  154.       if (!on) {      // If removing the link, then replace all with
  155.          r.pasteHTML(el.innerHTML);
  156.          return;
  157.       }
  158.       strURL = el.href;
  159.    }
  160.    // Get the text associated with this link
  161.    strText = r.text;
  162.    // Prompt for the URL
  163.    strURL = window.prompt("输入地址:", strURL);
  164.    if (strURL) {
  165.       // Default the TEXT to the url if non selected
  166.       if (!strText || !strText.length) {
  167.          strText = strURL;
  168.       }
  169.       // Replace with new URL
  170.       r.pasteHTML('<A href=' + strURL + ' target=_new>' + strText + '</a>');
  171.    }
  172.    reset();
  173. }
  174. // sel(); similar to doStyle() but called from the dropdown list boxes
  175. // for font and style commands.
  176. function sel(el)
  177. {
  178.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  179.    checkRange();
  180.    switch(el.id)
  181.    {
  182.    case "ctlFont":
  183.       document.execCommand('FontName', false, el[el.selectedIndex].value);
  184.       break;
  185.    case "ctlSize":
  186.       document.execCommand('FontSize', false, el[el.selectedIndex].value);
  187.       break;
  188.    case "ctlStyle":
  189.       document.execCommand('FormatBlock', false, el[el.selectedIndex].text);
  190.       break;
  191.    }
  192.    doc.focus();
  193.    reset();
  194. }
  195. // pickColor(): called when the text or fill color icons are clicked.  Displays
  196. // the color chooser control.  The color setting is completed by the event
  197. // handler of this control (see richedit.html)
  198. function pickColor(fg)
  199. {
  200.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  201.    checkRange();
  202.    var el = window.event.srcElement;
  203.    if (el && el.nodeName == "IMG") {
  204.       setState(el, true);
  205.    }
  206.    color.style.top = window.event.clientY + 10;
  207.    color.style.left = window.event.clientX - 100;
  208.    color.style.display = 'block';
  209.    color._fg = fg;
  210. }
  211. // setColor(): called from the fore/back color selection dialog event handler
  212. // to set/reset the fore/background color.
  213. function setColor(name, data)
  214. {
  215.    color.style.display = 'none';
  216.    checkRange();
  217.    if (!data) {
  218.       removeFormat(document.selection.createRange(), color._fg);
  219.    } else {
  220.       document.execCommand(color._fg, false, data);
  221.    }
  222.    setState(btnText, false);
  223.    setState(btnFill, false);
  224.    doc.focus();
  225. }
  226. // removeFormat(): Called to remove specific formats from the selected text.
  227. // The 'removeFormat' command removes all formatting.  The principle behind
  228. // this routine is to have a list of the possible formats the selection may
  229. // have, check the selection for the current formats, ignoreing the one we
  230. // want to use, then remove all formatting and then re-apply all but the
  231. // one we wanted to remove.
  232. function removeFormat(r, name)
  233. {
  234.    var cmd = [ "Bold", "Italic", "Underline", "Strikethrough", "FontName", "FontSize", "ForeColor", "BackColor" ];
  235.    var on = new Array(cmd.length);
  236.    for (var i = 0; i < cmd.length; i++) {
  237.       on[i] = name == cmd[i] ? null : r.queryCommandValue(cmd[i]);
  238.    }
  239.    r.execCommand('RemoveFormat');
  240.    for (var i = 0; i < cmd.length; i++) {
  241.       if (on[i]) r.execCommand(cmd[i], false, on[i]);
  242.    }
  243. }
  244. // setValue(): called from reset() to make a select list show the current font
  245. // or style attributes
  246. function selValue(el, str)
  247. {
  248.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  249.    for (var i = 0; i < el.length; i++) {
  250.       if ((!el[i].value && el[i].text == str) || el[i].value == str) {
  251.          el.selectedIndex = i;
  252.          return;
  253.       }
  254.    }
  255.    el.selectedIndex = 0;
  256. }
  257. // setState(): called from reset() to make a button represent the state
  258. // of the current text.  Pressed is on, unpressed is off.
  259. function setState(el, on)
  260. {
  261.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  262.    if (!el.disabled) {
  263.       if (on) {
  264.          el.defaultState = el.className = "down";
  265.       } else {
  266.          el.defaultState = el.className = null;
  267.       }
  268.    }
  269. }
  270. // getStyle(): called to obtain the class or type of formatting applied to an element,
  271. // This is used by reset() to set the state of the toolbar to indicate the class of
  272. // the current element.
  273. function getStyle() {
  274.    var style = document.queryCommandValue('FormatBlock');
  275.    if (style == "Normal") {
  276.       doc.focus();
  277.       var rng = document.selection.createRange();
  278.       if (typeof(rng.parentElement) != "undefined") {
  279.          var el = rng.parentElement();
  280.          var tag = el.nodeName.toUpperCase();
  281.          var str = el.className.toLowerCase();
  282.          if (!(tag == "DIV" && el.id == "doc" && str == "textedit")) {
  283.             if (tag == "SPAN") {
  284.                style = "." + str;
  285.             } else if (str == "") {
  286.                style = tag;
  287.             } else {
  288.                style = tag + "." + str;
  289.             }
  290.          }
  291.          return style;
  292.       }
  293.    }
  294.    return style;
  295. }
  296. // getfontface(): called to obtain the face attribute applied to a font tag,
  297. // This is used by reset() to set the state of the toolbar to indicate the class of
  298. // the current element.
  299. function getfontface()
  300. {
  301. var family = document.selection.createRange(); //create text range
  302. // don't get font face for image or table
  303. if (document.selection.type == 'Control') {
  304.    return;
  305. }
  306. var el = family.parentElement(); //get parent element
  307. var tag = el.nodeName.toUpperCase(); //convert tag element to upper case
  308. if (typeof(el.parentElement) != "undefined" && tag == "FONT") { //only do function if tag is font - this is for greater execution speed
  309. var elface = el.getAttribute('FACE'); //get the font tags FACE attribute
  310. return elface; //return the value of the face attribute to the reset() function
  311. }
  312. }
  313. // markSelectedElement(): called by onClick and onKeyup events
  314. // on the contectEditable area
  315. function markSelectedElement() {
  316.    RichEditor.selectedImage = null;
  317.    var r = document.selection.createRange();
  318.    if (document.selection.type != 'Text') {
  319.       if (r.length == 1) {
  320.          if (r.item(0).tagName == "IMG") {
  321.             RichEditor.selectedImage = r.item(0);
  322.          }
  323.       }
  324.    }
  325. }
  326. // reset(): called from all over the place to make the toolbar
  327. // represent the current text. If el specified, it was called from
  328. // hover(off)
  329. function reset(el)
  330. {
  331.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  332.    if (!el) color.style.display = 'none';
  333.    if (!el || el == ctlStyle)         selValue(ctlStyle, getStyle());
  334.    if (!el || el == ctlFont)         selValue(ctlFont, getfontface());
  335.    if (!el || el == ctlSize)         selValue(ctlSize, document.queryCommandValue('FontSize'));
  336.    if (!el || el == btnBold)         setState(btnBold, document.queryCommandValue('Bold'));
  337.    if (!el || el == btnItalic)         setState(btnItalic,   document.queryCommandValue('Italic'));
  338.    if (!el || el == btnUnderline)      setState(btnUnderline, document.queryCommandValue('Underline'));
  339.    if (!el || el == btnStrikethrough)   setState(btnStrikethrough, document.queryCommandValue('Strikethrough'));
  340.    if (!el || el == btnLeftJustify)   setState(btnLeftJustify, document.queryCommandValue('JustifyLeft'));
  341.    if (!el || el == btnCenter)         setState(btnCenter,   document.queryCommandValue('JustifyCenter'));
  342.    if (!el || el == btnRightJustify)   setState(btnRightJustify, document.queryCommandValue('JustifyRight'));
  343.    if (!el || el == btnFullJustify)   setState(btnFullJustify, document.queryCommandValue('JustifyFull'));
  344.    if (!el || el == btnNumList)      setState(btnNumList, document.queryCommandValue('InsertOrderedList'));
  345.    if (!el || el == btnBulList)      setState(btnBulList, document.queryCommandValue('InsertUnorderedList'));
  346. }
  347. // hover(): Handles mouse hovering over toolbar buttons
  348. function hover(on)
  349. {
  350.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  351.    var el = window.event.srcElement;
  352.    if (el && !el.disabled && el.nodeName == "IMG" && el.className != "spacer") {
  353.       if (on) {
  354.          el.className = "hover";
  355.       } else {
  356.          el.className = el.defaultState ? el.defaultState : null;
  357.       }
  358.    }
  359. }
  360. // hover(): Handles mouse clicks on toolbar buttons
  361. function press(on)
  362. {
  363.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  364.    var el = window.event.srcElement;
  365.    if (el && !el.disabled && el.nodeName == "IMG" && el.className != "spacer") {
  366.       if (on) {
  367.          el.className = "down";
  368.       } else {
  369.          el.className = el.className == "down" ? "hover" : el.defaultState ? el.defaultState : null;
  370.       }
  371.    }
  372. }
  373. // addTag(): This is the handler for the style dropdown.  This takes value
  374. // selected and interprates it and makes the necessary changes to the HTML to
  375. // apply this style.
  376. function addTag(obj) {
  377.    if (!RichEditor.txtView) return;      // Disabled in View Source mode
  378.    // Determine the type of element we are dealing with.
  379.    // TYPE 0 IS NORMAL-TAG, 1 IS CLASS, 2 IS SUBCLASS, 3 = Format Block command
  380.    var value = obj[obj.selectedIndex].value;
  381.    if (!value) {                        // Format Block
  382.       sel(obj);
  383.       return;
  384.    }
  385.    var type = 0;                        // TAG
  386.    if (value.indexOf(".") == 0) {            // .className
  387.       type = 1;
  388.    } else if (value.indexOf(".") != -1) {      // TAG.className
  389.       type = 2;
  390.    }
  391.    doc.focus();
  392.    // Pick up the highlighted text
  393.    var r = document.selection.createRange();
  394.    r.select();
  395.    var s = r.htmlText;
  396.    // If we have some selected text, then ignore silly selections
  397.    if (s == " " || s == "&nbsp;") {
  398.       return;
  399.    }
  400.    // How we apply formatting is based upon the type of formitting being
  401.    // done.
  402.    switch(type)
  403.    {
  404.    case 1:
  405.       // class: Wrap the selected text with a span of the specified
  406.       // class name
  407.       value = value.substring(1,value.length);
  408.       r.pasteHTML("<span class="+value+">" + r.htmlText + "</span>")
  409.       break;
  410.    case 2:
  411.       // subclass: split the value into tag + class
  412.       value = value.split(".");
  413.       r.pasteHTML('<' + value[0] + ' class="' + value[1] +'">'
  414.                + r.htmlText
  415.                + '</' + value[0] + '>'
  416.             );
  417.       break;
  418.    default:
  419.       // TAG: wrap up the highlighted text with the specified tag
  420.       r.pasteHTML("<"+value+">"+r.htmlText+"</"+value+">")
  421.       break;
  422.    }
  423. }
  424. // initStyleDropdown(): This takes the passed styleList and generates the style
  425. // dropdown list box from it.
  426. function initStyleDropdown(styleList) {
  427.    // Build the option list for the styles dropdown from the passed styles
  428.    for (var i = 0; i < styleList.length; i++) {
  429.       var oOption = document.createElement("OPTION");
  430.       if (styleList[i][0]) oOption.value = styleList[i][0];
  431.       oOption.text = styleList[i][1];
  432.       oOption.style.backgroundColor = 'white';
  433.       document.all.ctlStyle.add(oOption);
  434.    }
  435. }
  436. // applyOptions(): This takes the passed options string and actions them.
  437. // Called during the init process.
  438. function applyOptions(str)
  439. {
  440.    var options = str.split(";");
  441.    for (var i = 0; i < options.length; i++) {
  442.       var eq = options[i].indexOf('=');
  443.       var on = eq == -1 ? true : "yes;true;1".indexOf(options[i].substr(eq+1).toLowerCase()) != -1;
  444.       var name = eq == -1 ? options[i] : options[i].substr(0,eq);
  445.       var el = document.all("feature" + name);
  446.       if (el) {
  447.          el.runtimeStyle.display = (on ? 'inline' : 'none'); 
  448.       } else {
  449.          if (!RichEditor.aOptions) RichEditor.aOptions = new Array;
  450.          RichEditor.aOptions[name] = on;
  451.       }
  452.    }
  453. }
  454. // getOption(): Get the value for a previously set option or return undefined if
  455. // the option is not set.
  456. function getOption(name)
  457. {
  458.    if (RichEditor.aOptions) return RichEditor.aOptions[name];
  459.    return;   // Undefined
  460. // Handle drag and drop events into the editor window.  Until we
  461. // work out how to handle these better (which requires co-operation
  462. // from the code being dragged from as far as I can tell) we simply
  463. // disable the functionality.
  464. function handleDrag(n)
  465. {
  466.    // if drag and drop is disabled, then cancel the dragdrop
  467.    // events
  468.    if (!getOption("dragdrop"))
  469.    {
  470.       switch(n) {
  471.       case 0:   // ondragenter
  472.          window.event.dataTransfer.dropEffect = "none";
  473.          break;
  474.       }
  475.       // Cancel the event
  476.       window.event.returnValue = false;
  477.    }
  478. }