Swapping out the initial occurrence of every word in the list with a hyperlink

I stumbled upon a fantastic script on a programming forum that almost fits my requirements perfectly. It essentially replaces specific words in a document with links to Wikipedia. However, I have run into an issue where I only want the first occurrence of a word to be linked.

Here is the script (sourced from this particular response):

function replaceInElement(element, find, replace) {
    // logic to handle replacements and child nodes
}
function replaceInText(text, find, replace) {
    // code to replace text content with specified links
}

// defining keywords for matching purposes using regex
var find= /\b(keyword|whatever)\b/gi;

replaceInElement(document.body, find, function(match) {
    // creating wikipedia links based on matched keywords
});

I attempted to tweak the script by utilizing indexOf instead of regular expressions following guidance from another solution (referenced in this answer). The goal was to improve speed efficiency:

var words = ["keyword","whatever"];
var text = "Whatever, keywords are like so, whatever... Unrelated, I now know " +
           "what it's like to be a tweenage girl. Go Edward.";
var matches = []; 

var lowerCaseText = text.toLowerCase();
for (var i=0;i<words.length;i++) { 
    if (lowerCaseText.indexOf(words[i]) != -1) 
        matches.push(words[i]);    
}

My query is how can I merge these two scripts to achieve optimal speed without relying on external libraries?

Answer №1

Check out the modified code snippet below for your desired functionality http://jsfiddle.net/bW7LW/2/

function replaceContent(element, find, replace) {

    var found = {},
        replaceInElement = function(element, find, replace, init) {

            var child, tag, 
                len = element.childNodes.length, 
                i = 0,
                replaceInText = function(text, find, replace) {

                    var len = find.length,
                        index, i = 0;

                    for (; i < len; i++) {

                        index = text.data.indexOf(find[i]);

                        if (index !== -1 && found && !found[find[i]]) {

                            found[find[i]] = true;
                            text.splitText(index);
                            text.nextSibling.splitText(find[i]);
                            text.parentNode.replaceChild(replace(find[i]), text.nextSibling);
                            return;
                        };
                    };
                };

            // iterate over child nodes in reverse, as replacement may increase length of child node list.
            for (; i < len; i++) {

                child = element.childNodes[i];

                if (child.nodeType == 1) { // ELEMENT_NODE
                    tag = child.nodeName.toLowerCase();

                    if (tag != 'style' && tag != 'script') {
                        replaceInElement(child, find, replace);
                    }

                } else if (child.nodeType == 3) { // TEXT_NODE
                    replaceInText(child, find, replace);
                }
            }
        };
    replaceInElement(element, find, replace);
};

// keywords to match. This *must* be a 'g'lobal regexp or it'll fail bad
var find = 'Lorem Ipsum bla'.split(' ');

$(function() {

    // replace matched strings with wiki links
    replaceContent(document.body, find, function(str) {
        var link = document.createElement('a');
        link.href = 'http://en.wikipedia.org/wiki/' + str;
        link.appendChild(document.createTextNode(str));
        return link;
    });
});​

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Establish initial content for the specified div area

I need help setting page1.html to display by default when the page loads. Can you provide some guidance? Appreciate your assistance in advance. <head>     <title>Test</title>     <meta http-equiv="content-type" content="tex ...

Navigating between sibling components in Angular 1.5 using the component router

Is there a way to use the new component router in Angular 1.5 to display the sibling component alongside the main one within the ng-outlet directive? I am looking to showcase both the Detail View and the List View at the same time. Based on my understandin ...

Upon selecting multiple checkboxes, corresponding form fields will be displayed based on shared attributes

When multiple checkboxes are selected by the user, corresponding form fields should appear based on the checkboxes. For example, if both flight and hotel checkboxes are checked, then the full name and last name fields should be displayed while other fields ...

Is there a way to identify the moment when a dynamically added element has finished loading?

Edit: I've included Handlebar template loading in my code now. I've been attempting to identify when an element that has been dynamically added (from a handlebars template) finishes loading, but unfortunately, the event doesn't seem to trig ...

"Use jQuery to toggle the slide effect for the first element of a

Below is the HTML code snippet: <div class="row header collapse"> Content 1 <i class="fas fa-chevron-circle-up" ></i> </div> <div class="instructions-container"> <div></di ...

