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

后端 未结 1 1429
栀梦
栀梦 2020-12-06 08:36

Imagine this: you come across a webpage that says \"Just send a message to user@example.com\" but to actually send the email, you need to highlight the address and then cut

相关标签:
1条回答
  • 2020-12-06 09:14

    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-\x08\x0b\x0c\x0e-\x1f!\x23-\\[\\]-\x7f]|\\[\x01-011\x0b\x0c\x0e-\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> me@example.com for details
                     node = node.splitText(result.index);
    
                     // 2: Contact <SPLIT>me@example.com<SPLIT> for details
                     node = node.splitText(result[0].length);
    
                     // me@example.com
                     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.

    0 讨论(0)
提交回复
热议问题