How to change of web page content from a Google Chrome extension - google-chrome-extension

I am writing extension which will underline accent in English words on web pages.
I've got stuck after I click "Search" button on popup, nothing seems to happen.
Here's the scenario:
user double click a word on a web page.
the whole word is marked.
user clicks extension icon on chrome browser bar.
a popup is shown. Input field in popup is filled in with the marked word.
user adds accent. Ie. if marked word is 'boundary', in popup's input field there will be: 'boudary' displayed. Then user modify the input value to: 'boudary,bo' (without quotes).
user click "Search" button on popup.
letters "bo" in "boundary" word on page are being underlined.
manifest.json
{
"content_scripts": [ {
"js": [ "jquery.js", "jquery.highlight-4.js", "selection.js" ],
"matches": [ "\u003Call_urls\u003E" ]
} ],
"name": "Mark accent",
"version": "1.0",
"manifest_version": 2,
"options_page": "options.html",
"description": "Marks accent in english words for selected word on page",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"icons": {
"128": "icon.png"
},
"permissions": [ "tabs", "http://*/*", "https://*/*", "storage", "file:///*" ]
}
app.js
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: "getSelection"}, function (response) {
$("#t1").val(response.data);
console.log('input t1 value: ' + $("#t1").val(response.data));
});
});
$("#t1").keypress(function(event) {
if ( event.which == 13 ) {
$("#search_btn").click();
}
});
$("#t1").focus();
function search(that) {
var token = new String (t1.value);
chrome.tabs.executeScript(null,
{code:"$(document.body).highlight('"+token+"','text-decoration:underline')"});
window.close();
}
selection.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == "getSelection")
sendResponse({data: window.getSelection().toString()});
else
sendResponse({}); // snub them.
});
popup.html
<style>
body {
overflow: hidden; margin: 5px; padding: 0px; background: black;color: white;
width: 300px; font-family: 'Droid Sans', arial, sans-serif;
}
</style>
Please enter the word to highlight :
<input type="text" id="t1"/>
<button onclick="search(this)" id="search_btn">Search</button>
<button onclick="hl_clear(this)" id="clear_btn">Clear all highlights</button>
<script src="jquery.js"></script>
<script src="jquery.highlight-4.js"></script>
<script src="app.js"></script>
jquery.highlight-4.js
jQuery.fn.highlight = function(pat, fbgcolor) {
function innerHighlight(node, pat, fbgcolor) {
var skip = 0;
var array = pat.split(',');
var sWord = array[0];
var accent = array[1];
if (node.nodeType == 3) {
var pos = node.data.toUpperCase().indexOf(sWord);
if (pos >= 0) {
var middlebit = node.splitText(pos);
var endbit = middlebit.splitText(sWord.length);
var pos2 = middlebit.data.toUpperCase().indexOf(accent);
if (pos2 >= 0) {
var spannode = document.createElement('span');
spannode.className = 'highlight';
fbgcolor += ";padding: 0px; margin: 0px;";
spannode.setAttribute('style', fbgcolor);
var middlebit2 = middlebit.splitText(pos2);
var endbit2 = middlebit2.splitText(accent.length);
var middleclone2 = middlebit2.cloneNode(true);
spannode.appendChild(middleclone2);
middlebit2.parentNode.replaceChild(spannode, middlebit2);
}
skip = 1;
}
}
else if (node.nodeType == 1 && node.childNodes &&
!/(script|style)/i.test(node.tagName)) {
for (var i = 0; i < node.childNodes.length; ++i) {
i += innerHighlight(node.childNodes[i], pat, fbgcolor);
}
}
return skip;
}
return this.each(function() {
innerHighlight(this, pat.toUpperCase(), fbgcolor);
});
};

It is working after so many modifications and eliminated non-chrome extension related content. You can add your content to this skeleton.
Do not add Inline scripts in html
<button onclick="search(this)" id="search_btn">Search</button>
Basic Skeleton of your code:
manifest.json
{
"content_scripts": [ {
"js": [ "jquery.js", "jquery.highlight-4.js", "selection.js" ],
"matches": [ "<all_urls>" ]
} ],
"name": "Mark accent",
"version": "1.0",
"manifest_version": 2,
"description": "Marks accent in english words for selected word on page",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"icons": {
"128": "icon.png"
},
"permissions": [ "tabs", "<all_urls>" ]
}
app.js
function search(that) {
console.log("Search is clicked");
var token = document.getElementById("t1").value;
console.log(token);
chrome.tabs.executeScript(null,
{code:"highlight();"});
//window.close();
}
window.onload=function (){
document.getElementById("search_btn").onclick=search;
};
selection.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == "getSelection")
sendResponse({data: window.getSelection().toString()});
else
sendResponse({}); // snub them.
});
popup.html
<html>
<head>
<style>
body {
overflow: hidden; margin: 5px; padding: 0px; background: black;color: white;
width: 300px; font-family: 'Droid Sans', arial, sans-serif;
}
</style>
<script src="jquery.js"></script>
<script src="app.js"></script>
<body>
Please enter the word to highlight :
<input type="text" id="t1"/>
<button id="search_btn">Search</button>
<button id="">Clear all highlights</button>
</body>
</html>
jquery.highlight-4.js
function highlight(){
console.log("Highlight is called");
}
Let me know if it is still failing.

