0

The following code checks if the selected tag has childnodes. If a child node is present , it loops till a child node is found. When there are no further child nodes found, it loops out i.e it reaches a text node causing the loop to end. The function is made recursive to run until no child node is found. The code runs as per above info, but when I try to match TEXT_NODE (console.log() outputs all text node), replace() is used to identify phone numbers using regex and replaced with hyperlink. The number gets detected and is enclosed with a hyperlink but it gets displayed twice i.e. number enclosed with hyperlink and only the number.Following is the code

            function DOMwalker(obj){
            var regex = /\+\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}/g;
             var y = "<a href=\"javascript:void(0);\">$&</a>";
            if(obj.hasChildNodes()){
                var child = obj.firstChild;

                while(child){
                    if(child.nodeType!==3)
                    {
                        DOMwalker(child);
                    }
                    if (child.nodeType=== 3) {
                            var text = child.nodeValue;
                             console.log(typeof text);                            
                            var regs = regex.exec(text);

                            match = text.replace(regex,y);

                            if(match){

                                var item = document.createElement('a');
                                item.setAttribute('href','javascript:void(0);');
                                var detect = document.createTextNode(match);
                                var x=item.appendChild(detect);
                                console.log(x);
                               child.parentNode.insertBefore(x,child);
                           }
                     }

                     child=child.nextSibling;
                }
            }
        };
        $(window).load(function(){
            var tag = document.querySelector(".gcdMainDiv div.contentDiv");

            DOMwalker(tag);
        });

Following are the screenshot of the output: enter image description here

Here the number gets printed twice instead of one with hyperlink which is been displayed(expected highlighted number with hyperlink) and second widout tags

Following is console.log of x enter image description here

I have already gone through this.

The solution provided below works well with FF. The problem arises when used in IE11. It throws Unknown runtime error and references the .innerHTML. I used the appenChild(),but the error couldn't be resolved.

Community
  • 1
  • 1
logan
  • 110
  • 11
  • Perhaps you just copied and pasted your code wrong, but it looks like you have an infinite loop in your while block. Should the while bracket end after `child=child.nextSibling`? – hotforfeature Sep 02 '14 at 13:58
  • Can you provide some samples of phone numbers that you are expecting to match, but are failing? – talemyn Sep 02 '14 at 14:06
  • @abmitchell: fixed it...forget to end main `if` loop =] – logan Sep 02 '14 at 14:16
  • @talemyn: +11 111 11-11111 +11 1111 3333333 – logan Sep 02 '14 at 14:16
  • I am not sure what it is you're trying to accomplish. Can you post the HTML of the page you're trying to manipulate, as well as what you what the end HTML result to be after your manipulation? – hotforfeature Sep 10 '14 at 14:18
  • @abmitchell: Its an Intranet page, so can't be posted here. Scenario is the intranet page contains telephone directory of employees. A selected employee name displays telephone numbers, I want the number to be highlighted as a hyperlink in the telephone directory.. – logan Sep 15 '14 at 07:54
  • @Adi Yes, I know what the scenario is, and my solution will work. I'm obviously missing something if it's still not good enough for you though. You don't have to post the entire page, but at least post a sample of HTML before/after code that you want to happen. I can't offer any more advice without seeing what you want, instead of just describing what you want – hotforfeature Sep 15 '14 at 13:36
  • @abmitchell : Updated the code with screenshots. If you need more better screenshots..I will update it =] – logan Sep 15 '14 at 14:30
  • 2 things, the number is displaying twice because I believe you're not removing the second one, only adding the hyperlink (instead of replacing). Second, I don't need screenshots, but HTML code. For security, you don't have to post your actual production code, but create an example of what the HTML code needs to be before and after – hotforfeature Sep 16 '14 at 13:41
  • @abmitchell : Problem solved! here is the [link](http://stackoverflow.com/a/26076269/2407348) – logan Sep 27 '14 at 15:35

2 Answers2

1

You've got a couple of problems with what you posted. First, if a child is not node type 3 and not a SCRIPT node, you re-call recursivetree() but you do not pass the child in. The function will just start over at the first div element and again, infinitely loop.

Second, you're calling replace() on the node itself, and not the node's innerHTML. You're trying to replace a node with a string, which just won't work, and I think you mean to replace any matching numbers within that node, rather than the entire node.

If you have <div>My number is +111-555-9999</div>, you only want to replace the number and not lose everything else.

Try this as a solution:

function recursivetree(obj){
   var regex = /\+\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}/g;
   var y = "<a href=\"javascript:;\">$&</a>";
   var obj = obj || document.getElementsByTagName('div')[0];
   if(obj.hasChildNodes()){
       var child = obj.firstChild;
       while(child){
           if(child.nodeType !== 3 && child.nodeName !== 'SCRIPT'){
                  //Recall recursivetree with the child 
                  recursivetree(child);
           }

           //A nodeType of 3, text nodes, sometimes do not have innerHTML to replace
           //Check if the child has innerHTML and replace with the regex
           if (child.innerHTML !== undefined) {
                child.innerHTML = child.innerHTML.replace(regex,y);
           }
           child=child.nextSibling;
       }
   }
}
recursivetree();

