Tips for efficiently updating numerous words in text on a webpage powered by AJAX, as well as in select attributes, by implementing a Tampermonkey script

My approach involves translating specific text, words, and terms within an HTML document using a tree walker to target only text nodes:

var replaceArry = [
    [/View your user account/gi,    'Tu cuenta'],
    // etc.
];
var numTerms    = replaceArry.length;
var txtWalker   = document.createTreeWalker (
    document.body,
    NodeFilter.SHOW_TEXT,
    {   acceptNode: function (node) {
            //-- Skip whitespace-only nodes
            if (node.nodeValue.trim() )
                return NodeFilter.FILTER_ACCEPT;

            return NodeFilter.FILTER_SKIP;
        }
    },
    false
);

var txtNode     = null;
while (txtNode  = txtWalker.nextNode () ) {
    var oldTxt  = txtNode.nodeValue;

    for (var J  = 0;  J < numTerms;  J++) {
        oldTxt  = oldTxt.replace (replaceArry[J][0], replaceArry[J][1]);
    }
    txtNode.nodeValue = oldTxt;
}


While this method is effective on static pages without affecting hyperlinks or event handlers, I am looking for ways to:

  • Handle dynamically loaded content through AJAX requests
  • Replace text in placeholder attributes as well

Is there a way to achieve this functionality without resorting to complex RegEx operations that may disrupt the existing structure?

Answer №1

If you need to manage AJAX content, you have a couple of options. You can either utilize MutationObservers or implement polling with a timer. While the former approach may be more complex and intricate, using a timer is simpler, reliable, and suitable for most practical scenarios.

To handle attributes such as placeholder, you can simply target them by using

document.querySelectorAll("[placeholder]")
to access the nodes and iterate through the resulting NodeList.

Additionally, consider translating title attributes as well.

In summary:

  • Encapsulate the replacement code within a function.
  • Invoke that function within a setInterval.
  • Include a separate loop within the interval for the attributes you wish to modify.

Combining all these elements, the cross-browser userscript will resemble the example below. Review the inline comments and
you can experiment with the script on this jsFiddle page.

// ==UserScript==
// @name     Replace lots of terms on an AJAX'd page
// @include  http://fiddle.jshell.net/Hp6K2/show/*
// @grant    none
// ==/UserScript==
var replaceArry = [
    [/text/gi,                      'blather'],
    [/View your user account/gi,    'Tu cuenta'],
    // etc.
];
var numTerms    = replaceArry.length;
                  //-- Executes every 5 times per second; Adequately fast.
var transTimer  = setInterval (translateTermsOnPage, 222); 

function translateTermsOnPage () {
    /*--- Substitutes text on the page without disrupting links or JavaScript 
        functions.
    */
    var txtWalker   = document.createTreeWalker (
        document.body,
        NodeFilter.SHOW_TEXT, {
            acceptNode: function (node) {
                //-- Skips nodes composed solely of whitespace
                if (node.nodeValue.trim() ) {
                    if (node.tmWasProcessed)
                        return NodeFilter.FILTER_SKIP;
                    else
                        return NodeFilter.FILTER_ACCEPT;
                }
                return NodeFilter.FILTER_SKIP;
            }
        },
        false
    );
    var txtNode     = null;
    while (txtNode  = txtWalker.nextNode () ) {
        txtNode.nodeValue       = replaceAllTerms (txtNode.nodeValue);
        txtNode.tmWasProcessed  = true;
    }
    //
    //--- Now replaces user-visible attributes.
    //
    var placeholderNodes    = document.querySelectorAll ("[placeholder]");
    replaceManyAttributeTexts (placeholderNodes, "placeholder");

    var titleNodes          = document.querySelectorAll ("[title]");
    replaceManyAttributeTexts (titleNodes, "title");
}

function replaceAllTerms (oldTxt) {
    for (var J  = 0;  J < numTerms;  J++) {
        oldTxt  = oldTxt.replace (replaceArry[J][0], replaceArry[J][1]);
    }
    return oldTxt;
}

function replaceManyAttributeTexts (nodeList, attributeName) {
    for (var J = nodeList.length - 1;  J >= 0;  --J) {
        var node    = nodeList[J];
        var oldText = node.getAttribute (attributeName);
        if (oldText) {
            oldText = replaceAllTerms (oldText);
            node.setAttribute (attributeName, oldText);
        }
        else
            throw "attributeName does not match nodeList in replaceManyAttributeTexts";
    }
}

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

Showing list data from script to template in vue - A step-by-step guide

My task involves displaying data from the main table in MySQL. I need to show the type of each major by comparing it with the id in the faculty table. I have successfully logged this information using console.log, but I'm unsure how to display it on t ...

Is there a possibility of Node.js being blocked during the processing of large file uploads?

