Chrome extensions: How to keep badge text from flickering when navigating? - google-chrome

Here's a GIF demo, using a test extension.
I'm using this test extension to test out chrome.browserAction.setBadgeText(). I've noticed that when navigating, the badge text is flickering. All I am doing is clicking any hyperlinks on a webpage, so there's no page refreshing, nor navigating Back.
Is there a way to keep it from flickering? If not, is there a way to keep it persistent for as long as possible?
Code in question:
var SetBadge = function () {
chrome.windows.getCurrent({
populate: true
}, function (win) {
for (let i = 0; i < win.tabs.length; ++i) {
if (win.tabs[i].active) {
chrome.browserAction.setBadgeText({
text: "8",
tabId: win.tabs[i].id
});
}
}
});
};
chrome.webNavigation.onCommitted.addListener(() => {
SetBadge();
});
chrome.webRequest.onSendHeaders.addListener(() => {
SetBadge();
});
chrome.webRequest.onBeforeRedirect.addListener(() => {
SetBadge();
});
chrome.tabs.onActivated.addListener(() => {
SetBadge();
});
chrome.webRequest.onCompleted.addListener(() => {
SetBadge();
});

Related

Chrome Extension embedding script in active web page, in MV3?

beautiful people on the internet. I am new to chrome extension not new to writing code though. I have implemented webpack to use external packages. One major one in my application is npm package by the name "mark.js".
My application works like this i want some specific words to be highlighted in active webpage using this package. I have written code for this to achieve the functionality but the problem is with loading the script in a web page. I have performed different aspect of loading script but that doesnot work. The new MV3 version have some strict rules.
I want to achieve anything similar of loading script in an active webpage. Please help.
btn.addEventListener("click", async () => {
console.log("BUTTON IS PRESSED!!");
try {
await chrome.tabs.query(
{ active: true, currentWindow: true },
async function (tabs) {
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: highlightText,
args: [arr],
});
}
);
} catch (e) {
console.log("ERROR AT CHROME TAB QUERY : ", e);
}
});
async function highlightText(arr) {
console.log(typeof Mark);
try {
var instance2 = new Mark(document.querySelector("body"));
// instance2.mark("is");
var success = [];
// const instance2 = new Mark(document.querySelector("body"));
await Promise.all(
arr.map(async function (obj) {
console.log("OBJECT TEXT : ", obj.text);
instance2.mark(obj.text, {
element: "span",
each: function (ele) {
console.log("STYLING : ");
ele.setAttribute("style", `background-color: ${obj.color};`);
if (obj.title && obj.title != "") {
ele.setAttribute("title", obj.title);
}
ele.innerHTML = obj.text;
success.push({
status: "Success",
text: obj.text,
});
},
});
})
);
console.log("SUCCESS : ", success);
} catch (error) {
console.log(error);
}
}
There's no need to use chrome.runtime.getURL. Since you use executeScript to run your code all you need is to inject mark.js before injecting the function.
Also, don't load popup.js in content_scripts, it's not a content script (these run in web pages), it's a script for your extension page. Actually, you don't need content_scripts at all.
btn.addEventListener('click', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
const target = { tabId: tab.id };
const exec = v => (await chrome.scripting.executeScript({ target, ...v }))[0].result;
if (!await exec({ func: () => !!window.Mark })) {
await exec({files: ['mark.js.min'] });
await exec({func: highlightText, args: [arr] });
}
});
For V3 I assume you will want to use Content Scripts in your manifest to inject the javascript into every webpage it matches. I recently open-sourced TorpedoRead and had to do both V2 and V3, I recommend checking the repo as it sounds like I did something similar to you (Firefox is V2, Chrome is V3).
The code below need to be added to your manifest.json and this will execute on every page based on the matches property. You can read more about content scripts here: https://developer.chrome.com/docs/extensions/mv3/content_scripts/
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["yourscript.js"]
}
],

Chrome extension to iterate all paragraphs in an HTML

Currently my chrome extension is displaying a paragraph (first one), but wanted to iterate all paragraphs in an HTML and display those.
chrome.tabs.query( {
active: true,
lastFocusedWindow: true
},
function(array_of_Tabs) {
chrome.tabs.executeScript(tab.id, {code: "chrome.runtime.sendMessage(document.getElementsByTagName('p')[0].innerHTML);"});
});
chrome.runtime.onMessage.addListener(function(request) {
document.getElementsByTagName('html')[0].innerHTML = request;
});
I wanted to add something like this in the above js. Pls advice.
let paragraphs = document.getElementsByTagName("p");
for(let i = 0; i < paragraphs.length; i++) {
console.log(paragraphs[i].innerText) // Will print the content of each paragraph
}
You can join all the innerHTML's and message that.
chrome.tabs.query({
active: true,
lastFocusedWindow: true
},
function(array_of_Tabs) {
chrome.tabs.executeScript(tab.id, {
code: `chrome.runtime.sendMessage([...document.getElementsByTagName('p')].reduce(function(agg, elem) {agg.push(elem.innerHTML); return agg; }, []).join("\n<br>"));`
});
});
chrome.runtime.onMessage.addListener(function(request) {
document.getElementsByTagName('html')[0].innerHTML = request;
});