Related

How to modify html element on page load in Chrome extension

I have a button element on the popup.html file that I want to modify on page load via the content.js file. However, when I tried the below code it did not work (text button text does not change).
How do I change the button text when the content loaded?
popup.html:
<html>
<body>
<button id="to-modify-button">no text</button>
<script src="popup.js"></script>
</body>
</html>
popup.js:
const btn = document.getElementById("to-modify-button");
chrome.runtime.onMessage.addListener(function (
request,
sender,
sendResponse
) {
if (request.theme === "dark") {
btn.textContent = "Disable dark mode";
} else {
btn.textContent = "Enable dark mode";
}
});
content.js:
(() => {
chrome.runtime.sendMessage({ theme: "dark" });
})();
You can't push to popup. pull from popup.
manifest.json
{
"name": "content_scripts + popup",
"version": "1.0",
"manifest_version": 3,
"content_scripts": [
{
"js": [
"content.js"
],
"matches": [
"<all_urls>"
]
}
],
"action": {
"default_popup": "popup.html"
}
}
popup.html
<html>
<body>
<button id="to-modify-button">no text</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
const btn = document.getElementById("to-modify-button");
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, "message", (response) => {
console.log(response);
if (response.theme === "dark") {
btn.textContent = "Disable dark mode";
} else {
btn.textContent = "Enable dark mode";
}
});
});
content.js
console.log("content.js");
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log(message);
sendResponse({ theme: "dark" });
return true;
});

Chrome Extension Manifest V3 Visual Problems

The weirdest thing is happening;
With my extension enabled, certain web pages appear normally, but the non-visible parts have their background color changed to black. So, everything looks fine until you scroll. Here's an example with my extension enabled:
Here it is with my extension turned off:
Again, this only happens for some web pages (many are fine) and only for their non-visible (i.e., scrollable) parts.
The only DOM manipulation happening is in popup.js, which, anyway I believe doesn't fire unless you click the extension icon (right?). And by "DOM manipulation", I mean:
document.getElementById('getStartedBtn').innerHTML = "Sign out";
document.getElementById('getStartedBtn').style.color = '#fff';
... nothing more. There's nothing in my contentScript.js nor background.js (which, anyway, is the background service worker).
In terms of manifest.json permissions, this is what I have:
"permissions": [
"contextMenus",
"activeTab",
"identity"
]
-- EDIT --
As requested, here's the complete manifest.json:
{
"manifest_version": 3,
"name": "XXX",
"version": "1.0.3",
"description": "XXX",
"icons": {
"16": "icons/icon_16.png",
"32": "icons/icon_32.png",
"48": "icons/icon_48.png",
"128": "icons/icon_128.png"
},
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "XXX",
"default_popup": "popup.html"
},
"permissions": [
"contextMenus",
"activeTab",
"identity"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"run_at": "document_start",
"js": ["contentScript.js"],
"css": ["contentScript.css"]
}
],
"oauth2": {
"client_id": "XXX.apps.googleusercontent.com",
"scopes":["openid", "email", "profile"]
},
"key": "XXX"
}
Here's the complete popup.js:
'use strict';
import './popup.css';
import '#lottiefiles/lottie-player';
///////////////////////////////////////////////////
// Events
// Fire every time extension icon is clicked
document.addEventListener('DOMContentLoaded', updateButtonText);
document.getElementById('getStartedBtn').addEventListener('click', () => {
document.getElementById('getStartedBtn').style.color = '#1fa3ec';
document.getElementById('getStartedBtn').classList.add("button--loading");
getStarted();
});
///////////////////////////////////////////////////
// Event logic
const subscriptionHTML = 'Subscribe for $1.';
function updateButtonText() {
// Send msg to background
chrome.runtime.sendMessage({ type: 'isUserSignedIn' }, (response) => {
if (response.response === 'YES') {
document.getElementById('getStartedBtn').innerHTML = "Sign out";
document.getElementById('signedInAsLbl').innerHTML = `Signed in as ${response.email}`;
document.getElementById('getASubscriptionLbl').innerHTML = "";
} else {
document.getElementById('getStartedBtn').innerHTML = "Sign in";
document.getElementById('signedInAsLbl').innerHTML = "";
document.getElementById('getASubscriptionLbl').innerHTML = subscriptionHTML;
}
document.getElementById('getStartedBtn').style.color = '#fff';
document.getElementById('getStartedBtn').classList.remove("button--loading");
});
}
function getStarted() {
// Send msg to background
chrome.runtime.sendMessage({type: 'getStarted', payload: { message: "Let's get started!"}}, (response) => {
if (response.response === 'YES') {
document.getElementById('getStartedBtn').innerHTML = "Sign out";
document.getElementById('signedInAsLbl').innerHTML = `Signed in as ${response.email}`;
document.getElementById('getASubscriptionLbl').innerHTML = "";
} else if (response === 'NO') {
document.getElementById('getStartedBtn').innerHTML = "Sign in";
document.getElementById('signedInAsLbl').innerHTML = "";
document.getElementById('getASubscriptionLbl').innerHTML = subscriptionHTML;
}
document.getElementById('getStartedBtn').style.color = '#fff';
document.getElementById('getStartedBtn').classList.remove("button--loading");
});
}
And here's button--loading CSS class from popup.css, responsible for a loading spinning circle on the sign in/out button:
.button--loading::after {
content: "";
position: absolute;
width: 16px;
height: 16px;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
border: 4px solid transparent;
border-top-color: #ffffff;
border-radius: 50%;
animation: button-loading-spinner 1s ease infinite;
}
#keyframes button-loading-spinner {
from {
transform: rotate(0turn);
}
to {
transform: rotate(1turn);
}
}
Any ideas? I can't see why this is happening.