Is it possible for Node.js to become blocked during the processing of large file uploads? Due to Node.js having only one thread, is there a risk that other requests will be blocked while handling large file uploads? If this is the case, what is the best ...

What is the best way to utilize JSONP to display an entire HTML code with an alert?

When I attempt to use cross-domain ajax to retrieve the entire HTML page code, I keep receiving a failed message. The console log shows: "Uncaught SyntaxError: Unexpected token <" Below is my AJAX function: function fetchData(){ var url = documen ...

What is the best way to insert an image in front of text within a table cell that can be identified by its class name?

JavaScript Question: function addFlags(){ while(i < $('.tabledata').length){ var current_val = $('.tabledata').eq(i).text(); arr.push(current_val); $('.tabledata').eq(i).html("<img s ...

Sometimes, it feels like TypeScript's async await does not actually wait for the task to complete before moving on

Recently, I have been transitioning to using the async await pattern more frequently instead of the traditional Promise syntax because it can help in keeping the code structure cleaner. After some experimentation, I felt like I had a good grasp on how to u ...

JavaScript updates the cursor after the completion of the JS function

Here is some code that I have been working with: <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> </head> <body style="background-color:yellow;width ...

Tips for effectively monitoring scope for data loading

I have successfully created a custom Angular directive that utilizes D3.js to create a visualization. In my HTML, I reference this directive as follows: <gm-link-analysis data="linkAnalysis.connections"></gm-link-analysis> The relevant part o ...

Sharing a Twitter thread using Twit library with Node.js

I have been using Node.js along with the npm Twit module to post tweets on Twitter, and while it works for a single tweet, I am facing issues when trying to post multiple tweets as a thread. When attempting to post a series of tweets together, they do not ...

Stay connected with AJAX's latest updates on Twitter with just 13 bytes

Twitter sends a POST request of only 13 bytes when someone follows an account. This small amount of information helps to reduce latency and server load, providing advantages for web developers. However, removing unnecessary cookies and extra information f ...

How to Monitor Store Changes within a Vue File Using Vue.js

I am working with 2 vue files, header.vue and sidebar.vue. Both components are imported into layout.vue. Here are the steps I am following: 1. Initially, when the page loads, I update the store in header.vue with some values inside the created hook. 2. ...

What is the best way to send a JSON object to bootstrap-table?

In my controller, I am passing a JSON encoded object to the view. Using a Bootstrap table in the view to display the data, but it is showing "No matching records found." Can someone please assist with this issue? Here is my controller: see image And here ...

When the button is clicked, update the text within the <script> tags utilizing jQuery, JavaScript, or PHP

Here is the code snippet where changeme represents the text that needs to be replaced upon clicking a button: The following HTML and JavaScript code demonstrates this functionality: 1) Any input provided by the user in the field will be captured, replaci ...

Guide on transferring JavaScript Objects from the Front End to Spring Boot Back-end and effectively processing and parsing them

After struggling with this issue repeatedly while developing my web apps, I've reached a breaking point and need some help. My frustration might come across as venting, but I'm genuinely stuck. The challenge I'm facing is sending key-value ...

Encountering an error while trying to import GraphQL resolvers and schema

Upon attempting to start the server with the following setup, an error is encountered: Error: "createUser" defined in resolvers, but has an invalid value "function (userInput) {... The resolver's value must be of type object. index.ts const schema ...

Browsing through different pages on a Rails app will trigger numerous requests to various destinations

My application consists of a landing page and a profile page. The relevant parts of my rake routes are: index GET /welcome/index(.:format) welcome#index show GET /profile(/:username)(.:format) sessions#show root / ...

Warning: Next.js is throwing a hydration error because the server HTML does not include a matching <main> element within a <div>

I have been encountering hydration issues in my next.js application. After extensive troubleshooting, I have found that the culprit might be the higher order component called withAuth.js The error message displayed is: Warning: Expected server HTML to con ...

How to Handle Errors When Retrieving an AWS S3 Object Stream in Node.js

I am currently working on developing an Express server that will send items from a S3 bucket to the client using Node.js and Express. I came across the following code snippet in the AWS documentation. var s3 = new AWS.S3({apiVersion: '2006-03-01&apo ...

What methods are available to load sections of a complex SVG shape asynchronously?

I'm currently in the process of creating a website with a geographic map built using SVG, pulling data from OpenStreetMap. Due to its large size and potential for transformations such as zooming and moving, only a portion of it will be visible on the ...

Retrieve the data entered in the submit button field

My question concerns a form with two buttons: <form method="post" action=""> <button type="submit" name="age" value="20">Age 20</button> <button type="submit" name="age" value="30">Age 30</button> </form> When ...

Navigating through objects to retrieve internal object values

I currently have a collection of objects stored in my program. const objs = { "1":{ "name":"Candice", "Classes": [00029,00023,00032,000222], "id":0002918 }, "2":{ "name":"Clark", "classes" ...