用包含该文本的按钮替换网页段落中的每个单词 [英] Replace each word in webpage's paragraphs with a button containing that text

查看:75
本文介绍了用包含该文本的按钮替换网页段落中的每个单词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Google Chrome扩展程序,其中包含所有段落(p标签内容),并将每个单词放在一个按钮中。这是我正在开展的一个更大的计划的一部分。我有



manifest.json

  {
description注入内容脚本以使< p>元素按钮中的所有单词,
manifest_version:2,
name:按钮< p>中的所有单词,
版本:0.1,

权限:[
activeTab
],

背景:{
scripts:[
background.js
]
},

browser_action:{
default_icon:{
32:myIcon.png
},
default_title:Make Buttons
}
}

background.js

  chrome.browserAction.onClicked .addListener(function(tab){
//注入脚本以更改< p>按钮
chrome.tabs.executeScript(tab.id,{file:'contentScript.js'});
});

contentScript.js

 (function(){
function handleTextNode(textNode){
if(textNode.nodeName!文本'
|| textNode.parentNode.nodeName ==='SCRIPT'
|| textNode.parentNode.nodeName ==='STYLE'
){
// Don'不要做任何事情,除非是文本节点,而不是< script>或< style>
return;
}
let origText = textNode.textContent ;
let newHtml = origText.replace(/(^ | \s)(\S +)(?= \s | $)/ mg,'$ 1< button> $ 2< / button> );
//如果我们在文本中实际替换了,只能更改DOM
//比较字符串,因为它应该比第二个RegExp操作快,而
//让我们在一个地方使用RegExp可维护性
if(newHtml!== origText){
let newSpan = document.createElement('span');
newSpan.innerHTML = newHtml;
textNode.parentNode.replaceChild(newSpan,textNode);
}
}

//查找< p>的所有文本节点后代元素:
let allP = document.querySelectorAll('p'); //获取全部< p>
let textNodes = [];
for(let p of allP){
//创建一个NodeIterator来获取每个< p>的文本节点后代
let nodeIter = document.createNodeIterator(p,NodeFilter.SHOW_TEXT);
let currentNode;
//添加发现的文本节点到下面要处理的文本节点列表。
while(currentNode = nodeIter.nextNode()){
textNodes.push(currentNode);
}
}
//处理每个文本节点
textNodes.forEach(function(el){
handleTextNode(el);
});
})();

myIcon.png





handleTextNode中的代码对文本节点进行的更改已从我的另一个答案的代码修改。


I'm working on a Google Chrome extension that takes all the paragraphs (p tag content) and places each words in them up into a button. It's a part of a larger program I'm working on. I have a working copy of that part of the app on JSFiddle.

Now, I'm trying to port that code into a Chrome Extension. But, I'm having trouble accessing the DOM from my background script, so that I can manipulate it with my code (in my function FormatText()). I haven't even called the function yet, because I can't figure out how I'm supposed to edit the DOM in the first place within background.js.

Here is my code:

manifest.json

{
  "manifest_version": 2,
  "name": "Test Extension",
  "version": "1",
  "background": {
    "persistent": false,
    "scripts": ["background.js","jquery-3.0.0.min.js","TextSplitter.js"]
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"]
  }],
  "browser_action": {
    "default_title": "Test Extension"
  },
  "permissions": ["activeTab","tabs"]
}

content.js

// Listen for messages
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
    // If the received message has the expected format...
    if (msg.text === 'report_back') {
        // Call the specified callback, passing
        // the web-page's DOM content as argument
        sendResponse(document);
    }
});

background.js

// A function to use as callback
function doStuffWithDom(domContent) {
    console.log('I received the following DOM content:\n');
    console.log(JSON.stringify(domContent));
    var domAccess = $(domContent);
    var myText = $(domAccess).find("p").text();
    console.log("THIS IS MY TEXT: " + myText);
}

chrome.tabs.onUpdated.addListener(function (tabID, info, tab) {
    console.log("Status: " + info.status);
    if (info.status == "complete") {
        chrome.tabs.sendMessage(tab.id, { text: 'report_back' }, doStuffWithDom);
    }
});

TextSplitter.js