Create iframe using Google Chrome Extension manifest v3

I'm migrating an extension from manifest v2 to manifest v3 (and refactor and redesign...)
In the old version we were using an iframe within the tab, like this:
background.js
const open = () => {
const oldIframe = document.getElementById('cm-frame');
if (oldIframe) {
oldIframe.remove();
return;
}
const iframe = document.createElement('iframe');
iframe.setAttribute('id', 'cm-frame');
iframe.setAttribute('style', 'top: 10px;right: 10px;width: 450px;height: 100%;z-index: 2147483650;border: none; position:fixed;');
iframe.setAttribute('allow', '');
iframe.src = chrome.extension.getURL('index.html');
iframe.frameBorder = 0;
document.body.appendChild(iframe);
};
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.executeScript({
code: '(' + open.toString() + ')();'
}, () => { });
});
I've tried the same approach using chrome.actions.onClicked.addListener with chrome.scripting.executeScript and had no luck.
I know we could just use a popup ("default_popup": "popup.html",) but the iframe works better in terms of integration and design.
I was able to make it work.
background.js
chrome.action.onClicked.addListener(async function (tab) {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
const oldIframe = document.getElementById('cm-frame');
if (oldIframe) {
oldIframe.remove();
return;
}
const iframe = document.createElement('iframe');
iframe.setAttribute('id', 'cm-frame');
iframe.setAttribute(
'style',
'top: 10px;right: 10px;width: 400px;height: calc(100% - 20px);z-index: 2147483650;border: none; position:fixed;'
);
iframe.setAttribute('allow', '');
iframe.src = chrome.runtime.getURL('popup.html');
document.body.appendChild(iframe);
},
});
});
This my manifest.json file in case someone also needs it (I had to add stuff to permissions and web_accessible_resources to make it work and load correctly):
{
"manifest_version": 3,
"name": "Contact Mapping Extension",
"background": { "service_worker": "background.bundle.js" },
"action": {
"default_icon": "icon-34.png"
},
"icons": {
"128": "icon-128.png"
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*", "<all_urls>"],
"js": ["contentScript.bundle.js"],
"css": ["content.styles.css"]
}
],
"web_accessible_resources": [
{
"resources": ["content.styles.css", "icon-128.png", "icon-34.png", "popup.html"],
"matches": ["<all_urls>"]
}
],
"permissions": [
"tabs",
"activeTab",
"scripting"
]
}

Basic Google Chrome Extension Noob Question