Fiddle: http://jsfiddle.net/q07n5mz7/

Honestly? If you're trying to loop through the entire page and replace all instances of numbers, just do a replace on the body.

var regex = /\+\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}/g;
var y = "<a href=\"javascript:;\">$&</a>";
var body = document.body;
body.innerHTML = body.innerHTML.replace(regex, y);

Fiddle: http://jsfiddle.net/hmdv7adu/

hotforfeature
  • 2,558
  • 1
  • 16
  • 24
  • I won't suggest to use .innerhtml.Read this [link](http://stackoverflow.com/a/2254917/2407348) Using ur above code simply vanishes the content on the web page. I am developing a plugin for IE to highlight phone numbers on a web page. So the original content on the net should not be disturbed. I hope you get what i mean to say. – logan Sep 02 '14 at 14:41
  • Using the .innerHTML property is just fine, the link you provided is just one person's opinion (who must people in the question disagree with). If you want to highlight phone numbers, you're going to have to modify the original content in some way. Be that through replacing it with a hyperlink as you're currently doing, or adding styling/classes to make it stand out. As a plugin (I assume one person using to make life easier), it's fine to modify content after you receive it from the server, as long as you maintain the data (the number in this case) – hotforfeature Sep 02 '14 at 16:04
  • Also what this and you are doing doesn't "vanish" content. It replaces the client's side view with something else. – hotforfeature Sep 02 '14 at 16:16
  • Using .innerhtml() vanishes the content which is to be replaced and if you go through .innerhtml() especially its flaws, you will get to know what i mean to say – logan Sep 03 '14 at 07:51
  • What "flaws" does it have that make it inapplicable in your circumstance? Also, you are wanting to modify the client's view, correct? – hotforfeature Sep 03 '14 at 13:31
  • no other content on the web page should be harmed (i.e nothing should be altered) only the number should be highlighted! In my case the content is getting complately altered which is not desired – logan Sep 04 '14 at 09:21
  • You DO realize that in order to highlight the number, you have to alter the CLIENT's view of it? The SERVER view is not modified. You cannot highlight the number without modifying the content (adding a class, hyperlink, etc) – hotforfeature Sep 04 '14 at 13:29
  • Yeaa what you saying is true! But I do not want to use `.innerHTML()` but use only replace function. You can refer [this](http://stackoverflow.com/a/11662117/2407348) but i want to develop in javascript – logan Sep 05 '14 at 08:35
  • I think you should do some more research. 1, jQuery is Javascript, and 2, the jQuery function `replaceWith()` uses `.innerHTML` in it. I'm afraid that sometimes the best solution is the simple one. I don't understand why you're so adamant against a valid and well supported property. I think you're going to have trouble finding a solution that doesn't use it. – hotforfeature Sep 05 '14 at 13:44
  • using `.innerhtml()` is not solving my problem. It doesn't modify the content but destroys the `DOM`. – logan Sep 08 '14 at 08:37
  • As told by you I tried the code. The number didn't got detected. Now can you suggest any other solution, if you know? – logan Sep 09 '14 at 08:34
  • Well the solution temporarily solved my problem. But the question arises when used in IE11(works perfect in FF). It throws the `unknown runtime error` at `.innerHTML` – logan Sep 09 '14 at 13:21
  • Took a like at this article, it may be related to your error. You may need to be careful of the HTML you're inserting into certain tags with IE: http://blog.rakeshpai.me/2007/02/ies-unknown-runtime-error-when-using.html – hotforfeature Sep 09 '14 at 13:31
  • tried to use the trick provided in the blog but I am getting stuck when it comes to modifying the DOM content. I am updating my question. – logan Sep 10 '14 at 13:51
0

Finally, I got the solution of my question. I referred to this answer which helped me to solve my query.

Here goes the code:

            function DOMwalker(obj){
            if(obj.hasChildNodes()){
                var child = obj.firstChild;
                var children = obj.childNodes;
                var length = children.length;
                for(var i = 0;i<length;i++){
                    var nodes = children[i];
                    if(nodes.nodeType !==3){
                        DOMwalker(nodes);
                    }
                    if(nodes.nodeType===3){
                        //Pass the parameters nodes:current node being traversed;obj:selector being passed as parameter for DOMwalker function 
                        highlight(nodes,obj);
                    }
                }
                child = child.nextSibling;
            }
        }
        function highlight(node,parent){
            var regex =/(\d{1}-\d{1,4}-\d{1,5})|(\+\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9})/g;
            //Stores the value of current node which is passed through the if loop
            var matchs = node.data.match(regex);
            if matchs is true,add it to DOM
            if(matchs){
                var anchor = document.createElement("a");
                var y = /[(]\d[)]|[.-\s]/g;//removes spaces periods or dash,also number within brackets
                var remove = number.replace(y,'');
                //tel uri,if you have an app like skype for click-to dial
                anchor.setAttribute("href","tel:"+remove);
                //the anchor tag should be inserted before in the current node in the DOM
                parent.insertBefore(anchor,node);
                //append it toh the DOM to be displaye don the web page
                anchor.appendChild(node);

            }
            else
            {
                return false;
            }

        }

I hope this code helps others.

Community
  • 1
  • 1
logan
  • 110
  • 11