2010-03-19 12 views
10

Estoy trabajando en un editor de texto enriquecido como aplicación web, básicamente un editor XML escrito en javascript.Use javascript para ampliar un Rango DOM para cubrir nodos parcialmente seleccionados

Mi código de JavaScript debe envolver una selección de nodos desde el contenedor contentEditable div. Estoy usando los métodos descritos en MDC. Pero ya que necesito para sincronizar los contenedores div de contenido a XML DOM me gustaría evitar selecciones parciales como se describe en w3c ranges:

<BODY><H1>Title</H1><P>Blah xyz.</P></BODY

............^----------------^............

Esta selección se inicia dentro de H1 y termina en el interior P, Me gustaría que incluya H1, P por completo.

¿Existe alguna manera fácil de ampliar por completo la selección para cubrir por completo a niños parcialmente seleccionados? Básicamente quiero usar range.surroundContents() sin ejecutar una excepción.

(El código no tiene que trabajar con la ópera/IE)

Respuesta

8

En cuanto a la documentación del MDC, consigo hacer algo como esto:

Selection.prototype.coverAll = function() { 
    var ranges = []; 
    for(var i=0; i<this.rangeCount; i++) { 
     var range = this.getRangeAt(i); 
     while(range.startContainer.nodeType == 3 
       || range.startContainer.childNodes.length == 1) 
      range.setStartBefore(range.startContainer); 
     while(range.endContainer.nodeType == 3 
       || range.endContainer.childNodes.length == 1) 
      range.setEndAfter(range.endContainer); 
     ranges.push(range); 
    } 
    this.removeAllRanges(); 
    for(var i=0; i<ranges.length; i++) { 
     this.addRange(ranges[i]); 
    } 
    return; 
}; 

Puedes probarlo aquí: http://jsfiddle.net/GFuX6/9/

edición: Actualizado a tener la pantalla del navegador correctamente la selección aumentada. Hace lo que usted pidió, incluso si la selección contiene varios rangos (con Ctrl).

hacer varios nodos parciales negrita, aquí es una solución:

Selection.prototype.boldinize = function() { 
    this.coverAll(); 
    for(var i=0; i<this.rangeCount; i++) { 
     var range = this.getRangeAt(i); 
     var parent = range.commonAncestorContainer; 
     var b = document.createElement('b'); 
     if(parent.nodeType == 3) { 
      range.surroundContents(b); 
     } else { 
      var content = range.extractContents(); 
      b.appendChild(content); 
      range.insertNode(b); 
     } 
    } 
}; 
+0

De hecho, pero creo que esta es la ruta correcta. Trataré de crear una selección personalizada del original que tenga estas propiedades. –

+0

Extenderé mi pregunta para que quede más clara. También actualicé el ejemplo en http://jsfiddle.net/GFuX6/5/ –

+0

Seleccione un texto, presione escape y el texto se convierte en negrita. Hay una larga línea en el violín: 'window.getSelection(). GetRangeAt (0) .surroundContents (tag);' El violín actual amplía los límites de los nodos de texto, pero no puedo encontrar una manera de cubrir parcialmente nodos incluidos –

0

Si quiere decir que desea incluir el H1 etiquetas y P (es decir, el marcado válido), no se preocupe. Lo obtienes gratis Si quiere decir que desea incluir todo el contenido dentro de la selección (parcial), debe acceder al objeto Selección. Lea sobre esto en Quirksmode's introduction to Range.

+0

Como dice el artículo quirksmode, navegadores arreglar el HTML 'no válido': "los navegadores añadir la cantidad mínima de HTML para hacer que el rango válido". Prefiero no tener selecciones no válidas para empezar;) –

0

Gracias a Alsciende finalmente me ocurrió con el código en http://jsfiddle.net/wesUV/21/. Este método no es tan codicioso como el otro. Después de coverAll(), surroundContents() siempre debería funcionar.

Selection.prototype.coverAll = function() { 
    var ranges = []; 
    for(var i=0; i<this.rangeCount; i++) { 
    var range = this.getRangeAt(i); 
    var ancestor = range.commonAncestorContainer; 
    if (ancestor.nodeType == 1) {    
     if (range.startContainer.parentNode != ancestor && this.containsNode(range.startContainer.parentNode, true)) { 
      range.setStartBefore(range.startContainer.parentNode); 
     } 
     if (range.endContainer.parentNode != ancestor && this.containsNode(range.endContainer.parentNode, true)) { 
       range.setEndAfter(range.endContainer.parentNode); 
     } 
    } 
    ranges.push(range); 
    } 
    this.removeAllRanges(); 
    for(var i=0; i<ranges.length; i++) { 
    this.addRange(ranges[i]); 
    } 
    return; 
}; 

Y la función boldinize:

Selection.prototype.boldinize = function() { 
    for(var i=0; i<this.rangeCount; i++) {   
    var range = this.getRangeAt(i); 
    var b = document.createElement('b'); 
    try { 
     range.surroundContents(b); 
    } catch (e) { 
     alert(e); 
    } 
    } 
}; 
Cuestiones relacionadas