Can I make words into links automatically? (HTML / Javascript question)

Is there a way to have words or phrases automatically become links? For instance, if I wanted a particular word that’s used often on a webpage to link somewhere else (such as a definition for said word), is there any kind of applet that could do that?

I guess my idealised solution would be a self-contained javascript file that includes a list of words and what they link to, so whenever the browser came across a word in that Javascript file, it would make it a link – sort of like those annoying advertising based models that automatically link some words (like “Shoe”) to an advertiser (such as “Nike.com”).

I realize I could manually make a link for each word, but if I ever wanted to update the linked url, it’d be a major product to go back through and change each link.

Is there anything that can do this?

I know of some spyware that will make all sorts of words into links…
I guarantee this will be moved to ATMB.

Once your 5-minute window has passed, you wouldn’t be able to change a “url” link anyway.

If you want your own links to change over time, the best thing to do would be to have the link be a pre-set search on Google or the like. Such as something instead of something.

Having the type of ad-based keyword links in the SDMB would cause me (and many others I’d suspect) to leave quickly.

Thanks for the response, but I guess my OP wasn’t that clear…

What I want to do has nothing to do with the SDMB. Instead, it’s for a website I work for that provides online instruction manuals. Ideally, I’d like to have technical terms that appear throughout those documents automatically link to the definitions of those words, if that makes sense.

I retract my guarantee then.

It looks like you want automatic hyperlinks in you web pages, right? Controlled by you rather than a paying sponsor, presumably.

I’m no coder, but after a bit of Google-fu, I found some pre-built scripts that might do what you want, but some search hits were deemed questionable by McAfee. You could look through stuff yourself or wait for the real web gurus come along.

I’ve done that.

All I did to accomplish it was use a global search/replace command to change all occurances of, for example, “SMDB” to “http://boards.straightdope.com/sdmb/”.

Actually, I created such a command for each word I wanted to link, and saved them all in a file, so I could re-run them against the page whenever the text was changed.

Just about any text editor has this feature.

I’m not very good with HTML, so I leave the details to someone else, but perhaps this will help. It seems to me that you should clarify among three options here:

[ol]
[li]An external script that scans an HTML file, inserts the correct hyperlink, and writes a new HTML file[/li][li]Read from a file as the web page is loaded, creating the link’s object dynamically[/li][li]When a link is clicked, read from a file to “locate” the proper URL[/li][/ol]
Sounds to me like neither (1) nor (2) are what you want. For (1), you write the HTML, run the script, and get a new HTML file with the correct links (this would be something like using sed or perl on a pre-existing file). For (2), you would be dynamically serving the page. For (3), you might do something like the following; it’s some javascript I wrote for bibliography display. Each displayed item is followed by a link with a specified file name. When clicked, it will pop a window that displays the contents of the specified file. Here’s the javascript function:


<script language="JavaScript" type="text/javascript">
<!--
function popbibtex(bibentry) {
  bibwin = window.open(bibentry, "bibtexwindow", "menubar=1,scrollbars=yes,resizable=1,width=800,height=250,top=100,left=100");
}
// -->
</script>

And here’s how it’s used:


<!--
(<a href="javascript: popbibtex('./bibitem1.txt')">bibitem1</a>)
-->

When the link that is displayed as bibitem1 (from the second code window) is clicked, the contents of bibitem1.txt is displayed in a popup window. Normally, of course, the link is preceded by a bibliography entry, which I left out to avoid the clutter.

It sounds to me like you actually want to keep all your terms and definitions in a single file, which will require code to search the file and extract what you want. Hope that somewhat clarifies the issue and helps a bit.

Digital Stimulus sort of hinted at this in his/her post, but the best way to accomplish this is to use a database-driven format (such as PHP or ASP) that allows you to manipulate the text before it is written to the browser. With a dynamic page, you can control the output of the content on the fly, before the page is “written” and could very easily search for a substring within the string of data (for example, the word “foo” in the string “I had a lot of foo for lunch”) and replace it with a different string (“I had a lot of <a href=foo.html>foo</a> for lunch”).

Doing this sort of thing with static content seems way too complicated, if it can be accomplished at all.

I once wrote some javascript to do something very similar (except I wanted to change certain words into black text on a yellow background automatically, to display a page as search results), but I can’t seem to find it at the moment.

But here’s the gist. Your javascript looks something like this (forgive the pseudocode and any IEisms, it’s been a while since I’ve written DHTML stuff):



// -- linkables.js
var linkables = 
[
    { word: "shoes", link: "http://www.nike.com" },
    { word: "education", link: "http://www.straightdope.com" },
    { word: "search", link: "http://www.google.com" }
];

function CreateLinks()
{
    var elementsBefore = new Array();
    //first make an array containing all the elements in the document.
    //this must be a copy because as we iterate through, we will be
    //be adding elements, which will confuse our loop otherwise

    for(each element in the document)
    {
        elementsBefore[elementsBefore.length] = element;
    }

    for(var x in elementsBefore)
    {
        if(it is a text element)
        {
            CreateLinksInTextNode(element);
        }
    }
}

