3

I'm trying to change the attribute of the headline entries in any Google search by a Google Chrome extension. By headline entries I mean these red-underlined: Image: http://postimg.org/image/sgsyccbpf/ Looking at the HTML code of a random Google search with the Mozilla Firefox inspector: Image: http://postimg.org/image/gsywhsmkj/ My idea was to obtain every element by looking for class name "rc". Maybe it's not a good idea, but I think it would work.

In order to develop the Chrome extension, I've written these files:

manifest.json

{
    "name": "Test  1",
    "version": "1.0.0",
    "manifest_version": 2,
    "content_scripts": [
        {
            "matches": [
                "https://*/*",
                "http://*/*",
                "<all_urls>"
            ],
            "js":         ["content_scripts.js"],
            "run_at":     "document_start",
            "all_frames": true
        }
    ]
}

content:scripts.js

var doFilter = function() { 
    var classR = document.getElementsByClassName("rc");

    for(var i=0; i < classR.length; i++) { 
        classR[i].setAttribute("style", "background-color:green"); 
        classR[i].setAttribute("align", "center");
    }
}

window.addEventListener("DOMContentLoaded", function() {
    doFilter(document.body);
});

Here is a demonstration of how my extension worked in my own html page: Image: postimg.org/image/bdi02zvfl (This is a link to a image but the system don't allow me to post more than two of them)

However, while searching normally in Google it does not work. Every "headline entry" should be green-backgrounded and centered as in the demonstration.

What am I missing?

Thanks!

user2957378
  • 627
  • 2
  • 14
  • 29
  • possible duplicate of [How to know when Google search results page renders its results?](http://stackoverflow.com/questions/20582991/how-to-know-when-google-search-results-page-renders-its-results) – gkalpak Jan 12 '14 at 15:17
  • I've already marked as accepted your very exact solution in the thread you refered me. Now I've marked this one as well. Thank you. – user2957378 Jan 17 '14 at 18:48

3 Answers3

2

Since the Google fetches the results asynchronously, you could use a MutationObserver to catche changes in the DOM and act accordingly. See this answer for a more detailed explanation and sample code.

Below is the code from the above question with a few modifications to achieve what you want. Editing the modifyElem() function, it should be easy to realize just about any modification.

content.js:

console.log("Injected...");

/* MutationObserver configuration data: Listen for "childList"
 * mutations in the specified element and its descendants */
var config = {
    childList: true,
    subtree: true
};

/* Traverse 'rootNode' and its descendants and modify '.rc' elements */
function modifyElems(rootNode) {
    var nodes = [].slice.call(rootNode.querySelectorAll('.rc'));
    if (rootNode.className === 'rc') {
        nodes.push(rootNode);
    }
    while (nodes.length > 0) {
        var st = nodes.shift().style;
        st.backgroundColor = 'green';
        st.textAlign = 'center';
    }
}

/* Observer1: Looks for 'div#search' */
var observer1 = new MutationObserver(function(mutations) {
    /* For each MutationRecord in 'mutations'... */
    mutations.some(function(mutation) {
        /* ...if nodes have beed added... */
        if (mutation.addedNodes && (mutation.addedNodes.length > 0)) {
            /* ...look for 'div#search' */
            var node = mutation.target.querySelector("div#search");
            if (node) {
                /* 'div#search' found; stop observer 1 and start observer 2 */
                observer1.disconnect();
                observer2.observe(node, config);

                /* Modify any '.rc' elements already in the current node */
                modifyElems(node);

                return true;
            }
        }
    });
});

/* Observer2: Listens for element insertions */
var observer2 = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        if (mutation.addedNodes) {
            [].slice.call(mutation.addedNodes).forEach(function(node) {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    modifyElems(node);
                }
            });
        }
    });
});

/* Start observing 'body' for 'div#search' */
observer1.observe(document.body, config);
Community
  • 1
  • 1
gkalpak
  • 47,844
  • 8
  • 105
  • 118
1

Your doFilter() function only runs once when the page initially loads, which means that if Google loads in any results using AJAX (as it often does), your code will not affect them.

How about having your extension add a <style> element to the page head with the styles you want?

<style>
.rc { background-color: green; text-align: center; }
</style>

This has the added benefit of not blasting away any style attributes that the target elements might already have.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • I created a *mystyles.css* file with the code you wrote and added the line *"css":[ "mystyle.css"],* in the manifest; but it's not working. However, before we follow this solution I should say that my final goal will include another checking over the class "rc", so I will definitely need to evaluate it withing javascript. Is there any way to execute the script when AJAX code has already been executed? – user2957378 Jan 12 '14 at 05:56
0
$(window).load(function() {
    doFilter(document.body);;
});

Instead of:

window.addEventListener("DOMContentLoaded", function() {
    doFilter(document.body);
});

solved my problem. I also had to download jquery.js library file and refer it within the manifest here:

"js":         ["jquery.js", "content_scripts.js"],

There is a lot of confusion dealing with jQuery functions. As far as I could read, $(window).load() is the one which is executed once the page is fully created. Reference: jQuery - What are differences between $(document).ready and $(window).load? Thank you @JLRishe for the response.

Community
  • 1
  • 1
user2957378
  • 627
  • 2
  • 14
  • 29