PixelCompare method issue

I have an issue with PixelCompare extension.
Here, i am loading it:
viewer1 = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer1'), { extensions: [ 'GoogleMapsLocator', 'Autodesk.AEC.Minimap3DExtension','Autodesk.AEC.LevelsExtension','Autodesk.DocumentBrowser','Autodesk.ToolbarExtension' ,'Autodesk.Viewing.PixelCompare'] });
Then im trying to use it :
viewer1.compareTwoModels(data[0],data[1]);
Data is an array containing the models.
I get a "viewer.compareTwoModels is not a function" error which means either there is a typo in the function name or it doesnt exist.
Without access to the extension repo, i cannot confirm this method indeed exists.
Im at loss as to what to do and will welcome any help.
EDIT:
This snippet loads the document in the viewer to display it.
Autodesk.Viewing.Document.load(`urn:${urns[index]}`, function(doc){
var viewables=doc.getRoot().getDefaultGeometry();
doc.downloadAecModelData();
viewer1.loadDocumentNode(doc, viewables, {
placementTransform: (new THREE.Matrix4()).setPosition({ x: increment, y: 0, z: 0 }),
keepCurrentModels: true,
globalOffset: { x: 0, y: 0, z: 0 }
}).then(i => {
if(urns.length > 1) {
$(viewer1.toolbar.container).find('#toolbarXLS').hide();
}
});
increment += parseInt(sessionStorage.getItem('padding1'));
});
Then, im using this to pixel compare it:
viewer1.loadModel('urn:dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLmwwLS10X0k5UkVhbnNWRXBuLXl5Zmc_dmVyc2lvbj0x', {}, (model1) => {
console.log('test load model :' + model1)
viewer1.loadModel('urn:dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLmxXX0dONUJNVDBxdDRuOGZmRWx4SkE_dmVyc2lvbj0x', {}, async (model2) => {
const pcExt = await viewer1.loadExtension('Autodesk.Viewing.PixelCompare');
pcExt.compareTwoModels(model1, model2);
console.log()
});
});
I get an instant "file extension unsupported" error, probably on the first argument the code does not reach console.log('test load model :' + model1).
The function compareTwoModels is part of the extension object, not the viewer - see PixelCompare extension
function launchViewer() {
var options = {
env: 'Local'
};
Autodesk.Viewing.Initializer(options, () => {
viewer = new Autodesk.Viewing.GuiViewer3D(
document.getElementById('forgeViewer'), {}
);
viewer.start();
// Load 2 sheets
viewer.loadModel('scissors1.pdf', {}, (model1) => {
viewer.loadModel('scissors2.pdf', {}, async (model2) => {
// Compare them
const pcExt = await viewer.loadExtension('Autodesk.Viewing.PixelCompare');
pcExt.compareTwoModels(model1, model2);
});
});
});
}

dragAndDrop in selenium javascript

dragAndDrop()
How to do dragAndDrop in selenium with javascript?
element drag and drop sorting
I hope this works for you.
let actions = driver.actions({async: true, bridge:true});
await driver.findElements(By.css('.box2'))
.then(async(firstBoxes) => {
for (firstBox of firstBoxes) {
await actions.move({async: true, origin:firstBox}).press().perform();
await driver.findElements(By.css('.box1'))
.then(async(boxes) => {
for (secbox of boxes) {
await actions.dragAndDrop(firstBox, secbox).release().perform();
}
});
}
});

Chrome.storage.sync.get() seems to be duplicating keys?

I am saving some settings using the following sequence
var getSettings = async function() {
var settings;
try {
settings = await authenticatedGET(server_url + SETTINGS_ENDPOINT);
return settings;
} catch (error) {
console.log("Settings Fetch Failed: " + error);
throw new Error(error);
}
}
const setLocalSettings = function(settings) {
chrome.storage.sync.set({ 'LML_Settings': JSON.parse(settings) }, function() {
console.log("Settings saved locally");
});
}
At the line right after the setLocalSettings function definition, the 'settings' object logs out as
{"email_format":"individual","close_tab":true,"frequency":"DAILY"} (correctly as intended). When I go to fetch the settings using this sequence:
chrome.storage.sync.get('LML_Settings', function(LMLSettingsContainer) {
console.log(LMLSettingsContainer);
if (LMLSettingsContainer.LML_settings.close_tab == "true") {
closeCurrentTab();
}
})
LMLSettingsContainer logs out as
{
"LML_Settings": {
"close_tab": true,
"email_format": "individual",
"frequency": "DAILY"
}
}
accessing my settings with LMLSettingsContainer.LML_Settings["<setting>"] is a bit annoying (and its the whole reason I named the top variable LMLSettingsContainer).
Does anyone know if there's a way to have chrome save/get these values unwrapped?
chrome.storage.sync.get('LML_Settings', ({LML_settings}) => { ... }) works, per #wOxxOm