I am trying to create a basic Google Chrome Extension that simply copies the source HTML code on the page I am on. I have never created a Chrome extension and I am really stuck and would appreciate some help. I started the extension using the Chrome guide and from what I have read on the internet is I content scripts to access the webpage. I don't know how to call the content scripts however. I tried using import statements but I received errors - I think I am really misunderstanding how the whole thing works. I am trying to also get the console log to display in the webpage console, instead of the chrome extension console.
popup.html
<!DOCTYPE html>
<html>
<head>
<style>
button {
height: 30px;
width: 30px;
outline: none;
}
</style>
</head>
<body>
<button id="changeColor"></button>
<script src="popup.js"></script>
</body>
</html>
manifest.json
"name": "Company Websites",
"version": "1.0",
"description": "Build an Extension!",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["content.js"]
}
],
"page_action": {
"default_popup": "popup.html"
},
"permissions": ["storage","declarativeContent"],
"manifest_version": 2
}
content.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("changeColor").addEventListener("click", handler);
});
// The handler also must go in a .js file
function handler() {
console.log("hello?");
//somehow copy source code
}
background.js
chrome.runtime.onInstalled.addListener(function() {
chrome.storage.sync.set({color: '#3aa757'}, function() {
console.log("The color is green.");
});
});
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
pageUrl: {hostEquals: '* insert target web address*'},
})
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
Any help would be appreciated!
Make another file called load.js and do an XML HttpRequest, then include it in the popup.html.
popup.html
<script src="load.js"></script>
load.js
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var data = xhttp.responseText;
}}
xhttp.open("GET", "website url", true);
xhttp.send();
}
loadDoc()
From there you can store and retrieve it in local storage, console.log(data), or use it in document.getElementById('ID').innerHTML = data

removeListener в Chrome extension not working

Here is the contents of background.js:
var toggle = false;
chrome.browserAction.onClicked.addListener(function(tab) {
toggle = !toggle;
if(toggle) {
var start_working = function() {
chrome.tabs.query({ url: ["http://*/*","https://*/*"], currentWindow: true }, function (tabs) {
for (var i = 0; i < tabs.length; i++) {
chrome.tabs.executeScript(tabs[i].id, {code : "var enabled = 1;"});
chrome.tabs.executeScript(tabs[i].id, {file: 'js/new.js'});
chrome.browserAction.setIcon({path: "add48.png", tabId:tabs[i].id});
}
});
}
if (!chrome.tabs.onUpdated.hasListener(start_working)) {
chrome.tabs.onUpdated.addListener(start_working);
chrome.tabs.query({url: ["http://*/*","https://*/*"]}, function (tabs) {
console.log('1start_working='+chrome.tabs.onUpdated.hasListener(start_working));
console.log('1toggle='+toggle);
for (var i = 0; i < tabs.length; i++) {
chrome.tabs.executeScript(tabs[i].id, {code : "var enabled = 1;"});
chrome.tabs.executeScript(tabs[i].id, {file: 'js/new.js'});
chrome.browserAction.setIcon({path: "add48.png", tabId:tabs[i].id});
}
}
);
}
} else {
chrome.tabs.onUpdated.removeListener(start_working);
console.log('2start_working='+chrome.tabs.onUpdated.hasListener(start_working));
console.log('2toggle='+toggle);
chrome.tabs.query({url: ["http://*/*","https://*/*"], currentWindow: true }, function (tabs) {
for (var i = 0; i < tabs.length; i++) {
chrome.tabs.executeScript(tabs[i].id, {code : "var enabled = 0; $('#sort_g').remove();"});
chrome.browserAction.setIcon({path: "add48_off.png", tabId:tabs[i].id});
}
}
);
return false;
}
});
Here is the code of manifest.json:
{
"manifest_version": 2,
"name": "Ds",
"version": "0.2",
"background": {
"scripts": ["background.js"]
},
"icons": {
"48": "add48.png",
"128": "add128.png"
},
"browser_action": {
"default_icon": "add48_off.png"
},
"permissions": [
"tabs",
"notifications",
"*://*/*"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/jquery-2.2.4.min.js"],
"run_at": "document_end",
"all_frames": true
}
],
"web_accessible_resources": ["tpl/panel.html"]
}
When we click on the application icon, we add an element to all the HTML tabs and make the icon "active", and when we click the icon again, we change the icon to gray and remove the html element from all pages.
Also, when updating the html tab, the element should again appear and the extension icon should be active.
All this is implemented, but after disabling the extension, an html element still appears, although the new.js script should not be connected and chrome.tabs.onUpdated.hasListener(start_working)=false
Here's the log after disabling the extension:
background.js:49 2start_working=false
background.js:50 2toggle=false
But when updating the tab anyway, the html element appears on the page
I can not understand why this happens? Moreover, the console shows that after disabling the extension, when updating the page, the new.js script is connected already 3 times.

Resources