2010-05-22 3 views
8

Je montre du texte stylé simple comme html dans un UIWebView sur iPhone. C'est fondamentalement une série de paragraphes avec la phrase occasionnelle forte ou accentuée. Au moment de l'exécution, j'ai besoin d'appliquer des styles à des plages de texte.appliquer le style à la gamme de texte avec javascript dans uiwebview

Il existe quelques scénarios similaires, dont l'un est la mise en évidence des résultats de recherche. Si l'utilisateur a cherché "quelque chose", je voudrais changer la couleur d'arrière-plan derrière les occurrences du mot, puis restaurer plus tard l'arrière-plan d'origine.

Est-il possible d'appliquer des styles à des plages de texte en utilisant javascript? Une partie clé de ceci est également capable d'annuler les styles.

Il semble y avoir deux chemins possibles à suivre. L'une serait de modifier du code html dans Objective-C et de le passer par javascript comme le nouveau innerHTML de certains conteneurs. L'autre serait d'utiliser javascript pour manipuler directement les nœuds DOM.

Je pourrais manipuler html, mais cela semble ennuyeux en Objective-C donc je préférerais manipuler le DOM si c'est une approche raisonnable. Je ne suis pas familier avec javascript et DOM donc je ne sais pas si c'est une approche raisonnable. J'ai écrit des routines pour traduire entre des plages de texte et des plages de nœuds avec des décalages. Donc, si je commence par la plage de texte 100-200 et que cela commence dans un paragraphe et se termine dans un troisième, je peux obtenir les nœuds de texte et les décalages dans les nœuds qui représentent la plage de texte donnée. J'ai juste besoin d'un moyen de diviser un nœud de texte à un décalage dans le texte. Actuellement, j'applique juste des styles aux paragraphes contenant la gamme de texte.

Quelques notes:

  • javascript directement EURAutres cadres externes comme jquery.
  • les modifications n'ont jamais besoin d'être écrites sur le disque.
  • les modifications doivent être annulables ou au moins amovibles.
  • Les styles à appliquer existent déjà dans un fichier css.
  • il doit fonctionner dans l'iPhone 3.0 et en avant.
  • tous les fichiers source sont livrés avec l'application.
  • veuillez être verbeux.

Merci pour vos suggestions.

Répondre

19

Je pense que vous demandez beaucoup pour obtenir une solution complète pour cela, mais cela semblait intéressant, donc je l'ai implémenté. Les travaux suivants dans les navigateurs WebKit récents, y compris Safari sur iPhone exécutant OS 3.0. Il utilise la méthode non-standard mais pratique intersectsNode de Range, qui existe dans WebKit mais qui a été supprimée de Firefox dans la version 3.0, de sorte qu'elle ne fonctionne pas dans les versions récentes de Firefox mais pourrait être faite de manière triviale.

Les éléments suivants entoureront chaque noeud de texte sélectionné avec un élément <span> avec une classe de "someclass" et également une classe unique pour permettre une annulation facile. applyClassToSelection renvoie cette classe unique; passez cette classe dans removeSpansWithClass pour retirer les travées.

MISE À JOUR: Correction d'un problème lorsque la sélection est entièrement contenu dans un nœud texte unique

MISE À JOUR 2: maintenant testé et fonctionne dans l'iPhone OS 3.0 en cours d'exécution.

MISE À JOUR 3: Ajout de la fonction rangeIntersectsNode pour ajouter la prise en charge de Firefox 3.0 et versions ultérieures. Ce code devrait maintenant fonctionner dans Firefox 1.0+, Safari 3.1+, Google Chrome, Opera 9.6+ et éventuellement d'autres (non testés jusqu'à présent). Cela ne fonctionne pas du tout dans Internet Explorer et donnera des erreurs dans ce navigateur. Je prévois de travailler sur une version d'IE bientôt.

<script type="text/javascript"> 
    var nextId = 0; 

    var rangeIntersectsNode = (typeof window.Range != "undefined" 
      && Range.prototype.intersectsNode) ? 

     function(range, node) { 
      return range.intersectsNode(node); 
     } : 

     function(range, node) { 
      var nodeRange = node.ownerDocument.createRange(); 
      try { 
       nodeRange.selectNode(node); 
      } catch (e) { 
       nodeRange.selectNodeContents(node); 
      } 

      return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 && 
       range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1; 
     }; 

    function applyClassToSelection(cssClass) { 
     var uniqueCssClass = "selection_" + (++nextId); 
     var sel = window.getSelection(); 
     if (sel.rangeCount < 1) { 
      return; 
     } 
     var range = sel.getRangeAt(0); 
     var startNode = range.startContainer, endNode = range.endContainer; 

     // Split the start and end container text nodes, if necessary 
     if (endNode.nodeType == 3) { 
      endNode.splitText(range.endOffset); 
      range.setEnd(endNode, endNode.length); 
     } 

     if (startNode.nodeType == 3) { 
      startNode = startNode.splitText(range.startOffset); 
      range.setStart(startNode, 0); 
     } 

     // Create an array of all the text nodes in the selection 
     // using a TreeWalker 
     var containerElement = range.commonAncestorContainer; 
     if (containerElement.nodeType != 1) { 
      containerElement = containerElement.parentNode; 
     } 

     var treeWalker = document.createTreeWalker(
      containerElement, 
      NodeFilter.SHOW_TEXT, 
      // Note that Range.intersectsNode is non-standard but 
      // implemented in WebKit 
      function(node) { 
       return rangeIntersectsNode(range, node) ? 
        NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; 
      }, 
      false 
     ); 

     var selectedTextNodes = []; 
     while (treeWalker.nextNode()) { 
      selectedTextNodes.push(treeWalker.currentNode); 
     } 

     var textNode, span; 

     // Place each text node within range inside a <span> 
     // element with the desired class 
     for (var i = 0, len = selectedTextNodes.length; i < len; ++i) { 
      textNode = selectedTextNodes[i]; 
      span = document.createElement("span"); 
      span.className = cssClass + " " + uniqueCssClass; 
      textNode.parentNode.insertBefore(span, textNode); 
      span.appendChild(textNode); 
     } 

     return uniqueCssClass; 
    } 

    function removeSpansWithClass(cssClass) { 
     var spans = document.body.getElementsByClassName(cssClass), 
      span, parentNode; 

     // Convert spans to an array to prevent live updating of 
     // the list as we remove the spans 
     spans = Array.prototype.slice.call(spans, 0); 

     for (var i = 0, len = spans.length; i < len; ++i) { 
      span = spans[i]; 
      parentNode = span.parentNode; 
      parentNode.insertBefore(span.firstChild, span); 
      parentNode.removeChild(span); 

      // Glue any adjacent text nodes back together 
      parentNode.normalize(); 
     } 
    } 

    var c; 
</script> 

<input type="button" onclick="c = applyClassToSelection('someclass')" 
    value="Add class"> 
<input type="button" onclick="removeSpansWithClass(c)" 
    value="Remove class"> 
+0

Merci. C'est plus que ce que j'espérais. – drawnonward

+0

Peut-être mettre cela sur github, donc nous pouvons suivre au moins. – Mark

+1

Je travaille sur une bibliothèque de sélection et de sélection de plusieurs navigateurs qui inclura une version améliorée de cette bibliothèque. Pas beaucoup de progrès pour le moment, mais j'ai créé un projet de code Google: http://code.google.com/p/rangy/ –

Questions connexes