1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Need help with turning URLs into hyperlinks

Discussion in 'JavaScript' started by qwikad.com, May 27, 2016.

  1. #1
    It turns URLs into hyperlinks only if I press the space bar or Enter after I type a URL. I want it to turn a URL into a hyperlink as soon as I finish typing it (right after I finish typing .com, .org, .net, etc). I am guessing it has something to do with startOffset / endOffset/ start / end / rng but I can't figure it out:

    
    tinymce.PluginManager.add('autolink', function(editor) {
        var AutoUrlDetectState;
        var AutoLinkPattern = /^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;
    
        if (editor.settings.autolink_pattern) {
            AutoLinkPattern = editor.settings.autolink_pattern;
        }
    
        editor.on("keydown", function(e) {
            if (e.keyCode == 13) {
                return handleEnter(editor);
            }
        });
    
        // Internet Explorer has built-in automatic linking for most cases
        if (tinymce.Env.ie) {
            editor.on("focus", function() {
                if (!AutoUrlDetectState) {
                    AutoUrlDetectState = true;
    
                    try {
                        editor.execCommand('AutoUrlDetect', false, true);
                    } catch (ex) {
                        // Ignore
                    }
                }
            });
    
            return;
        }
    
        editor.on("keypress", function(e) {
            if (e.keyCode == 41) {
                return handleEclipse(editor);
            }
        });
    
        editor.on("keyup", function(e) {
            if (e.keyCode == 32) {
                return handleSpacebar(editor);
            }
        });
    
        function handleEclipse(editor) {
            parseCurrentLine(editor, -1, '(', true);
        }
    
        function handleSpacebar(editor) {
            parseCurrentLine(editor, 0, '', true);
        }
    
        function handleEnter(editor) {
            parseCurrentLine(editor, -1, '', false);
        }
    
        function parseCurrentLine(editor, end_offset, delimiter) {
            var rng, end, start, endContainer, bookmark, text, matches, prev, len, rngText;
    
            function scopeIndex(container, index) {
                if (index < 0) {
                    index = 0;
                }
    
                if (container.nodeType == 3) {
                    var len = container.data.length;
    
                    if (index > len) {
                        index = len;
                    }
                }
    
                return index;
            }
    
            function setStart(container, offset) {
                if (container.nodeType != 1 || container.hasChildNodes()) {
                    rng.setStart(container, scopeIndex(container, offset));
                } else {
                    rng.setStartBefore(container);
                }
            }
    
            function setEnd(container, offset) {
                if (container.nodeType != 1 || container.hasChildNodes()) {
                    rng.setEnd(container, scopeIndex(container, offset));
                } else {
                    rng.setEndAfter(container);
                }
            }
    
            // Never create a link when we are inside a link
            if (editor.selection.getNode().tagName == 'A') {
                return;
            }
    
            // We need at least five characters to form a URL,
            // hence, at minimum, five characters from the beginning of the line.
            rng = editor.selection.getRng(true).cloneRange();
            if (rng.startOffset < 5) {
                // During testing, the caret is placed between two text nodes.
                // The previous text node contains the URL.
                prev = rng.endContainer.previousSibling;
                if (!prev) {
                    if (!rng.endContainer.firstChild || !rng.endContainer.firstChild.nextSibling) {
                        return;
                    }
    
                    prev = rng.endContainer.firstChild.nextSibling;
                }
    
                len = prev.length;
                setStart(prev, len);
                setEnd(prev, len);
    
                if (rng.endOffset < 5) {
                    return;
                }
    
                end = rng.endOffset;
                endContainer = prev;
            } else {
                endContainer = rng.endContainer;
    
                // Get a text node
                if (endContainer.nodeType != 3 && endContainer.firstChild) {
                    while (endContainer.nodeType != 3 && endContainer.firstChild) {
                        endContainer = endContainer.firstChild;
                    }
    
                    // Move range to text node
                    if (endContainer.nodeType == 3) {
                        setStart(endContainer, 0);
                        setEnd(endContainer, endContainer.nodeValue.length);
                    }
                }
    
                if (rng.endOffset == 1) {
                    end = 2;
                } else {
                    end = rng.endOffset - 1 - end_offset;
                }
            }
    
            start = end;
    
            do {
                // Move the selection one character backwards.
                setStart(endContainer, end >= 2 ? end - 2 : 0);
                setEnd(endContainer, end >= 1 ? end - 1 : 0);
                end -= 1;
                rngText = rng.toString();
    
                // Loop until one of the following is found: a blank space, &nbsp;, delimiter, (end-2) >= 0
            } while (rngText != ' ' && rngText !== '' && rngText.charCodeAt(0) != 160 && (end - 2) >= 0 && rngText != delimiter);
    
            if (rng.toString() == delimiter || rng.toString().charCodeAt(0) == 160) {
                setStart(endContainer, end);
                setEnd(endContainer, start);
                end += 1;
            } else if (rng.startOffset === 0) {
                setStart(endContainer, 0);
                setEnd(endContainer, start);
            } else {
                setStart(endContainer, end);
                setEnd(endContainer, start);
            }
    
            // Exclude last . from word like "www.site.com."
            text = rng.toString();
            if (text.charAt(text.length - 1) == '.') {
                setEnd(endContainer, start - 1);
            }
    
            text = rng.toString();
            matches = text.match(AutoLinkPattern);
    
            if (matches) {
                if (matches[1] == 'www.') {
                    matches[1] = 'http://www.';
                } else if (/@$/.test(matches[1]) && !/^mailto:/.test(matches[1])) {
                    matches[1] = 'mailto:' + matches[1];
                }
    
                bookmark = editor.selection.getBookmark();
    
                editor.selection.setRng(rng);
                editor.execCommand('createlink', false, matches[1] + matches[2]);
                editor.selection.moveToBookmark(bookmark);
                editor.nodeChanged();
            }
        }
    });
    
    Code (markup):

     
    qwikad.com, May 27, 2016 IP
  2. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #2
    How would the script know that you have finished typing a URL? Right now when you press space it evaluates if the string has a pattern in the start: https, etc. To do what you want you'll have to check on every key entry if the finishing characters of the string include .com, .org etc. but this etc. has to be an array of all TLDs. Do you think you'll have real benefits from achieving what you describe? I think pressing space is good enough. If you think you really need this functionality I'll look how to do it.
     
    Blizzardofozz, May 27, 2016 IP
  3. sarahk

    sarahk iTamer Staff

    Messages:
    28,500
    Likes Received:
    4,460
    Best Answers:
    123
    Trophy Points:
    665
    #3
    I'd leave well alone.
    @Blizzardofozz and I are on the same wavelength :)

    lets say I typed in mysite.co
    • How is the script to know that I've finished typing?
    • How is the script to know that I'm going to keep going... .co.uk, .com, etc
    • What if I was going to type in a deeplink? something like mysite.com/products/widgets/red/v2.html
     
    sarahk, May 27, 2016 IP
  4. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #4
    How about turning it into a hyperlink if someone types http:// or https:// ? And then a space or a new line will mean the URL is ended. Can this be done?
     
    qwikad.com, May 28, 2016 IP
  5. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #5
    I thought that now it works like that?
     
    Blizzardofozz, May 28, 2016 IP
  6. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #6
    I guess you guys missed my point. It turns into a hyperlink ONLY after you press the space bar or Enter when you finish typing a URL. A URL will stay like it's a plain text if nothing is pressed. What I want is I want it to start turning into a hyperlink while the URL is being typed. And yes it can be done. I have another editor that does that and I would want this one to do the same, BUT anything I tried didn't work. That script makes no sense to me. To understand what I mean by it "after you press the space bar or Enter" check out this jsfiddle:

    http://fiddle.tinymce.com/


     
    qwikad.com, May 28, 2016 IP
  7. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #7
    It happens here:

    
    editor.on("keydown", function(e) {
         if (e.keyCode == 13) {
             return handleEnter(editor);
         }
    });
    
    editor.on("keypress", function(e) {
         if (e.keyCode == 41) {
             return handleEclipse(editor);
         }
    });
    
    editor.on("keyup", function(e) {
         if (e.keyCode == 32) {
             return handleSpacebar(editor);
         }
    });
    
    
    Code (markup):
    This code checks if you have entered 13 - enter; 41 - select; 32 - space and then makes the magic. The new code should check on every key user presses if he had entered a string that is part of the pattern:
    var AutoLinkPattern = /^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i;
    This after last space user had entered.

    I have to go now but I'll check tomorrow if you have managed to do it and will try to help if you didn't.
     
    Blizzardofozz, May 28, 2016 IP
  8. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #8
    Can't make it work. Tried all sorts of things. Will wait for your solution.
     
    qwikad.com, May 28, 2016 IP
  9. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #9
    Try changing:
    
    editor.on("keyup", function(e) {
      if (e.keyCode == 32) {
        return handleSpacebar(editor);
      }
    });
    
    Code (markup):
    into this:

    
    editor.on("keyup", function(e) {
      parseCurrentLine(editor, 0, '', true);
    });
    
    Code (markup):
    and see if it will work.
     
    Blizzardofozz, May 29, 2016 IP
  10. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #10
    Not quite. Actually when I was trying to make it work it did the same thing to me. Basically to goes like this you start typing http:// or www. the moment it hits the first letter it converts into a hyperlink:

    1.gif
     
    qwikad.com, May 29, 2016 IP
  11. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #11
    
    editor.on("keyup", function(e) {
      return handleSpacebar(editor);
    });
    
    Code (markup):
    try like this. just remove the if statement that checks if user presses space and the script will check the string for the URL pattern on every keyup. This should work.

    Oh I get it - it turns to link the URL when detects www. and then stops turning the string into link?

    Try what happens if comment out or remove this:
    
    if (editor.selection.getNode().tagName == 'A') {
    return;
    }
    
    Code (markup):
     
    Last edited: May 29, 2016
    Blizzardofozz, May 29, 2016 IP
  12. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #12
    No, it's still doing the same thing. I don't think it's going to work unless something like this happens: you start typing a URL, after you key in http:// or www. it should turn into: <a href="http ://someurlcom">http ://someurl.com and it should stay open until you push the space bar or Enter, then </a> should close it. Other than that I can't see how it's going to work. Everything there goes through DOM, so I am not sure if it's designed to work that way, but maybe you can figure it out.

     
    qwikad.com, May 29, 2016 IP
  13. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #13
    Did you try removing
    
    if (editor.selection.getNode().tagName == 'A') {
    return;
    }
    
    
    Code (markup):
     
    Blizzardofozz, May 29, 2016 IP
  14. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #14
    I didn't see you added this, let me try. I'll post a PS here so that I wouldn't have to run up the comment count.


    @Blizzardofozz **PS**
    Still doing the same thing.
     
    qwikad.com, May 29, 2016 IP
  15. PoPSiCLe

    PoPSiCLe Illustrious Member

    Messages:
    4,623
    Likes Received:
    725
    Best Answers:
    152
    Trophy Points:
    470
    #15
    I think a better / easier / less resources used solution would be to just use a warning before the editor, saying that links will be converted to actual hyperlinks after pressing space or enter. Having the DOM updating after every keystroke is demanding, and can lead to problems.
     
    PoPSiCLe, May 29, 2016 IP
  16. Blizzardofozz

    Blizzardofozz Well-Known Member

    Messages:
    132
    Likes Received:
    9
    Best Answers:
    1
    Trophy Points:
    118
    #16
    My bad I didn't fully analyze the script. This plugin uses editor.execCommand('createlink'...) method to create the link so to achieve what you want it should turn the link into a string again on the next key press and all process to repeat till user hits the space so the string will be turned into a link and again to string every time. Are you sure you've seen this in other editor and what is the name of this editor so I could check? It doesn't seems logical.

    Is it possible what you have seen is just underlining and coloring of the future link with css? And then after hitting space the string to be converted into a link?
     
    Blizzardofozz, May 30, 2016 IP
  17. qwikad.com

    qwikad.com Illustrious Member Affiliate Manager

    Messages:
    7,151
    Likes Received:
    1,656
    Best Answers:
    29
    Trophy Points:
    475
    #17
    Now that I checked it out, the other editor doesn't use the html dom or "createlink" function. It's a pure regex. My bad.

    Can this be done with the code I have up there? That would give my users some assurance that the link is / being created while they are entering it. It's all about a quality user experience for me.
     
    qwikad.com, May 30, 2016 IP
  18. ketting00

    ketting00 Well-Known Member

    Messages:
    772
    Likes Received:
    27
    Best Answers:
    3
    Trophy Points:
    128
    #18
    Do you mean something like this:
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Test</title>
        <style>
            textarea {
                width: 400px;
                height: 200px;
            }
        </style>
    </head>
    <body>
      
        <textarea id="textarea"></textarea>
        <script>
            var tex = document.getElementById('textarea')
             , exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
    
            tex.addEventListener('keyup', function(e) {
                var txt = tex.value;
    
                if (e.keyCode == 32) {
                    var ttt = txt.replace(exp, "<a href='$1'>$1</a>")
                     , mor = exp.test(txt);      
                  
                    tex.value = ttt;
                  
                    if(mor == true) {
                        exp = null;
                    }
                }
            });
        </script>
    
    </body>
    </html>
    
    Code (markup):
    However, it only works one time. I don't know how to disable keyup, so I null the element and causes the code error.

    Maybe the others can help.
     
    ketting00, Jun 1, 2016 IP