function CreateLinksInTextNode(node)
{
    for(var linkable in linkables)
    {
        var otext = node.data.toLowerCase();
        var oterm = linkable.word.toLowerCase();
        var searchStart = 0;
        var inserted = false;
        var offset;

        //replace text node "hello shoes goodbye" with three new nodes:
        // 1) text node: 'hello '
        // 2) "A" node: '<a href="http://www.nike.com">shoes</a>'
        // 3) text node: ' goodbye'
        while( (offset = otext.indexOf(oterm, searchStart)) >= 0 )
        {
            inserted = true;
            var before = node.data.substr(searchStart, offset - searchStart)
            var matched = node.data.substr(offset, linkable.word.length);

            var newnode = document.createTextNode(before);
            node.parentNode.insertBefore(newnode, node);

            newnode = document.createElement('<a href="' + linkable.link + '">');
            newnode.innerText = matched;
            node.parentNode.insertBefore(newnode, node);

            searchStart = offset + linkable.word.length;
        }

        if(inserted)
        {
            var after = node.data.substr(searchStart, node.data.length - searchStart
);
            var newnode = document.createTextNode(after);
            node.parentNode.insertBefore(newnode, node);

            node.removeNode(true);
        }

    }
}


Then all you have to do is <script src=“linkables.js” /> from any page, and call CreateLinks() from somewhere after your page is fully loaded. The nice thing about this approach is that it even works on text that is created dynamically on the client-side from javascript, which the preprocess-on-the-server-to-create-links approach won’t do.

I can’t say I agree about this approach being better. Opening up a connection to a database on every page hit is a very expensive proposition in terms of server scalability. Even firing up a PHP or ASP interpreter is pretty heavyweight when compared to serving two static files (the HTML and JS). Never waste your server’s CPU time on something the browser can do without the user even noticing.

For clarity, this would be option (2) from my earlier post. I should think it would be way more trouble than it’s worth (unless you plan on redefining terms daily). :slight_smile:

It looks to me like the code given by galt would work (and be better), replacing both my static links to files (in the HTML) and the use of individual files (storing the text to be displayed in popup window). You could make it run a bit more efficiently in the search (for instance, by alphabetizing the terms, then doing a binary search), but I suspect it wouldn’t be worth the effort (unless you have a huge number of defined terms).

Galt, that’s a very good solution and exactly what the OP is looking for.

I tend towards dynamic, database-driven solutions because that is what my company specializes in. I do not consider leaning on a database to be a problem for any server using the right setup and the right code. However, well-executed JavaScript is also perfectly viable as you have shown here.

For some, database-driven content is easier to update, manage and manipulate. For others, it’s a simple script like yours.

For what it’s worth, I can see that I made a large coding error. I took the solution that was in my brain which modified occurrences of a single word and wrapped it in a foreach loop without thinking too hard about it. The code, as presented, will not produce the right results if there is a single text element that contains more than one of the specified “linkables”. Not too difficult to fix, but I don’t have time at the moment. So take it with a grain of salt. :wink:

Which is why caching engines exist and would be very useful in this situation… Everytime the page is updated, re-render it and update a static cache of it on the server. Keeping all the keywords (especially if it gets big) would be much more easier to deal with in a database rather than being in a massive Javascript file (especially if you don’t want a complete list visible to the public for whatever reason).

An excellent point. I still like the client-side solution enough that I fixed my code over lunch (note that it requires the prototype.js library (http://www.prototypejs.org) because I’m lazy and can’t be bothered to remember the proper portable way to walk the document). Note also that if you actually want to use this, it might be useful to split the data table into its own file.



var linkables =
[
    { word: "shoes", link: "http://www.nike.com" },
    { word: "education", link: "http://www.straightdope.com" },
    { word: "search", link: "http://www.google.com" }
];

function CreateLinks()
{
    var textNodes = new Array();
    var elems = $$('*');
    for(var elem in elems)
    {
        var children = elems[elem].childNodes;
        for(var child in children)
        {
            if(children[child].nodeType == 3)
            {
                textNodes[textNodes.length] = children[child];
            }
        }
    }

    for(var x in textNodes)
    {
        CreateLinksInTextNode(textNodes[x]);
    }
}

// 0) if this node matches the search term:
// 1) insert new, highlighted nodes in front of the given node
// 2) delete given node

function CreateLinksInTextNode(node)
{
    var otext = node.data
    var searchStart = 0;
    var inserted = false;

    if(!otext) return;

    var next = FindNextLinkable(otext);
    while( next.index >= 0)
    {
        inserted = true;
        var before = otext.substr(0, next.index)
        var matched = otext.substr(next.index, next.word.length);

        var newnode = document.createTextNode(before);
        node.parentNode.insertBefore(newnode, node);

        newnode = document.createElement('<a>');
        newnode.innerText = matched;
        newnode.href = next.link;
        node.parentNode.insertBefore(newnode, node);

        var newstart = next.index + next.word.length;
        otext = otext.substr(newstart);
        next = FindNextLinkable(otext);
    }

    if(inserted)
    {
        var newnode = document.createTextNode(otext);
        node.parentNode.insertBefore(newnode, node);

        node.removeNode(true);
    }

    return inserted;
}

function FindNextLinkable(str)
{
    var result = new Object();
    result.index = -1;

    if(!str || str.length == 0) return result;

    for(var x in linkables)
    {
        if(!linkables.hasOwnProperty(x)) continue;

        var l = linkables[x];
        var index = str.indexOf(l.word);
        if(index >= 0)
        {
            alert("found " + l.word + " in " + str);
            if(result.index >= 0)
            {
                if(result.index > index)
                {
                    result.index = index;
                    result.word = l.word;
                    result.link = l.link;
                }
            }
            else
            {
                result.index = index;
                result.word = l.word;
                result.link = l.link;
            }
        }
    }

    return result;
}


I know you didn’t ask, but this is one of my biggest gripes with reading articles on Wikipedia. It seems like every third word in some articles is a hyperlink to some other article.

Thats because one of the solutions to the OPs problem is a wiki - most wiki engines automatically link terms in content to pages with the same title.

I can see why the javascript/client processing is a solution, but for a moderate-to-large scale hyperlinked documentation project - I would use a wiki of some sort. It will end up being easier to develop, manage and maintain.

Si