2017-03-07 1 views
3

Je suis en train de créer un outil surligneur qui fonctionne comme ceci:Remplacement HTML puis en ajoutant un fragment de document de nouveau dans le html

  • Un utilisateur sélectionne d'abord une plage de texte.
  • Ils puis cliquez sur l'un des boutons de couleur et l'arrière-plan du texte sélectionné est mis en évidence
  • Ensuite, ils choisissent une autre plage de texte ...
  • Maintenant, quand ils cliquent sur le bouton tout le code html est remplacé par le version en cache du html (pas de surbrillance)
  • Ensuite, le nouveau texte sélectionné qui a été mis en surbrillance est rajouté dans le nouveau fichier html.

De cette manière, une seule plage de texte peut être mise en surbrillance à la fois.

Problème:

J'ai du mal à comprendre le Range, Selection et Node API

En ce moment je ne peux pas ajouter le texte mis en évidence de nouveau dans le code html frais ... Je Je ne fais que l'ajouter au document.

Ce que j'ai jusqu'à présent:

https://jsfiddle.net/4mb39jd6/

(function(){ 

    var highlighter = { 

    /** 
    * 
    */ 
    init: function(){ 
     this.cacheDOM(); 
     this.bindEvents(); 
    }, 

    /** 
    * 
    */ 
    cacheDOM: function(){ 
     this.$html   = $('.content').html(); 
     this.$content  = $('.content'); 
     this.$highlighter = $('.highlighter'); 
    }, 

    /** 
    * 
    */ 
    bindEvents: function(){ 
     this.$highlighter.on('mousedown', this.highlightSelection.bind(this)); 
    }, 

    /** 
    * 
    */ 
    highlightSelection: function(e){ 

     var selection = window.getSelection();   // get selection 
     var text  = selection.toString();   // get selected text 
     var newNode = document.createElement('span'); // create node 

     newNode.style.backgroundColor = $(e.target).css('backgroundColor'); // set node properties 
     newNode.appendChild(document.createTextNode(text));     // append selection text to node 

     var range = selection.getRangeAt(0);  // 2 - get the selected range 
     range.deleteContents();     // delete the contents 
     range.insertNode(newNode);    // insert the new node with the replacement text 
     documentFragment = range.cloneContents(); // clone the node 

     this.$content.html(this.$html);    // refresh the content 
     document.body.appendChild(documentFragment); // add the new highlighted text 
    }, 
    }; 
    highlighter.init(); 

})(); 

Q:

Comment puis-je ajouter mon nœud en surbrillance ... qui ressemble à ceci <span style="background-color: rgb(255, 255, 131);">some random text</span> de nouveau dans un document html frais de sorte qu'il est dans la même position.

+0

Quel est le motif spécifique que vous souhaitez cloner tout le contenu ? Commenter les trois dernières lignes dans 'highlightSection' semble produire le comportement désiré ... https://jsfiddle.net/wxrxf6r1/ – user3297291

+0

Oui, la raison est que je veux seulement une section sélectionnée du texte à un moment donné. .. comme il est je peux mettre en évidence partout ... Je veux seulement être en mesure de sélectionner une gamme à la fois. –

+1

Avez-vous regardé [mark.js] (https://markjs.io/)? – dude

Répondre

1

Si l'objectif est d'avoir un seul point fort à la fois, je vais pour une approche moins compliquée que:

  • Lors de l'ajout d'un point fort,
  • vérifie le code HTML pour le point culminant précédent,
  • éradique une fois trouvé

Pour ce faire, marquer votre point fort <span> s avec un attribut ou une classe (ou mieux encore, stocker une référence):

newNode.classList.add("js-highlight"); 

Ajouter une méthode pour supprimer un tel élément:

clearHighlight: function() { 
    var selection = document.querySelector(".js-highlight"); 

    if (selection) { 
    selection.parentElement.replaceChild(
     document.createTextNode(selection.innerText), 
     selection 
    ); 
    } 
} 

Ensuite, avant de remplacer votre range avec l'élément en surbrillance, appelez clearHighlight.

Exemple: https://jsfiddle.net/2tqdLfb1/

Une alternative:

J'ai essayé aussi une autre approche qui respecte votre logique "HTML en cache", mais je l'ai trouvé excessivement complexe. Les bases de cette approche:

  • Vérifiez le chemin d'interrogation pour la parentElement de la sélection
  • Stocker l'indice de départ et l'indice de fin de la sélection
  • Remplacez le code HTML de la chaîne HTML en cache
  • Trouver l'élément parent nouvellement injectée de la sélection par l'intermédiaire de la requête de trajet stockées
  • scinder sa innerText pour 1, 2 ou 3 textNodes sur la base de l'index de début et de fin de sélection
  • Remplacer le textNode qui représente la sélection par votre point fort <span>

Un exemple qui montre comment vous pouvez stocker le chemin de requête pour votre ancêtre de gamme:

function getPathUpToSelector(selector, element, path) { 
    var parent = element.parentElement; 

    if (parent && !element.matches(selector)) { 
    var index = Array.from(parent.children).indexOf(element) + 1; 
    path.push("*:nth-child(" + index + ")"); 

    return getPathUpToSelector(selector, parent, path); 
    } 

    return [selector].concat(path).join(" > "); 
} 
+0

Merci! C'est fantastique. Je compliquais trop les choses et cela fonctionne bien. Le seul problème est maintenant que si je sélectionne du texte sur deux nœuds alors le balisage HTML est détruit ... J'ai commencé une nouvelle question ici: http://stackoverflow.com/questions/42656501/serializing-html-placing-span-elements -around-selected-text-while-préservant-e –