function FormatText(domObject) {
    var pElements = []; // Holds the split paragraphs for each p tag
    var pElementIndex = 0;

    //Loop through each p tag in web page
    $("p").each(function (webPElementIndex, webPElement) {
        var jQObjWebPElement = $(webPElement);// Convert p element to jQuery Obj
        // split current paragraph element text into an array of seperate words
        pElements[webPElementIndex] = jQObjWebPElement.text().split(" ");
    });

    //Clear text out of all p elements
    $("p").empty();

    //Loop through p elements in the webpage to add back text with spans around each word
    $("p").each(function (webPElementIndex, webPElement) {
        // convert current web page element to jQuery Obj
        var jQObjWebPElement = $(webPElement);
        // Loop through each word stored in each stored paragraph element
        $.each(pElements[pElementIndex], function (pElementWordIndex, pElementWord) {
            var jQObjPElementWord = $(pElementWord); // convert element to jQuery object
            jQObjWebPElement.append($("<button>")
                            .text(pElements[pElementIndex][pElementWordIndex]));
        });
        pElementIndex = pElementIndex + 1;
    });
}

Please pardon my ignorance as I am very new to working with the DOM in general, especially in a Chrome extension.

解决方案

Your code appears overly complex in a few areas. In particular, the DOM can only be manipulated from a content script. As wOxxOm mentioned in a comment, it would be a good idea for you to read the Chrome extension architecture overview. It has overall architecture information which should help your understanding of how things are generally done/organized.

The following complete extension (tested on Chrome and Firefox) changes all non-whitespace characters surrounded by a whitespace character (or the start or end of a line/paragraph) to be within a <button>. It does this when an actionButton is clicked in the browser user interface.

When the actionButton is clicked, the contentScript.js file is injected. The content script makes the changes and exits. For this functionality, there is no need for a content script that is sitting in the page waiting to get a message to perform a simple function. You may actually be doing more than you have described/shown with code, but for the functionality mentioned in the Question, injecting the script with tabs.executeScript() is a better, less complicated, and more efficient choice.

I chose not to use jQuery. jQuery is good for many things. In this instance, I did not like the trade-off of loading 90 KiB of code to save just a few characters instead of accomplishing the same thing with stock JavaScript.

I did not take a good look at the code you are using to perform your button-ization. I already had code in another answer which could be easily adapted to perform this task. Given that your question was about how to manipulate the DOM, not about the functionality of your button-ization code, I chose to use the code I was already familiar with.

The extension in action:

manifest.json

{
    "description": "Inject content script to make all words in <p> elements buttons",
    "manifest_version": 2,
    "name": "Button all words in <p>",
    "version": "0.1",

    "permissions": [
        "activeTab"
    ],

    "background": {
        "scripts": [
            "background.js"
        ]
    },

    "browser_action": {
        "default_icon": {
            "32": "myIcon.png"
        },
        "default_title": "Make Buttons"
    }
}

background.js:

chrome.browserAction.onClicked.addListener(function(tab) {
    //Inject the script to change the text in <p> to buttons
    chrome.tabs.executeScript(tab.id,{file: 'contentScript.js'});
});

contentScript.js:

(function(){
    function handleTextNode(textNode) {
        if(textNode.nodeName !== '#text'
            || textNode.parentNode.nodeName === 'SCRIPT' 
            || textNode.parentNode.nodeName === 'STYLE'
        ) {
            //Don't do anything except on text nodes, which are not children 
            //  of <script> or <style>.
            return;
        }
        let origText = textNode.textContent;
        let newHtml=origText.replace(/(^|\s)(\S+)(?=\s|$)/mg, '$1<button>$2</button>');
        //Only change the DOM if we actually made a replacement in the text.
        //Compare the strings, as it should be faster than a second RegExp operation and
        //  lets us use the RegExp in only one place for maintainability.
        if( newHtml !== origText) {
            let newSpan = document.createElement('span');
            newSpan.innerHTML = newHtml;
            textNode.parentNode.replaceChild(newSpan,textNode);
        }
    }

    //Find all text node descendants of <p> elements:
    let allP = document.querySelectorAll('p');  // Get all <p>
    let textNodes = [];
    for (let p of allP) {
        //Create a NodeIterator to get the text nodes descendants of each <p>
        let nodeIter = document.createNodeIterator(p,NodeFilter.SHOW_TEXT);
        let currentNode;
        //Add text nodes found to list of text nodes to process below.
        while(currentNode = nodeIter.nextNode()) {
            textNodes.push(currentNode);
        }
    }
    //Process each text node
    textNodes.forEach(function(el){
        handleTextNode(el);
    });
})();

myIcon.png:

The code in handleTextNode to make changes to text nodes was modified from code in another answer of mine.

这篇关于用包含该文本的按钮替换网页段落中的每个单词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