Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

javascript - How to replace email addresses with mailto links in a live web page?

Imagine this: you come across a webpage that says "Just send a message to [email protected]" but to actually send the email, you need to highlight the address and then cut and paste it into the recipient field of a new compose window of your email client of choice.

Obviously life would be easier if it were simply a mailto: link, so you could click on it and have a new message created automatically. How do I build an extension that turns email addresses into clickable mailto: links?

I was originally going to ask if there was an extension to enable similar functionality for unlinked Twitter @username mentions but I thought this email address problem would be a simpler situation.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

Use innerHTML to replace the email - No, this breaks page's, especially because event listeners are removed and attributes are also replaced.

Recursively loop through all nodes:

  • Loop in the reverse order, to prevent conflicts when you modify the DOM.
  • For each item, check it's nodeType value.
    • If .nodeType === 1 (element), call the function again (recursion).
    • If .nodeType === 3 (text node):
      1. Use a regular expression and the exec method to find one email address. Use the result's .index property to know the starting position of the email address, and result[0].length to know the length of the address.
      2. Use the node's splitText method cut the text node in three parts.
      3. Create an <a> element.
      4. Append the email's text node (the second text node from the previous) to this anchor. It's automatically removed from the document.
      5. Insert this link before the third node.

Demo

Not a chrome extension, but it shows how a chrome extension would behave: http://jsfiddle.net/ckw89/

Chrome extension

(the regexp is based on MongoEngine's EmailField pattern):

script.js

 // Initiate recursion
 wrapLink(document.body);

 function wrapLink(elem) { // elem must be an element node
     var nodes = elem.childNodes
       , i = nodes.length
       , regexp = /([-!x23$%&'*+/=?^_`{}|~0-9A-Z]+(.[-!x23$%&'*+/=?^_`{}|~0-9A-Z]+)*|^"([x01-x08x0bx0cx0e-x1f!x23-\[\]-x7f]|\[x01-011x0bx0cx0e-x7f])*")@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?.)+[A-Z]{2,6}/i
       , node, emailNode, a, result;
     while (node = nodes[--i]) {
         if (node.nodeType === 1) {
             // Skip anchor tags, nested anchors make no sense
             if (node.nodeName.toUpperCase() !== 'A')
                wrapLink(node);
         } else if (node.nodeType === 3) {
             // 1: Please note that the regexp has NO global flag,
             //    and that `node.textContent` shrinks when an address is found
             while (result = regexp.exec(node.textContent)) {
                 // 2: Contact <SPLIT> [email protected] for details
                 node = node.splitText(result.index);

                 // 2: Contact <SPLIT>[email protected]<SPLIT> for details
                 node = node.splitText(result[0].length);

                 // [email protected]
                 emailNode = node.previousSibling

                 // 3. Create link
                 a = document.createElement('a');
                 a.href = 'mailto:' + result[0];

                 // 4: Append emailNode
                 a.appendChild(emailNode);

                 // 5: Insert before
                 elem.insertBefore(a, node);
             }
         }
     }
 }

This script will work immediately when used as a Content script, because its only interaction with the page is the DOM. For completeness, here's the contents of the manifest.json file:

{
    "name": "Turns email addresses in `mailto:`s",
    "version": "1",
    "version_version": 2,
    "content_scripts": [{
        "matches": ["*://*/*"],
        "js": ["script.js"]
    }]
}

Performance notice

The current script replaces all nodes in the live document. Consider moving the root node (eg <body>) to a document fragment before manipulating.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...