开发者

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:

  1. 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.
  2. Most of the functions you want to apply have built-in commands in the browser, accessible via the execCommand method of the iframe's document. Why not use them? They'll be faster than your equivalents, preserve the selection and will be added to the undo stack.
  3. 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);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