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