2

I've tried a few different techniques now but I can't get one to work reliably across all content. What I need to do is have all instances of the business name include a trademark symbol:

ie -> DinosaurCakes becomes DinosaurCakes<sup>&tm;</sup> or Would you like some DinosaurCakes? becomes Would you like some DinosaurCakes<sup>&tm;</sup>

The javascript version I was trying to do was looping through the page on load and replacing the string with the function I found here-> http://james.padolsey.com/javascript/find-and-replace-text-with-javascript/ But it isn;t digging in to all of the child nodes for some reason and so some versions of the string don;t get replaced.

I then tried to do it in Drupal via hook_page_alter with:

function dinosaur_page_alter(&$page) {
    // attempting to add the DinosaurCake (tm) marks using page_alter
    // find all '#markup' and then scan for terms
    function display_array(&$your_array){
      foreach ($your_array as $key => &$value){
        if (is_array($value)){
          display_array($value);
        }
        elseif (is_string($value) && $key === "#markup") {
          $value = str_replace(array('DinosaurCakes"), array('DinosaurCakes<sup class="reg">&tm;</sup>'), $value);
        }
      }
    }
    display_array($page);
}

However, using this method, it doesn't work on headings and does apply to title attributes and pathnames which of course breaks everything.

Any ideas on the best way to attack this?

2
  • Do you need specifically to change it when it is being rendered? I'm thinking of a solution that would replace these words in content once, instead of calling that code every time the page is served, or this is not the case for you? Sep 1 '12 at 1:46
  • No it doesn't need to happen on render - that's just where I was trying to do it so that all the views and blocks had finished rendering. Sep 1 '12 at 6:53
4

You can use "String Overrides" (http://drupal.org/project/stringoverrides) module to accomplish what you want to do and it will work even if JavaScript is disabled and the changes will be cached as well by the Drupal cache.

Note: This will work with content pass by the t() function, if you have the word hard coded on the theme or module it will not work. Also it is CaSe SeSiTiVe.

2
  • Does String Overrides pass HTML or does it get escaped?
    – mpdonadio
    Sep 2 '12 at 0:59
  • I can't get String overrides to work on html regions, or parts of strings. It only appears to work if you use the entire string, or send the term you want to change through t() every time you want to use it (drupal.org/node/1569620) Sep 5 '12 at 12:17
0

I ran into this exact problem recently on a Drupal 6 project. Drupal 7 could be handled the same way.

In my case, I needed to put the ® Registered Trademark on Drupal output H1 Page Titles wrapped in <sup></sup> tags. I understand html is not allowed in titles, but my specific solution is not subject to problems introduced by not escaping html, and it still does escape user-provided content intially:

The underlying issue is that because all page titles go through drupal_set_title(), they also get passed through filter_xss. Understanding this, I am comfortable with the cleanliness of my page titles. The user actually types the (R) symbol (not html &reg). Then, in the theme, I re-scan the text and string-replace the cleaned HTML in the part that outputs page title:

In page.tpl.php, the <h1></h1> page title bit:

<?php print $title; ?>

becomes:

<?php print strstr($title, "®") ? str_replace("®", "<sup>®</sup>", $title) : $title; ?>

Did a check for strstr() for efficiency: If it doesn't exist, don't bother processing str_replace. In your case, if all page titles have it, you might just do a straight up str_replace and take it home in one fell swoop.

A bit better and more generic solution would do it regex and for all registered and copyright symbols.

0

I ended up falling back to a javascript solution. It provided the most reliable solution across all content on the page. There are still a few weird quirks with it not working in some specific html scenarios, but it works well enough.

Snippet in case anyone else would like to use a similar solution - it's not elegant, but it works:

/* Find and add in registered trademark and trademark symbols where needed. */

//get ALL the text nodes - adapted from http://stackoverflow.com/questions/9178174/find-all-text-nodes
function recurse(element) {
    if (element.childNodes.length > 0) {
      //there are additional children, send them back through for exploration
        for (var i = 0; i < element.childNodes.length; i++) {
            recurse(element.childNodes[i]);
        }
    }

    if (element.nodeType == 3 && /\S/.test(element.nodeValue)) {
      // we have a text node, send it off for processing
      doReplacements(element, element.parentElement);
    }
}

var html = document.getElementsByTagName('html')[0];
recurse(html);

function doReplacements(element, parent) {

    var html = element.data;
    //ensure we only process each chunk of text once.
    if (element.nextSibling){
        if (element.nextSibling.nodeName.toLowerCase() === 'sup'){
        //do nothing, this one has been done.
        //console.log('bailing');
        return;
        }
    }
    // Do the following replacements:
    //add reg marks
    html = element.data.replace(/\bPuppyDawg\b|\bFeisty(\s)Clown\b|\bRabid(\s)Dinosaurs\b/gi, "$&<sup>&reg;</sup>");
    //add trademarks
    html = html.replace(/\bMad(\s)Cat\b/g, '$&<sup>&trade;</sup>');

    //now rebuild the html with the new tags in place (via http://james.padolsey.com/javascript/find-and-replace-text-with-javascript/)
    //note, since I started this, I have found this: https://github.com/padolsey/findAndReplaceDOMText which may work if we need to start over...
    var frag = (function () {
        var wrap = document.createElement('div'),
            frag = document.createDocumentFragment();

        wrap.innerHTML = html;
        while (wrap.firstChild) {
            frag.appendChild(wrap.firstChild);
        }
        return frag;
    })();

    parent.insertBefore(frag, element);
    parent.removeChild(element);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.