2010-08-21 5 views
1

J'ai une autre question concernant getSelection.Javascript getSelection

Je travaille sur un éditeur de texte WYSIWYG et j'utilise des fonctions personnalisées pour appliquer un effet HTML au texte sélectionné. Jusqu'à présent, les choses fonctionnent bien.

Actuellement, la façon dont cela fonctionne est ce que vous mettez en surbrillance, elle remplace l'ensemble du texte dans la zone de texte avec ce que vous avez sélectionné. J'essaie de comprendre comment faire pour appliquer les effets désirés sans enlever tout le reste du corps.

Pensées?

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.document.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); 
    } 
} 

Répondre

1

Plusieurs pensées:

  1. Remise en place du innerHTML du corps de l'iframe chaque fois que vous exécutez une de vos commandes personnalisées est une erreur, pour plusieurs raisons. L'un est que ce sera lent, en particulier pour une grande quantité de contenu. Un autre est que vous perdrez la sélection. Une autre est que vous perdrez tous les gestionnaires d'événements que vous avez ajoutés aux éléments du contenu modifiable.
  2. La plupart des fonctions que vous souhaitez appliquer ont des commandes intégrées dans le navigateur, accessibles via la méthode execCommand du document de l'iframe. Pourquoi ne pas les utiliser? Ils seront plus rapides que vos équivalents, conserveront la sélection et seront ajoutés à la pile d'annulation.
  3. window.prompt est généralement inutilisable depuis IE7, qui l'a désactivé par défaut, en donnant à l'utilisateur une option pour l'activer (si vous êtes chanceux).

MISE À JOUR

Au lieu d'utiliser innerHTML, vous devez utiliser sur les noeuds DOM contenus dans la sélection. Vous pouvez utiliser ma propre bibliothèque appelée Rangy (http://code.google.com/p.rangy), qui résume les différences entre IE et les autres objets de sélection et d'étendue des navigateurs et ajoute également des méthodes pratiques pour gérer les nœuds d'une sélection. Voici un exemple très simpliste de la façon dont vous pourriez mettre en œuvre une commande audacieuse (en pratique, vous voulez vérifier chaque si la plage est déjà complètement gras et vérifier chaque nœud de texte pour l'audace avant qui l'entoure):

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

Merci pour répondre Tim. J'utilisais l'execCommand au début, mais les commandes sont limitées, vous avez un contrôle très limité sur la sortie HTML, et il est plus difficile de basculer entre le texte enrichi et le bbcode. Je sais que innerHTML n'est pas la bonne chose à faire, c'est pourquoi la question est de savoir ce que je fais au lieu de innerHTML pour remplacer la sélection uniquement. J'ai trouvé des solutions via Google, mais aucune d'entre elles ne semblait fonctionner comme elles le souhaitaient. – Cory