Javascript getSelection
I got another question related to the getSelection.
I'm working on a WYSIWYG text editor and I'm using custom functions to apply HTML effect to the selected text. So far things are working great.
Currently the way it works is whatever you highlight, it replaces the entire body of text in the textarea with what you selected. I am trying to figure out how to make it apply the desired effects without removing everything else in the body.
Thoughts?
function button(type) {
var txt = '';
editor_body = document.getElementById('editor').contentWindow.document;
if (editor_body.getSelection()) {
txt = editor_body.getSelection();
} else if (editor_body.selection.createRange()) {
txt = editor_body.selection.createRange();
} else return;
switch (type) {
case "bold": txt = '<b>' + txt + '</b>'; break
case "italic": txt = '<i>' + txt + '</i>'; break
case "underline": txt = '<u>' + txt + '</u>'; break
case "strike": txt = '<strike>' + txt + '</strike>'; break
case "supscript": txt = '<sup>' + txt + '</sup>'; break
case "subscript": txt = '<sub>' + txt + '</sub>'; break
case "alignleft": txt = '<div style="text-align: left;">' + txt + '</div>'; break
case "aligncenter": txt = '<div style="text-align: center;">' + txt + '</div>'; break
case "alignright": txt = '<div style="text-align: right;">' + txt + '</div>'; break
case "alignjustify": txt = '<div style="text-align: justify;">' + txt + '</div>'; break
case "ol": txt = '<ol>' + txt + '</ol>'; break
case "ul": txt = '<ul>' + txt + '</ul>'; break
case "insertlink": insertlink = prompt("Enter image URL:", "http://"); if ((insertlink != null) && (insertlink != "")) {txt = '<a href="' + insertlink + '">' + txt + '</a>'; } break
case "insertimage": insertimage = prompt("Enter image URL:", "http://"); if ((insertimage != null) && (insertimage != "")) {txt = '<img src="' + insertimage + '">'; } break
case 'insertvideo': insertvideo = prompt("Enter video URL:", "http://"); if ((insertvideo != null) && (insertvideo != "")) {txt = '<object type="application/x-shockwave-flash" data="' + insertvideo + '" width="640" height="385"><param name="movie" value="' + insertvideo + '" /></object>';} break
}
editor_body.body.innerHTML = txt;
document.getElementById('editor').contentWindow.focus();
}
function Start() {
var e;
document.getElementById('editor').contentWindow.docu开发者_运维百科ment.designMode = "on";
try {
document.getElementById('editor').contentWindow.document.execCommand("styleWithCSS", false, "false");
} catch (e) {
}
try {
document.getElementById('editor').contentWindow.document.execCommand("undo", false, null);
editormode = "true";
} catch (e) {
editormode = "false";
}
if (document.addEventListener) {
document.addEventListener("mouseup", dismissmenu, true);
document.getElementById("editor").contentWindow.document.addEventListener("mouseup", dismissmenu, true);
document.addEventListener("keypress", dismissmenu, true);
document.getElementById("editor").contentWindow.document.addEventListener("keypress", dismissmenu, true);
} else if (document.attachEvent) {
document.attachEvent("mouseup", dismissmenu, true);
document.getElementById("editor").contentWindow.document.attachEvent("mouseup", dismissmenu, true);
document.attachEvent("keypress", dismissmenu, true);
document.getElementById("editor").contentWindow.document.attachEvent("keypress", dismissmenu, true);
}
}
Several thoughts:
- Replacing the
innerHTML
of the iframe's body each time you execute one of your custom commands is a mistake, for several reasons. One is that it will be slow, particularly for a large amount of content. Another is that you'll lose the selection. Another is that you'll lose any event handlers you may have added to elements within the editable content. - Most of the functions you want to apply have built-in commands in the browser, accessible via the
execCommand
method of the iframe'sdocument
. Why not use them? They'll be faster than your equivalents, preserve the selection and will be added to the undo stack. window.prompt
is generally unusable since IE7, which disabled it by default, giving the user an option to enable it (if you're lucky).
UPDATE
Instead of using innerHTML
, you should operate on the DOM nodes contained within the selection. You could use my own library called Rangy ( http://code.google.com/p.rangy ), which abstracts the differences between IE and other browsers' selection and range objects and also adds some convenient methods for dealing within the nodes of a selection. Here's a very simplistic example of how you could implement a bold command (in practice, you'd want to check each whether the range is already completely bold and check each text node for boldness before surrounding it):
var iframe = document.getElementById("your_iframe");
var iframeDoc = iframe.contentDocument, iframeWin;
if (iframeDoc) {
iframeWin = iframeDoc.defaultView;
} else {
iframeWin = iframe.contentWindow;
iframeDoc = iframeWin.document;
}
var sel = rangy.getSelection(iframeWin);
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
// If the range has either boundary within a text node, split that text node
// so that we can work with the part that is selected
range.splitBoundaries();
// Get an array of all text nodes within the
var textNodes = range.getNodes([3]); // [3] specifies the types of node required
// Surround each text node
for (var i = 0, len = textNodes.length, el, n; i < len; ++i) {
n = textNodes[i];
el = iframeDoc.createElement("b");
n.parentNode.insertBefore(el, n);
el.appendChild(n);
}
}
精彩评论