]> code.citadel.org Git - citadel.git/blob - webcit/static/richtext.js
*** empty log message ***
[citadel.git] / webcit / static / richtext.js
1 // Cross-Browser Rich Text Editor
2 // http://www.kevinroth.com/rte/demo.htm
3 // Written by Kevin Roth (kevin@NOSPAMkevinroth.com - remove NOSPAM)
4 // Visit the support forums at http://www.kevinroth.com/forums/index.php?c=2
5
6 //init variables
7 var isRichText = false;
8 var rng;
9 var currentRTE;
10 var allRTEs = "";
11
12 var isIE;
13 var isGecko;
14 var isSafari;
15 var isKonqueror;
16
17 var imagesPath;
18 var includesPath;
19 var cssFile;
20
21
22 function initRTE(imgPath, incPath, css) {
23         //set browser vars
24         var ua = navigator.userAgent.toLowerCase();
25         isIE = ((ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1) && (ua.indexOf("webtv") == -1)); 
26         isGecko = (ua.indexOf("gecko") != -1);
27         isSafari = (ua.indexOf("safari") != -1);
28         isKonqueror = (ua.indexOf("konqueror") != -1);
29         
30         //check to see if designMode mode is available
31         if (document.getElementById && document.designMode && !isSafari && !isKonqueror) {
32                 isRichText = true;
33         }
34         
35         if (!isIE) document.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT | Event.MOUSEDOWN | Event.MOUSEUP);
36         document.onmouseover = raiseButton;
37         document.onmouseout  = normalButton;
38         document.onmousedown = lowerButton;
39         document.onmouseup   = raiseButton;
40         
41         //set paths vars
42         imagesPath = imgPath;
43         includesPath = incPath;
44         cssFile = css;
45         
46         if (isRichText) document.writeln('<style type="text/css">@import "' + includesPath + 'rte.css";</style>');
47         
48         //for testing standard textarea, uncomment the following line
49         //isRichText = false;
50 }
51
52 function writeRichText(rte, html, width, height, buttons, readOnly) {
53         if (isRichText) {
54                 if (allRTEs.length > 0) allRTEs += ";";
55                 allRTEs += rte;
56                 writeRTE(rte, html, width, height, buttons, readOnly);
57         } else {
58                 writeDefault(rte, html, width, height, buttons, readOnly);
59         }
60 }
61
62 function writeDefault(rte, html, width, height, buttons, readOnly) {
63         if (!readOnly) {
64                 document.writeln('<textarea name="' + rte + '" id="' + rte + '" style="width: ' + width + 'px; height: ' + height + 'px;">' + html + '</textarea>');
65         } else {
66                 document.writeln('<textarea name="' + rte + '" id="' + rte + '" style="width: ' + width + 'px; height: ' + height + 'px;" readonly>' + html + '</textarea>');
67         }
68 }
69
70 function raiseButton(e) {
71         if (isIE) {
72                 var el = window.event.srcElement;
73         } else {
74                 var el= e.target;
75         }
76         
77         className = el.className;
78         if (className == 'rteImage' || className == 'rteImageLowered') {
79                 el.className = 'rteImageRaised';
80         }
81 }
82
83 function normalButton(e) {
84         if (isIE) {
85                 var el = window.event.srcElement;
86         } else {
87                 var el= e.target;
88         }
89         
90         className = el.className;
91         if (className == 'rteImageRaised' || className == 'rteImageLowered') {
92                 el.className = 'rteImage';
93         }
94 }
95
96 function lowerButton(e) {
97         if (isIE) {
98                 var el = window.event.srcElement;
99         } else {
100                 var el= e.target;
101         }
102         
103         className = el.className;
104         if (className == 'rteImage' || className == 'rteImageRaised') {
105                 el.className = 'rteImageLowered';
106         }
107 }
108
109 function writeRTE(rte, html, width, height, buttons, readOnly) {
110         if (readOnly) buttons = false;
111         
112         //adjust minimum table widths
113         if (isIE) {
114                 if (buttons && (width < 600)) width = 600;
115                 var tablewidth = width;
116         } else {
117                 if (buttons && (width < 500)) width = 500;
118                 var tablewidth = width + 4;
119         }
120         
121         if (buttons == true) {
122                 document.writeln('<table class="rteBack" cellpadding=2 cellspacing=0 id="Buttons1_' + rte + '" width="' + tablewidth + '">');
123                 document.writeln('      <tr>');
124                 document.writeln('              <td>');
125                 document.writeln('                      <select id="formatblock_' + rte + '" onchange="Select(\'' + rte + '\', this.id);">');
126                 document.writeln('                              <option value="">[Style]</option>');
127                 document.writeln('                              <option value="<p>">Paragraph</option>');
128                 document.writeln('                              <option value="<h1>">Heading 1 <h1></option>');
129                 document.writeln('                              <option value="<h2>">Heading 2 <h2></option>');
130                 document.writeln('                              <option value="<h3>">Heading 3 <h3></option>');
131                 document.writeln('                              <option value="<h4>">Heading 4 <h4></option>');
132                 document.writeln('                              <option value="<h5>">Heading 5 <h5></option>');
133                 document.writeln('                              <option value="<h6>">Heading 6 <h6></option>');
134                 document.writeln('                              <option value="<address>">Address <ADDR></option>');
135                 document.writeln('                              <option value="<pre>">Formatted <pre></option>');
136                 document.writeln('                      </select>');
137                 document.writeln('              </td>');
138                 document.writeln('              <td>');
139                 document.writeln('                      <select id="fontname_' + rte + '" onchange="Select(\'' + rte + '\', this.id)">');
140                 document.writeln('                              <option value="Font" selected>[Font]</option>');
141                 document.writeln('                              <option value="Arial, Helvetica, sans-serif">Arial</option>');
142                 document.writeln('                              <option value="Courier New, Courier, mono">Courier New</option>');
143                 document.writeln('                              <option value="Times New Roman, Times, serif">Times New Roman</option>');
144                 document.writeln('                              <option value="Verdana, Arial, Helvetica, sans-serif">Verdana</option>');
145                 document.writeln('                      </select>');
146                 document.writeln('              </td>');
147                 document.writeln('              <td>');
148                 document.writeln('                      <select unselectable="on" id="fontsize_' + rte + '" onchange="Select(\'' + rte + '\', this.id);">');
149                 document.writeln('                              <option value="Size">[Size]</option>');
150                 document.writeln('                              <option value="1">1</option>');
151                 document.writeln('                              <option value="2">2</option>');
152                 document.writeln('                              <option value="3">3</option>');
153                 document.writeln('                              <option value="4">4</option>');
154                 document.writeln('                              <option value="5">5</option>');
155                 document.writeln('                              <option value="6">6</option>');
156                 document.writeln('                              <option value="7">7</option>');
157                 document.writeln('                      </select>');
158                 document.writeln('              </td>');
159                 document.writeln('              <td width="100%">');
160                 document.writeln('              </td>');
161                 document.writeln('      </tr>');
162                 document.writeln('</table>');
163                 document.writeln('<table class="rteBack" cellpadding="0" cellspacing="0" id="Buttons2_' + rte + '" width="' + tablewidth + '">');
164                 document.writeln('      <tr>');
165                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'bold.gif" width="25" height="24" alt="Bold" title="Bold" onClick="FormatText(\'' + rte + '\', \'bold\', \'\')"></td>');
166                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'italic.gif" width="25" height="24" alt="Italic" title="Italic" onClick="FormatText(\'' + rte + '\', \'italic\', \'\')"></td>');
167                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'underline.gif" width="25" height="24" alt="Underline" title="Underline" onClick="FormatText(\'' + rte + '\', \'underline\', \'\')"></td>');
168                 document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
169                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'left_just.gif" width="25" height="24" alt="Align Left" title="Align Left" onClick="FormatText(\'' + rte + '\', \'justifyleft\', \'\')"></td>');
170                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'centre.gif" width="25" height="24" alt="Center" title="Center" onClick="FormatText(\'' + rte + '\', \'justifycenter\', \'\')"></td>');
171                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'right_just.gif" width="25" height="24" alt="Align Right" title="Align Right" onClick="FormatText(\'' + rte + '\', \'justifyright\', \'\')"></td>');
172                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'justifyfull.gif" width="25" height="24" alt="Justify Full" title="Justify Full" onclick="FormatText(\'' + rte + '\', \'justifyfull\', \'\')"></td>');
173                 document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
174                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'hr.gif" width="25" height="24" alt="Horizontal Rule" title="Horizontal Rule" onClick="FormatText(\'' + rte + '\', \'inserthorizontalrule\', \'\')"></td>');
175                 document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
176                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'numbered_list.gif" width="25" height="24" alt="Ordered List" title="Ordered List" onClick="FormatText(\'' + rte + '\', \'insertorderedlist\', \'\')"></td>');
177                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'list.gif" width="25" height="24" alt="Unordered List" title="Unordered List" onClick="FormatText(\'' + rte + '\', \'insertunorderedlist\', \'\')"></td>');
178                 document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
179                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'outdent.gif" width="25" height="24" alt="Outdent" title="Outdent" onClick="FormatText(\'' + rte + '\', \'outdent\', \'\')"></td>');
180                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'indent.gif" width="25" height="24" alt="Indent" title="Indent" onClick="FormatText(\'' + rte + '\', \'indent\', \'\')"></td>');
181                 document.writeln('              <td><div id="forecolor_' + rte + '"><img class="rteImage" src="' + imagesPath + 'textcolor.gif" width="25" height="24" alt="Text Color" title="Text Color" onClick="FormatText(\'' + rte + '\', \'forecolor\', \'\')"></div></td>');
182                 document.writeln('              <td><div id="hilitecolor_' + rte + '"><img class="rteImage" src="' + imagesPath + 'bgcolor.gif" width="25" height="24" alt="Background Color" title="Background Color" onClick="FormatText(\'' + rte + '\', \'hilitecolor\', \'\')"></div></td>');
183                 document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
184                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'hyperlink.gif" width="25" height="24" alt="Insert Link" title="Insert Link" onClick="FormatText(\'' + rte + '\', \'createlink\')"></td>');
185                 document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'image.gif" width="25" height="24" alt="Add Image" title="Add Image" onClick="AddImage(\'' + rte + '\')"></td>');
186                 if (isIE) {
187                         document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'spellcheck.gif" width="25" height="24" alt="Spell Check" title="Spell Check" onClick="checkspell()"></td>');
188                 }
189 //              document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
190 //              document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'cut.gif" width="25" height="24" alt="Cut" title="Cut" onClick="FormatText(\'' + rte + '\', \'cut\')"></td>');
191 //              document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'copy.gif" width="25" height="24" alt="Copy" title="Copy" onClick="FormatText(\'' + rte + '\', \'copy\')"></td>');
192 //              document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'paste.gif" width="25" height="24" alt="Paste" title="Paste" onClick="FormatText(\'' + rte + '\', \'paste\')"></td>');
193 //              document.writeln('              <td><img class="rteVertSep" src="' + imagesPath + 'blackdot.gif" width="1" height="20" border="0" alt=""></td>');
194 //              document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'undo.gif" width="25" height="24" alt="Undo" title="Undo" onClick="FormatText(\'' + rte + '\', \'undo\')"></td>');
195 //              document.writeln('              <td><img class="rteImage" src="' + imagesPath + 'redo.gif" width="25" height="24" alt="Redo" title="Redo" onClick="FormatText(\'' + rte + '\', \'redo\')"></td>');
196                 document.writeln('              <td width="100%"></td>');
197                 document.writeln('      </tr>');
198                 document.writeln('</table>');
199         }
200         document.writeln('<iframe id="' + rte + '" name="' + rte + '" width="' + width + 'px" height="' + height + 'px" src="' + includesPath + 'blank.htm"></iframe>');
201         if (!readOnly) document.writeln('<br /><input type="checkbox" id="chkSrc' + rte + '" onclick="toggleHTMLSrc(\'' + rte + '\');" />&nbsp;View Source');
202         document.writeln('<iframe width="154" height="104" id="cp' + rte + '" src="' + includesPath + 'palette.htm" marginwidth="0" marginheight="0" scrolling="no" style="visibility:hidden; display: none; position: absolute;"></iframe>');
203         document.writeln('<input type="hidden" id="hdn' + rte + '" name="' + rte + '" value="">');
204         document.getElementById('hdn' + rte).value = html;
205         enableDesignMode(rte, html, readOnly);
206 }
207
208 function enableDesignMode(rte, html, readOnly) {
209         var frameHtml = "<html id=\"" + rte + "\">\n";
210         frameHtml += "<head>\n";
211         //to reference your stylesheet, set href property below to your stylesheet path and uncomment
212         if (cssFile.length > 0) {
213                 frameHtml += "<link media=\"all\" type=\"text/css\" href=\"" + cssFile + "\" rel=\"stylesheet\">\n";
214         } else {
215                 frameHtml += "<style>\n";
216                 frameHtml += "body {\n";
217                 frameHtml += "  background: #FFFFFF;\n";
218                 frameHtml += "  margin: 0px;\n";
219                 frameHtml += "  padding: 0px;\n";
220                 frameHtml += "}\n";
221                 frameHtml += "</style>\n";
222         }
223         frameHtml += "</head>\n";
224         frameHtml += "<body>\n";
225         frameHtml += html + "\n";
226         frameHtml += "</body>\n";
227         frameHtml += "</html>";
228         
229         if (document.all) {
230                 var oRTE = frames[rte].document;
231                 oRTE.open();
232                 oRTE.write(frameHtml);
233                 oRTE.close();
234                 if (!readOnly) oRTE.designMode = "On";
235         } else {
236                 try {
237                         if (!readOnly) document.getElementById(rte).contentDocument.designMode = "on";
238                         try {
239                                 var oRTE = document.getElementById(rte).contentWindow.document;
240                                 oRTE.open();
241                                 oRTE.write(frameHtml);
242                                 oRTE.close();
243                                 if (isGecko && !readOnly) {
244                                         //attach a keyboard handler for gecko browsers to make keyboard shortcuts work
245                                         oRTE.addEventListener("keypress", kb_handler, true);
246                                 }
247                         } catch (e) {
248                                 alert("Error preloading content.");
249                         }
250                 } catch (e) {
251                         //gecko may take some time to enable design mode.
252                         //Keep looping until able to set.
253                         if (isGecko) {
254                                 setTimeout("enableDesignMode('" + rte + "', '" + html + "', " + readOnly + ");", 10);
255                         } else {
256                                 return false;
257                         }
258                 }
259         }
260         //contributed by TotalJSNoob and archv1le (thanks guys!)
261         //if the following gets uncommented, indenting and list items will not function correctly
262 //      if (isIE) {
263 //              var hack = function () {rteKeyPress(document.getElementById(rte).contentWindow);};
264 //              var oRTE = document.getElementById(rte).contentWindow;
265 //              oRTE.document.onkeypress = hack;
266 //      }
267 }
268
269 function updateRTEs() {
270         var vRTEs = allRTEs.split(";");
271         for (var i = 0; i < vRTEs.length; i++) {
272                 updateRTE(vRTEs[i]);
273         }
274 }
275
276 function updateRTE(rte) {
277         if (!isRichText) return;
278         
279         //set message value
280         var oHdnMessage = document.getElementById('hdn' + rte);
281         var oRTE = document.getElementById(rte);
282         var readOnly = false;
283         
284         //check for readOnly mode
285         if (document.all) {
286                 if (frames[rte].document.designMode != "On") readOnly = true;
287         } else {
288                 if (document.getElementById(rte).contentDocument.designMode != "on") readOnly = true;
289         }
290         
291         if (isRichText && !readOnly) {
292                 //if viewing source, switch back to design view
293                 if (document.getElementById("chkSrc" + rte).checked) {
294                         document.getElementById("chkSrc" + rte).checked = false;
295                         toggleHTMLSrc(rte);
296                 }
297                 
298                 if (oHdnMessage.value == null) oHdnMessage.value = "";
299                 if (document.all) {
300                         oHdnMessage.value = frames[rte].document.body.innerHTML;
301                 } else {
302                         oHdnMessage.value = oRTE.contentWindow.document.body.innerHTML;
303                 }
304                 
305                 //if there is no content (other than formatting) set value to nothing
306                 if (stripHTML(oHdnMessage.value.replace("&nbsp;", " ")) == "" 
307                         && oHdnMessage.value.toLowerCase().search("<hr") == -1
308                         && oHdnMessage.value.toLowerCase().search("<img") == -1) oHdnMessage.value = "";
309                 //fix for gecko
310                 if (escape(oHdnMessage.value) == "%3Cbr%3E%0D%0A%0D%0A%0D%0A") oHdnMessage.value = "";
311         }
312 }
313
314 function toggleHTMLSrc(rte) {
315         //contributed by Bob Hutzel (thanks Bob!)
316         var oRTE;
317         if (document.all) {
318                 oRTE = frames[rte].document;
319         } else {
320                 oRTE = document.getElementById(rte).contentWindow.document;
321         }
322         
323         if (document.getElementById("chkSrc" + rte).checked) {
324                 document.getElementById("Buttons1_" + rte).style.visibility = "hidden";
325                 document.getElementById("Buttons2_" + rte).style.visibility = "hidden";
326                 if (document.all) {
327                         oRTE.body.innerText = oRTE.body.innerHTML;
328                 } else {
329                         var htmlSrc = oRTE.createTextNode(oRTE.body.innerHTML);
330                         oRTE.body.innerHTML = "";
331                         oRTE.body.appendChild(htmlSrc);
332                 }
333         } else {
334                 document.getElementById("Buttons1_" + rte).style.visibility = "visible";
335                 document.getElementById("Buttons2_" + rte).style.visibility = "visible";
336                 if (document.all) {
337                         //fix for IE
338                         var output = escape(oRTE.body.innerText);
339                         output = output.replace("%3CP%3E%0D%0A%3CHR%3E", "%3CHR%3E");
340                         output = output.replace("%3CHR%3E%0D%0A%3C/P%3E", "%3CHR%3E");
341                         
342                         oRTE.body.innerHTML = unescape(output);
343                 } else {
344                         var htmlSrc = oRTE.body.ownerDocument.createRange();
345                         htmlSrc.selectNodeContents(oRTE.body);
346                         oRTE.body.innerHTML = htmlSrc.toString();
347                 }
348         }
349 }
350
351 //Function to format text in the text box
352 function FormatText(rte, command, option) {
353         var oRTE;
354         if (document.all) {
355                 oRTE = frames[rte];
356                 
357                 //get current selected range
358                 var selection = oRTE.document.selection; 
359                 if (selection != null) {
360                         rng = selection.createRange();
361                 }
362         } else {
363                 oRTE = document.getElementById(rte).contentWindow;
364                 
365                 //get currently selected range
366                 var selection = oRTE.getSelection();
367                 rng = selection.getRangeAt(selection.rangeCount - 1).cloneRange();
368         }
369         
370         try {
371                 if ((command == "forecolor") || (command == "hilitecolor")) {
372                         //save current values
373                         parent.command = command;
374                         currentRTE = rte;
375                         
376                         //position and show color palette
377                         buttonElement = document.getElementById(command + '_' + rte);
378                         // Ernst de Moor: Fix the amount of digging parents up, in case the RTE editor itself is displayed in a div.
379                         document.getElementById('cp' + rte).style.left = getOffsetLeft(buttonElement, 4) + "px";
380                         document.getElementById('cp' + rte).style.top = (getOffsetTop(buttonElement, 4) + buttonElement.offsetHeight + 4) + "px";
381                         if (document.getElementById('cp' + rte).style.visibility == "hidden") {
382                                 document.getElementById('cp' + rte).style.visibility = "visible";
383                                 document.getElementById('cp' + rte).style.display = "inline";
384                         } else {
385                                 document.getElementById('cp' + rte).style.visibility = "hidden";
386                                 document.getElementById('cp' + rte).style.display = "none";
387                         }
388                 } else if (command == "createlink") {
389                         var szURL = prompt("Enter a URL:", "");
390                         try {
391                                 //ignore error for blank urls
392                                 oRTE.document.execCommand("Unlink", false, null);
393                                 oRTE.document.execCommand("CreateLink", false, szURL);
394                         } catch (e) {
395                                 //do nothing
396                         }
397                 } else {
398                         oRTE.focus();
399                         oRTE.document.execCommand(command, false, option);
400                         oRTE.focus();
401                 }
402         } catch (e) {
403                 alert(e);
404         }
405 }
406
407 //Function to set color
408 function setColor(color) {
409         var rte = currentRTE;
410         var oRTE;
411         if (document.all) {
412                 oRTE = frames[rte];
413         } else {
414                 oRTE = document.getElementById(rte).contentWindow;
415         }
416         
417         var parentCommand = parent.command;
418         if (document.all) {
419                 //retrieve selected range
420                 var sel = oRTE.document.selection; 
421                 if (parentCommand == "hilitecolor") parentCommand = "backcolor";
422                 if (sel != null) {
423                         var newRng = sel.createRange();
424                         newRng = rng;
425                         newRng.select();
426                 }
427         }
428         oRTE.focus();
429         oRTE.document.execCommand(parentCommand, false, color);
430         oRTE.focus();
431         document.getElementById('cp' + rte).style.visibility = "hidden";
432         document.getElementById('cp' + rte).style.display = "none";
433 }
434
435 //Function to add image
436 function AddImage(rte) {
437         var oRTE;
438         if (document.all) {
439                 oRTE = frames[rte];
440                 
441                 //get current selected range
442                 var selection = oRTE.document.selection; 
443                 if (selection != null) {
444                         rng = selection.createRange();
445                 }
446         } else {
447                 oRTE = document.getElementById(rte).contentWindow;
448                 
449                 //get currently selected range
450                 var selection = oRTE.getSelection();
451                 rng = selection.getRangeAt(selection.rangeCount - 1).cloneRange();
452         }
453         
454         imagePath = prompt('Enter Image URL:', 'http://');                              
455         if ((imagePath != null) && (imagePath != "")) {
456                 oRTE.focus();
457                 oRTE.document.execCommand('InsertImage', false, imagePath);
458                 oRTE.focus();
459         }
460 }
461
462 //function to perform spell check
463 function checkspell() {
464         try {
465                 var tmpis = new ActiveXObject("ieSpell.ieSpellExtension");
466                 tmpis.CheckAllLinkedDocuments(document);
467         }
468         catch(exception) {
469                 if(exception.number==-2146827859) {
470                         if (confirm("ieSpell not detected.  Click Ok to go to download page."))
471                                 window.open("http://www.iespell.com/download.php","DownLoad");
472                 } else {
473                         alert("Error Loading ieSpell: Exception " + exception.number);
474                 }
475         }
476 }
477
478 // Ernst de Moor: Fix the amount of digging parents up, in case the RTE editor itself is displayed in a div.
479 function getOffsetTop(elm, parents_up) {
480         var mOffsetTop = elm.offsetTop;
481         var mOffsetParent = elm.offsetParent;
482         
483         if(!parents_up) {
484                 parents_up = 10000; // arbitrary big number
485         }
486         while(parents_up>0 && mOffsetParent) {
487                 mOffsetTop += mOffsetParent.offsetTop;
488                 mOffsetParent = mOffsetParent.offsetParent;
489                 parents_up--;
490         }
491         
492         return mOffsetTop;
493 }
494
495 // Ernst de Moor: Fix the amount of digging parents up, in case the RTE editor itself is displayed in a div.
496 function getOffsetLeft(elm, parents_up) {
497         var mOffsetLeft = elm.offsetLeft;
498         var mOffsetParent = elm.offsetParent;
499         
500         if(!parents_up) {
501                 parents_up = 10000; // arbitrary big number
502         }
503         while(parents_up>0 && mOffsetParent) {
504                 mOffsetLeft += mOffsetParent.offsetLeft;
505                 mOffsetParent = mOffsetParent.offsetParent;
506                 parents_up--;
507         }
508         
509         return mOffsetLeft;
510 }
511
512 function Select(rte, selectname) {
513         var oRTE;
514         if (document.all) {
515                 oRTE = frames[rte];
516                 
517                 //get current selected range
518                 var selection = oRTE.document.selection; 
519                 if (selection != null) {
520                         rng = selection.createRange();
521                 }
522         } else {
523                 oRTE = document.getElementById(rte).contentWindow;
524                 
525                 //get currently selected range
526                 var selection = oRTE.getSelection();
527                 rng = selection.getRangeAt(selection.rangeCount - 1).cloneRange();
528         }
529         
530         var idx = document.getElementById(selectname).selectedIndex;
531         // First one is always a label
532         if (idx != 0) {
533                 var selected = document.getElementById(selectname).options[idx].value;
534                 var cmd = selectname.replace('_' + rte, '');
535                 oRTE.focus();
536                 oRTE.document.execCommand(cmd, false, selected);
537                 oRTE.focus();
538                 document.getElementById(selectname).selectedIndex = 0;
539         }
540 }
541
542 function kb_handler(evt) {
543         var rte = evt.target.id;
544         
545         //contributed by Anti Veeranna (thanks Anti!)
546         if (evt.ctrlKey) {
547                 var key = String.fromCharCode(evt.charCode).toLowerCase();
548                 var cmd = '';
549                 switch (key) {
550                         case 'b': cmd = "bold"; break;
551                         case 'i': cmd = "italic"; break;
552                         case 'u': cmd = "underline"; break;
553                 };
554
555                 if (cmd) {
556                         FormatText(rte, cmd, true);
557                         //evt.target.ownerDocument.execCommand(cmd, false, true);
558                         // stop the event bubble
559                         evt.preventDefault();
560                         evt.stopPropagation();
561                 }
562         }
563 }
564
565 function docChanged (evt) {
566         alert('changed');
567 }
568
569 function stripHTML(oldString) {
570         var newString = oldString.replace(/(<([^>]+)>)/ig,"");
571         
572         //replace carriage returns and line feeds
573    newString = newString.replace(/\r\n/g," ");
574    newString = newString.replace(/\n/g," ");
575    newString = newString.replace(/\r/g," ");
576         
577         //trim string
578         newString = trim(newString);
579         
580         return newString;
581 }
582
583 function trim(inputString) {
584    // Removes leading and trailing spaces from the passed string. Also removes
585    // consecutive spaces and replaces it with one space. If something besides
586    // a string is passed in (null, custom object, etc.) then return the input.
587    if (typeof inputString != "string") return inputString;
588    var retValue = inputString;
589    var ch = retValue.substring(0, 1);
590         
591    while (ch == " ") { // Check for spaces at the beginning of the string
592       retValue = retValue.substring(1, retValue.length);
593       ch = retValue.substring(0, 1);
594    }
595    ch = retValue.substring(retValue.length-1, retValue.length);
596         
597    while (ch == " ") { // Check for spaces at the end of the string
598       retValue = retValue.substring(0, retValue.length-1);
599       ch = retValue.substring(retValue.length-1, retValue.length);
600    }
601         
602         // Note that there are two spaces in the string - look for multiple spaces within the string
603    while (retValue.indexOf("  ") != -1) {
604                 // Again, there are two spaces in each of the strings
605       retValue = retValue.substring(0, retValue.indexOf("  ")) + retValue.substring(retValue.indexOf("  ")+1, retValue.length);
606    }
607    return retValue; // Return the trimmed string back to the user
608 }
609
610 //contributed by archv1le (thanks archv1le!)
611 function rteKeyPress(window) {
612         if (window.event.keyCode == 13) {
613                 var range = window.document.selection.createRange();
614                 var obj = range.parentElement();
615                 if (obj.tagName != "LI") {
616                         window.event.returnValue = false; // cancel Standard-event
617                         range.pasteHTML('<br>');
618                         range.select(); // re-sets the cursor to the right position
619                 }
620         }
621 }