Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
917 views
in Technique[技术] by (71.8m points)

javascript - How to replace lots of words in AJAX-driven page text, and in select attributes -- using a Tampermonkey script?

I'm translating text/words/terms inside an HTML document using a tree walker to affect 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;
}


This works well on static pages (and it doesn't bust hyperlinks or event handlers), but I want it to also:

  • Catch AJAX'd-in content
  • Replace text in placeholder attributes

How do I do that without resorting to RegEx and really mucking things up?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

To handle AJAX content, you can either use MutationObservers or polling with a timer. The former can get tricky and complicated, while the timer is simple, robust, and works well for most all practical applications.

To handle attributes like placeholder, merely use document.querySelectorAll("[placeholder]") to get the nodes and loop through the resulting NodeList.

While you are at it, you'll probably want to translate title attributes too.

In short:

  • Put the replacement code in a function.
  • Call that function inside a setInterval.
  • Add a separate loop, inside the interval, for the attributes you want to change.

Putting it all together, the cross-browser userscript would look like the following. See the inline comments and
you can test the script against 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;
                  //-- 5 times/second; Plenty fast.
var transTimer  = setInterval (translateTermsOnPage, 222); 

function translateTermsOnPage () {
    /*--- Replace text on the page without busting links or javascript 
        functionality.
    */
    var txtWalker   = document.createTreeWalker (
        document.body,
        NodeFilter.SHOW_TEXT, {
            acceptNode: function (node) {
                //-- Skip whitespace-only nodes
                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 replace 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";
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...