JS: Obtenez un tableau de tous les nœuds sélectionnés dans le contenuEditable div

Bonjour, j'ai travaillé avec contentEditable depuis un moment maintenant et je pense que j'ai une très bonne gestion. Une chose qui m'échappe est la façon d'obtenir un ensemble de références à tous les nœuds qui sont partiellement ou entièrement dans la sélection de l'utilisateur. Quelqu'un at-il eu une idée?

Voici un élément à partir de:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> function getSelectedNodes(){ var sel = window.getSelection(); try{var frag=sel.getRangeAt(0).cloneContents()}catch(e){return(false);} var tempspan = document.createElement("span"); tempspan.appendChild(frag); var selnodes = Array() //<<- how do I fill this array?? var output = '' for(i in selnodes){ output += "A "+selnodes[i].tagName+" was found\n" //do something cool with each element here... } return(output) } </script> </head> <body contentEditable="true" onkeypress="return(keypress(event))"> <div>This <strong>div</strong> is <em>content</em> <span class='red'>editable</span> and has a couple of <em><strong>child nodes</strong></em> within it</div> <br /> <br /> <a href="#" onmouseover="alert(getSelectedNodes())">hover here</a> </body> </html> 

Voici une version qui vous donne les noeuds sélectionnés et partiellement sélectionnés plutôt que les clones. Alternativement, vous pouvez utiliser ma bibliothèque Rangy , qui a une méthode getNodes() de ses objets Range et fonctionne dans IE <9.

 function nextNode(node) { if (node.hasChildNodes()) { return node.firstChild; } else { while (node && !node.nextSibling) { node = node.parentNode; } if (!node) { return null; } return node.nextSibling; } } function getRangeSelectedNodes(range) { var node = range.startContainer; var endNode = range.endContainer; // Special case for a range that is contained within a single node if (node == endNode) { return [node]; } // Iterate nodes until we hit the end container var rangeNodes = []; while (node && node != endNode) { rangeNodes.push( node = nextNode(node) ); } // Add partially selected nodes at the start of the range node = range.startContainer; while (node && node != range.commonAncestorContainer) { rangeNodes.unshift(node); node = node.parentNode; } return rangeNodes; } function getSelectedNodes() { if (window.getSelection) { var sel = window.getSelection(); if (!sel.isCollapsed) { return getRangeSelectedNodes(sel.getRangeAt(0)); } } return []; } 

Vous êtes si proche! Lorsque vous ajoutez le Document Fragment à l'élément de span temporaire, vous les avez transformés en un groupe gérable, accessible via le tableau childNodes .

  var selnodes = tempspan.childNodes; 

De plus, vous vous for(i in selnodes) à des problèmes avec la boucle for(i in selnodes) , qui renverrait les éléments dans le tableau, PLUS la propriété length et la propriété __proto__ et toutes les autres propriétés que l'objet peut avoir.

Vous ne devriez vraiment utiliser ces types de boucles lors de la bouclage des propriétés d'un objet, puis toujours avec if (obj.hasOwnProperty[i]) pour filtrer les propriétés héritées du prototype.

Lors de la mise en boucle des tableaux, utilisez:

  for(var i=0,u=selnodes.length;i<u;i++) 

Enfin, une fois que vous chargez ce tableau, vous devrez vérifier chaque élément pour voir s'il s'agit d'un nœud DOM ou d' un nœud Texte avant de pouvoir le gérer. Nous pouvons le faire en vérifiant s'il prend en charge la propriété tagName .

  if (typeof selnodes[i].tagName !== 'undefined') 

Voici tout:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> function getSelectedNodes(){ var sel = window.getSelection(); try{var frag=sel.getRangeAt(0).cloneContents()}catch(e){return(false);} var tempspan = document.createElement("span"); tempspan.appendChild(frag); console.log(tempspan); window.selnodes = tempspan.childNodes; var output = '' for(var i=0, u=selnodes.length;i<u;i++){ if (typeof selnodes[i].tagName !== 'undefined'){ output += "A "+selnodes[i].tagName+" was found\n" } else output += "Some text was found: '"+selnodes[i].textContent+"'\n"; //do something cool with each element here... } return(output) } </script> </head> <body contentEditable="true" onkeypress="return(keypress(event))"> <div>This <strong>div</strong> is <em>content</em> <span class='red'>editable</span> and has a couple of <em><strong>child nodes</strong></em> within it</div> <br /> <br /> <a href="#" onmouseover="alert(getSelectedNodes())">hover here</a> </body> </html> 

Le code ci-dessous est un exemple pour résoudre votre problème, ci-dessous code retourner tous les nœuds sélectionnés dans la gamme

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>payam jabbari</title> <script src="http://code.jquery.com/jquery-2.0.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function(){ var startNode = $('p.first').contents().get(0); var endNode = $('span.second').contents().get(0); var range = document.createRange(); range.setStart(startNode, 0); range.setEnd(endNode, 5); var selection = document.getSelection(); selection.addRange(range); // below code return all nodes in selection range. this code work in all browser var nodes = range.cloneContents().querySelectorAll("*"); for(var i=0;i<nodes.length;i++) { alert(nodes[i].innerHTML); } }); </script> </head> <body> <div> <p class="first">Even a week ago, the idea of a Russian military intervention in Ukraine seemed far-fetched if not totally alarmist. But the arrival of Russian troops in Crimea over the weekend has shown that he is not averse to reckless adventures, even ones that offer little gain. In the coming days and weeks</p> <ol> <li>China says military will respond to provocations.</li> <li >This Man Has Served 20 <span class="second"> Years—and May Die—in </span> Prison for Marijuana.</li> <li>At White House, Israel's Netanyahu pushes back against Obama diplomacy.</li> </ol> </div> </body> </html>