Show JSON response using AJAX jQuery

After receiving the JSON Response, { "user_data": { "id": 22, "first_name": xxx, "last_name": xxx, "phone_number": "123456789", }, "question_with_answers" : [ { "id": 1, ...

Sequencing the loading of resources in AngularJS one after the other by utilizing promises

While working in a service, my goal is to load a resource using $http, store it in a variable, load a child resource and store that as well. I understand the concept of promises for this task, but I am struggling with how to properly implement it in my cod ...

ES6 component rendering is malfunctioning on CodePen

class PlayfulPaws extends React.Component { constructor(props) { super(props); }; render() { return ( <div> <DIV /> <JSX /> <aClassDiv /> </div> ); }; }; ReactDOM.render(&l ...

Angular 2 Mixup: Using Leaflet and Google Maps with Incorrect Tile Order

I am encountering an issue while working on Leaflet and Google within Angular 2. The problem lies in the Tilemill tiles not rendering properly as they are displaying in a strange order. Here is a screenshot of the current state: https://i.stack.imgur.com/ ...

Is there a way to iterate through an array in reverse, starting from the last element and ending at the first element?

Is there a way in JavaScript to map an Array starting from the last index and going all the way to the beginning descending, without iterating from the beginning index? I'm looking for a more efficient method or feature I might have overlooked. Any s ...

How to retrieve static attributes while declaring an interface

class A { public static readonly TYPE = "A"; } interface forA { for: A.TYPE } I am facing an issue while trying to access A.TYPE from the forA interface in order to perform type guarding. The error I encounter is: TS2702: 'A' only refe ...

Error code 12004 encountered during the execution of a service request

While working on a service call in my JavaScript code that retrieves XML data using XMLHttpRequest, everything runs smoothly in Chrome and Firefox, successfully fetching the data over HTTPS. However, when attempting to execute the same code in IE11, it ret ...

Learn how to showcase specific row information in a vuetify data table on Vue.js by implementing icon clicks

I am currently working on a Vuetify data table that showcases order information, with an option for users to cancel their orders by clicking on the cancel icon. Upon clicking the cancel icon, a confirmation overlay pops up displaying the specific order id. ...

Replace minor components (SVG) within the primary SVG illustration

I'm interested in transforming SVG elements into the main SVG element. For example, let's say the black square represents the main SVG element. I want to change elements 1, 2, and 3 to different SVG elements using JavaScript code. However, I am u ...

Creating dynamic class fields when ngOnInit() is called in Angular

I am trying to dynamically create variables in a class to store values and use them in ngModel and other places. I understand that I can assign values to variables in the ngOnInit() function like this: export class Component implements OnInit{ name: st ...

Calculating the total price of items in a shopping cart by multiplying them with the quantity in Vue.js

I am currently working on enhancing the cart system in Vue.js, with a focus on displaying the total sum of product prices calculated by multiplying the price with the quantity. In my previous experience working with PHP, I achieved this calculation using ...

The Chrome Keyboard on Android seamlessly passes words to the next input field when the focus changes in JavaScript

When using two input fields, pressing the enter key on the first field in Chrome (49) on Android (6.0.1) carries over the last word typed to the new input due to the right-bottom button on the standard keyboard. Is there a way to prevent this behavior or a ...

Is it possible to utilize the NavigationTimingAPI with asynchronous requests?

Currently, I am working on implementing performance measuring functionality in our project that utilizes custom elements v1. The NavigationTimingAPI provides detailed measurements for various navigation types (navigate, reload, browser back/forward): Is ...

Debugging with Webstorm in node.js may not navigate to breakpoints as expected

Currently utilizing the angular-fullstack generator alongside Webstorm 10. The setup for node.js remote debug is as follows: localhost: 127.0.0.1 port: 5858 After inputting 'grunt serve:debug': Debugger listening on port 5858 Node Inspecto ...

The Jssor bullet navigator is not visible on the webpage

Currently, I am working on implementing a full-width slider with arrow navigators, bullet navigators, and captions using the Jssor plugin. Rather than copying and pasting example code, I decided to tackle this project independently with just a little guida ...