views:

384

answers:

2

Hi,

So I figured out that the replace function, that finds all single-letter "words" (prepositions and conjunction, etc.) and replace the space after them with a   to prevent leaving these characters at the end of line, should be something like

myString.replace(/\s\w(?=\s)/,"$1 ")

Now how do I apply it to all text on a webpage? I am looking for some universal solution, a simple function which I put into <head> without need to change anything else in the webpage.

Thank you very much.

+1  A: 
function replaceText(node)
{
  var current = node.nodeValue;
  var replaced = current.replace(searchpattern, replacepattern);
  node.nodeValue = replaced;
}
function traverse(node)
{
  var children = node.childNodes;
  var childLen = children.length;
  for(var i = 0; i < childLen; i++)
  {
    var child = children.item(i);
    if(child.nodeType == 3)//or if(child instanceof Text)
      replaceText(child);
    else
      traverse(child);
  }
}
function replaceAll()
{
  traverse(document.body);
}

Call replaceAll() from body's onload.

<body onload="replaceAll()">
Amarghosh
thank you! maybe better to put it all including replaceAll() call into $(document).ready(function() { // do stuff when DOM is ready });instead of using <body onload="replaceAll()"> ?
Josef Richter
I don't know jQuery, but if that's how you do `onload` in jquery, ya, you can do that.
Amarghosh
so this solution works very well and I finally found the correct regex is current.replace(/(\s\w)\s/g,"$1\xA0"); thank you
Josef Richter
+2  A: 

you could try something like this:

$('body').contents().filter(function(){ 
     return this.nodeType == 3;
}).each(function(){
   this.nodeValue = this.nodeValue.replace(/\s\w(?=\s)/,"$1&nbsp;");
});

Basically we grab the body element and get its contents - the contents() method will grab text nodes as well as elements which is what we want. Then we filter on nodeType reducing the set to only text nodes. then we do the regex replace.

prodigitalson
this looks even better :-) exactly a kind of "hack" I was looking for, especially this filter by nodeType - didn't know that. thanks
Josef Richter
Please note i had my nodeType wrong.. it was `1` when it should have been `3` - i have corrected my answer.
prodigitalson
thanks. it still doesn't seem to work for me. the this.nodeValue is void as I can see in js console. any idea?
Josef Richter
before or after the replace? try breaking it out like `var newText = this.nodeValue.replace(/\s\w(?=\s)/,"$1 "); this.nodeValue = newText;` other than tha try alerting the `nodeName` and make sure its `TEXT`.
prodigitalson
Will this really allow you to insert HTML as the OP wants to do? Since you're only changing the nodeValue of a text node, won't it just insert the text " " rather than actually inserting a HTML entity?
Martin
before the replace (thus after it as well). it returns 'nodeType = 3' but 'nodeValue' is void.
Josef Richter
I've tried the other solution below by Amarghosh and it actually works (although I am not exactly sure why). but as Martin suggests, it really does replace it with text "$1 " instead of inserting HTML entity :-(
Josef Richter
@MArtin: Good Point. I didnt even think of that!
prodigitalson
@Martin To insert non-breaking space to a text node, you can use `"\xA0"` instead of `" "`
Amarghosh
I finally realized the difference between this solution and the other by Amarghosh - the loop needs to dig deeper in the DOM tree. this way it seems it doesn't replace anything if I have e.g. <div><span>whatever string</span></div> because it looks for text within <div> tag but not within the nested <span>. so we probably need separate function to be called recursively. anyone has some nice way to do it?
Josef Richter