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.