2

The usecase of my chrome extension is

As soon as the user loads his/her email, the content script should read the text from the opened mail and find if any text from the email matches with the provided topic objects. If it matches, it should create that text a url.For example if my topic object is

var topic = [{
 'name': 'Hello'
},
{'name': 'how are'}
]

In my opened mail page, if there is the word called 'hello', then that text should be converted to hyperlink hello.

original -> Hello world, how are you. This is the dummy text. 

then it should be

<a href="https://www.google.com/search/?q=Hello">Hello</a> world, <a href="https://www.google.com/search/?q=how are you">how are you</a>. This is the dummy text

I had no idea so i researched in the google and found one answer in stackoverflow. I tried that code to understand but it did not work to me. I tried to know about treewalk but did not able to make it work. Here is what I have copied

content_script.js (I admit its a copied code)

Here node.textContent is not fetching the email subject and body.

function onLoad() {
    console.log('loaded');
    // document.addEventListener('click', init);
    var re = /Mumbai/g;
    var regs;

    var walker = document.createTreeWalker(
        document.body,
        NodeFilter.SHOW_TEXT,
        function(node) {
            if ((regs = re.exec(node.textContent))) {
                if (!node.parentNode.classList.contains('highlighted_text')) {
                    var match = document.createElement('A');
                    match.appendChild(document.createTextNode(regs[0]));
                    match.href = 'http://www.url.com/';

                    // add an attribute so we know this element is one we added
                    // Im using a class so you can target it with css easily
                    match.classList.add('highlighted_text');

                    var after = node.splitText(regs.index);
                    after.nodeValue = after.nodeValue.substring(regs[0].length);
                    node.parentNode.insertBefore(match, after);
                }
            }
            return NodeFilter.FILTER_SKIP;
        },
        false
    );

    // Make the walker step through the nodes
    walker.nextNode();

    // and it ends here
}

    if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', onLoad);
} else {
    onLoad();
}

here is the manifest

"background": {
  "scripts": [
    "extension/js/background.js"
  ],
  "persistent": true
},
"options_page": "index.html",
"content_scripts": [
  {
    "matches": ["https://mail.google.com/*", "http://mail.google.com/*"],
    "js": ["extension/js/content.js"],
    "css": ["extension/css/main.css"]
  }
],
"permissions": [
  "contextMenus",
  "tabs",
  "storage",
  "https://mail.google.com/*",
  "http://mail.google.com/*"
],
milan
  • 2,409
  • 2
  • 34
  • 71
  • after the hyperlink is created where should it redirect the user ? – user3210641 May 26 '18 at 12:25
  • The snippet you copied works as expected. Simply replace the `var re = /Mumbai/g;` with the word you require and `match.href = 'http://www.url.com/';` with the site you want it to direct to. Or am I missing the problem you have here? – Luka Čelebić May 26 '18 at 12:28
  • it should redirect to something like google.com/?q=thathighlightedtext – milan May 26 '18 at 13:05
  • I bundled it again by replacing that re part as var re = 'Mumbai' and loaded the extension then refreshed the page to see if it creates the link for the text Mumbai or not but it is not working.Also you can see, I have used the console.log('loaded') which is not shown either as soon as the document is loaded – milan May 26 '18 at 13:09
  • That variable is regex, you can't replace it with only a single word that's a string, as for the console.log not showing, you'll have to add your `manifest.json` to the question. – Luka Čelebić May 26 '18 at 13:14
  • i have created a gist as well https://gist.github.com/MilanRgm/60a213478e1d07e1f1be17aead832944 – milan May 26 '18 at 13:14
  • @PredatorIWD I have updated my code. Now the onLoad function runs but still I could not highlight that Mumbai text in the email body. When i consoled, node.textContent it is not fetching that word. Not only that word but none of the text from the email body. – milan May 26 '18 at 14:16

1 Answers1

2

Here is a demo extension that you can examine and then implement logic to your own extension based on it.


As an example, this extension will turn every "da" found inside the page into a link leading to, in this case, "http://www.url.com/".

It will run once when the whole page is loaded and then on every hash change (when you open new mail).

Note: You will need to download jQuery in order for the extension to work.

Manifest.json:

{
  "manifest_version": 2,

  "name": "Example",
  "version": "1.0",

  "content_scripts": [{
    "matches": ["*://mail.google.com/*"],
    "js": ["jquery-3.3.1.min.js", "content.js"]
  }]
}

Content.js

function searchPage() {

    var re = /da/g; // example regex that the function will use for search
    var regs;

    var walker = document.createTreeWalker(
        document.body,
        NodeFilter.SHOW_TEXT,
        function(node) {
            if ((regs = re.exec(node.textContent))) {
                if (!node.parentNode.classList.contains('highlighted_text')) {
                    var match = document.createElement('A');
                    match.appendChild(document.createTextNode(regs[0]));
                    match.href = 'http://www.url.com/';

                    // add an attribute so we know this element is one we added
                    // Im using a class so you can target it with css easily
                    match.classList.add('highlighted_text');

                    var after = node.splitText(regs.index);
                    after.nodeValue = after.nodeValue.substring(regs[0].length);
                    node.parentNode.insertBefore(match, after);
                }
            }
            return NodeFilter.FILTER_SKIP;
        },
        false
    );

    walker.nextNode();
}

// Run when the whole document loads
$(window).bind("load", function() {
    searchPage();
});

// Run on every hash change (when opening new mail)
$(window).on('hashchange', function() {
    searchPage();
});
Luka Čelebić
  • 1,083
  • 11
  • 21
  • Huge thanks for the solution. How did i map this to object instead of single string('da') like I have in the question, topic object? – milan May 28 '18 at 01:16
  • Depends where are you storing or modifying the object. If you need to get it from other parts of the extension you can use [extension messaging](https://developer.chrome.com/extensions/messaging), if you have it hardcoded inside your content.js you can iterate through the object and use the [RegExp Constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) to construct the regex from object values. – Luka Čelebić May 28 '18 at 02:14
  • Which do you recommend? Calling the api from background script and use the extension messaging or calling the api just inside $(window).bind("load", function() {} in content_script. ii) By iterating the object and use RegExp constructor, you mean to say i iteration the object just inside the scope of function(node) and check if it matches or not? I have marked your solution but need help to understand clearly the best way as I am needing this sooner and this is my first try. – milan May 28 '18 at 02:43
  • The shortest possible route is probably the best, it all depends where you get your object from. If you have to call your API from an external source every time you want your content.js to run then call it from there and get the object. In any case, you can then break the object down into any parts from which you can extract the needed data for searching the page and then call the function for each of those words after you have passed them as an argument to that function for example. – Luka Čelebić May 28 '18 at 03:24
  • not sure i understand the "call the function for each of those words after you have passed them as an argument to that function" part. Can you show me a simple example, please? – milan May 28 '18 at 03:47
  • For example, make it so the `searchPage` function takes an argument which is going to set the variable `re`. Then iterate through your `topic` array and call the `searchPage` function for [each value](https://stackoverflow.com/questions/29776996/javascript-apply-a-function-to-each-element-on-array-of-objects) inside it while passing that value to the function. – Luka Čelebić May 28 '18 at 04:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/171902/discussion-between-milan-and-predatoriwd). – milan May 28 '18 at 08:49