I'm trying my hand at a simple Chrome Extension, but I've hit a snag.
I'm trying to autofill a login form (username and password). (As backup in case the chrome autofill functionality is disabled)
I've managed to inject a script into the page and I can console.log the input I'm targeting. But it won't set the value.
Manifest.json
{
"manifest_version": 2,
"name": "Test Extension",
"description": "Test Extension",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "index.html"
},
"content_scripts": [
{
"matches": [ "*://*.domain.net/*" ],
"js": [ "autofill.js" ]
}
],
"permissions": [
"tabs",
"*://*.domain.net/*"
]
}
autofill.js
console.log( "Script properly injected into page" );
let usernameInput = document.querySelector( 'input[name="username"]' );
let passwordInput = document.querySelector( 'input[name="password"]' );
console.log( usernameInput );
usernameInput.value = "test";
What am I missing here?
Apparently, the issue was with the autofill functionality of Chrome. Setting the autocomplete attribute to off, false or new-password in case of the password didn't work for me. Chrome seems to ignore this.
Disabling Chrome Autofill
My solution was to add a small timeout before executing my code. It's far from ideal, but it works.
setTimeout( () => {
usernameInput.value = "username";
passwordInput.value = "password"
}, 500 );
The problem is almost certainly that you need to wait for the document loaded event. As it is, your script has finished before the elements are loaded on the page.
Make your autofill.js
console.log( "Script properly injected into page" );
document.addEventListener('DOMContentLoaded', function () {
let usernameInput = document.querySelector( 'input[name="username"]' );
let passwordInput = document.querySelector( 'input[name="password"]' );
console.log( usernameInput );
usernameInput.value = "test";
});
Related
Before you read this, it may be related to
How can a Chrome extension get a user's permission to use user's computer's microphone?
I've added an answer below, including code and my manifest, if that helps.
I am writing a minimal Chrome Extension (using Chrome 75.0.3770.90 on MacOS 10.14.5) to implement a 'listen' button for my accessibility project. I've written an HTML version with the JavaScript which works the microphone.
However, when I lift that code into the Extension background.js file, the text-to-speech works, but not the speech-to-text. The code runs, but the flashing mic never appears in the tab.
The code which works is:
<!DOCTYPE html>
<html>
<body>
<h2>All-in-one JavaScript Example</h2>
<button onclick="myCode();">Listen</button>
<script>
window.SpeechRecognition = window.webkitSpeechRecognition
|| window.SpeechRecognition;
function myCode() {
recognition = new SpeechRecognition();
recognition.start();
recognition.onresult = function(event) {
if (event.results[0].isFinal) {
response = event.results[0][0].transcript;
synth = window.speechSynthesis;
synth.speak( new SpeechSynthesisUtterance(
"i don't understand, "+response
));
} }
alert( "all-in-one: we're done!" );
}
</script>
</body>
</html>
Minimal reproducible example:
{
"name": "myName",
"description": "Press to talk",
"version": "0.97",
"manifest_version": 2,
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": ["contentSettings","desktopCapture","*://*/*","tabCapture","tabs","tts","ttsEngine"],
"browser_action": {
"default_icon": "images/myIcon512.png",
"default_title": "Press Ctrl(Win)/Command(Mac)+Shift+ Down to speak"
},
"commands": {
"myCommand": {
"suggested_key": {
"default": "Ctrl+Shift+Down",
"mac": "Command+Shift+Down"
},
"description": "Start speaking"
}
},
"icons": {
"512": "images/myIcon512.png"
}
}
My background JavaScript is:
window.SpeechRecognition = window.webkitSpeechRecognition || window.SpeechRecognition;
function myCode() {
var recognition = new SpeechRecognition();
recognition.onresult = function(event) {
if (event.results[0].isFinal) {
var synth = window.speechSynthesis;
synth.speak( new SpeechSynthesisUtterance(
"sorry, I don't understand."
)
);
}
}
recognition.start();
alert( "extension: we're done!" );
}
chrome.commands.onCommand.addListener(function(command) {
if (command === 'myCommand')
myCode();
});
I've also noticed that the code only runs once - I can keep on clicking in the listen button, but the Extension command only runs once (putting in an alert at the beginning of the function only gets displayed the first time around)
The default on my browser is that it should ask (once) which it does on the HTML version.
Thanks, just for reading this far! I've put an answer, with code, below.
The problem I had is that the mic seems to be a background task, whereas I'm trying to interact with tab contents. I don't think this is usual, and have ended up with a generic 'matches' value (*://*/*) in my manifest (in full):
{ "name": "Enguage(TM) - Let's all talk to the Web",
"short_name" : "Enguage",
"description": "A vocal Web interface",
"version": "0.98",
"manifest_version": 2,
"content_security_policy": "script-src 'self'; object-src 'self'",
"background": {
"scripts": ["kbTx.js"],
"persistent": false
},
"content_scripts": [
{ "matches" : ["*://*/*"],
"js": ["tabRx.js", "interp.js"]
} ],
"permissions": [
"activeTab",
"contentSettings",
"desktopCapture",
"tabCapture",
"tabs",
"tts"
],
"browser_action": {
"default_icon": "images/lbolt512.png",
"default_title": "Press Ctrl(Win)/Command(Mac)+Shift+ Space and speak"
},
"commands": {
"enguage": {
"suggested_key": {
"default": "Ctrl+Shift+Space",
"mac": "Command+Shift+Space"
},
"description": "single utterance"
} },
"icons": {
"16": "images/lbolt16.png",
"48": "images/lbolt48.png",
"128": "images/lbolt128.png",
"512": "images/lbolt512.png"
} }
I think Google might not like this! Anyway, I have put in a keyboard listener in my background code (kbTx.js):
chrome.commands.onCommand.addListener(function(command) {
if (command === 'enguage') {
// find the active tab...
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
//send it a message...
chrome.tabs.sendMessage(
tabs[0].id, // index not always 0?
null, // message sent - none required?
null // response callback - none expected!
//function(response) {console.log("done" /*response.farewell*/);}
);
});
}
});
And I've put in a context script which listens for this message (tabRx.js):
window.SpeechRecognition = window.webkitSpeechRecognition ||
window.SpeechRecognition;
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
var recognition = new SpeechRecognition();
recognition.start();
recognition.continuous = false;
recognition.onresult = function(event) {
if (event.results[0].isFinal) {
window.speechSynthesis.speak(
new SpeechSynthesisUtterance(
interp( event.results[0][0].transcript )
) );
} } }
);
The message listener essentially contains the code in the allInOne.html example above.
There may be other ways of doing this, but this works and seems reasonably lightweight.
Hope this helps.
Please feel free to add comments to this, if you think I can improve my code!
I'm building a chrome extension and I want to add a content to the div element in the compose window of Gmail web page.
By using the inspect tool in chrome, I got the class of the div, prepend the content but it is not showing.
Manifest.json
{
"manifest_version": 2,
"name": "Gmail Extension",
"description": "Personalised extension for gmail",
"version": "1.0",
"icons": {
"128": "icon128.png",
"48": "icon48.png",
"16": "icon16.png"
},
"content_scripts":[
{
"matches": ["https://mail.google.com/*"],
"js": ["content.js", "jquery-3.3.1.min.js"]
}
],
"permissions": [
"tabs",
"https://mail.google.com/*"
]
}
Content.js
$('div#:ug.J-J5-Ji btx').prepend('<p>Test added</p>');
Image of the compose window, the div highlighted
The text element isn't showing
Thanks
Here's what I did to add a checkbox to the Compose window:
// listen for the event that is fired when the document has finished loading
document.addEventListener('DOMContentLoaded', addUpdateButton, true);
addUpdateButton();
function addUpdateButton() {
var optionsArea = document.getElementsByClassName("aoD az6");
if (optionsArea && optionsArea.length > 0) {
var ecsLabel = document.createElement('label');
ecsLabel.setAttribute('name','ecsslabel');
ecsLabel.innerHTML = "Send as ECS: ";
ecsLabel.setAttribute('id','ecsLabel');
optionsArea[0].appendChild(ecsLabel);
var ecs = document.createElement('input');
ecs.setAttribute('type','checkbox');
ecs.setAttribute('name','ecsbox');
chrome.storage.sync.get("ecs_mode",
function(val) {
ecs.checked = val["ecs_mode"];
});
ecs.setAttribute('id','ecsOption');
optionsArea[0].appendChild(ecs);
}
}
and here's the result (actually, I added several checkboxes, but omitted the code for clarity):
Basically I am trying to create an Auto Visitor Extension for Chrome to open a website's URL after some specific time. When I open the popup everything works fine but when the popup is close nothing works. I am trying to find out a method to run that Auto Visitor Extension even when the popup is close I have read multiple questions regarding this phenomena on Stack Overflow but none of them clarifies what I am looking for.
Here is my manifest file:
manifest.json
{
"manifest_version": 2,
"name": "Auto Visitor",
"description": "This extension will visit multiple pages you saved in extension",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": [
"background.js"
],
"persistent": false
},
"permissions": [
"activeTab",
"storage",
"tabs",
"http://*/",
"https://*/"
]
}
The background file that i want to run even when popup is close :
background.js
// this will work only when you denie the background script in manifest
chrome.runtime.onInstalled.addListener(function(details) {
var initTime = 5;
chrome.storage.local.set({"avtime": initTime}, function() {});
});
reloadMainTab();
function reloadMainTab() {
chrome.storage.local.get('avurl', function (result) {
var urlsToLoad = result.avurl;
console.log(urlsToLoad);
if(urlsToLoad==undefined){
// do nothing
}else{
var urlsArr = urlsToLoad.split(",");
chrome.storage.local.get('avtime', function (result) {
var thisTime = result.avtime;
/*
setting it to -1 because it gets incremented by 1
when it goes into getSelected method
*/
var index=-1;
setInterval(function(){
if(index < urlsArr.length-1){
chrome.tabs.getSelected(function (tab) {
// console.log('index in get selected'+index)
chrome.tabs.update(tab.id,{url: urlsArr[index]});
});
index++;
}else{
index=-1;
}
}, thisTime+"000");
});
}
});
}
any help would be really appreciated
im trying to share my screen and record it but the problem its that when i choose the source of the stream, it doesnt start streaming, it only shows the window with the screen and window options to share but after selecting one, i checked that i get the ChromeMediaSource and the ChromeMediaSourceID but as i said, the dialog that says sharing wont appear and because of this i cant record anything.
This is an error i found debugging that is not logged into the console:
" at chrome-extension://mnoggiilghljimfhpghalhngdciecafi/background.js:16:31"
which is in "chrome.desktopCapture.chooseDesktopMedia" in the background file
this is my background file
background.js
chrome.runtime.onConnect.addListener( function( port ){
// listen for messages from the port
port.onMessage.addListener( function( message ){
// send back a "pending" answer on the port
port.postMessage( {
"answer": 1,
"state": "pending",
"requestId": message.requestId
} );
chrome.desktopCapture.chooseDesktopMedia(["screen", "window"], port.sender.tab, function( id ){
var response = {
"answer": 1,
"state": "completed",
"requestId": message.requestId,
"streamId": id || undefined
};
// send back a "completed" answer on the port
port.postMessage( response );
} );
} );
} );
this is the file that its loaded to the website using the extension
bridge.js
// open a port to communicate with background
var port = chrome.runtime.connect();
// create node
var node = document.createElement( 'div' );
// listen for messages from webpage and forward them to the background, through the previously opened port
window.addEventListener( 'message', function ( event ){
if ( event.source != window || !event.data ){
return;
}
// prevent to return answer to the background
if( event.data.answer ){
return;
}
port.postMessage( event.data );
} );
// listen for messages from background and forward them to the webpage
port.onMessage.addListener( function( data ){
window.postMessage( data, '*' );
} );
// insert tag into parent page
node.id = 'extension-screensharing-installed';
document.body.appendChild( node );
manifest.js
{
"name": "extension name",
"description": "This extension allows you to share your screen",
"version": "0.1",
"manifest_version": 2,
"minimum_chrome_version": "34",
"icons": {
"16": "img16.png",
"48": "img48.png",
"128": "img128.png"
},
"background": {
"scripts": ["background.js"]
},
"content_scripts": [ {
"js": [ "bridge.js" ],
"matches": [
"https://*/tester"
]
} ],
"permissions": [
"desktopCapture",
"https://*/tester"
]
}
could it be something wrong in my code?
i dont fully understand the error found by debuging
thanks!
edit: added manifest.json file!
Developing a Chrome screen-sharing extension includes instructions and sample code on developing the extension wherein values for apiKey, sessionId and token were entered and OT.registerScreenSharingExtension() method was also used to register the screen-sharing extension.
// API key and generate a test session ID and token:
var apiKey = "<YOUR_API_KEY>";
var sessionId = "<YOUR_SESSION_ID>";
var token = "<YOUR_TOKEN>";
var session = OT.initSession(apiKey, sessionId);
session.connect(token, function(error) {
var publisher = OT.initPublisher('camera');
session.publish(publisher, function() {
screenshare();
});
});
session.on('streamCreated', function(event) {
session.subscribe(event.stream);
});
OT.registerScreenSharingExtension('chrome', '<YOUR_CHROME_EXTENSION_ID>', 2);
And for the recording part, you may check how they did it in Screensharing with WebRTC. Hope it helps!
I am trying to fire a notification whenever I double click on a word/select it. Found several examples online but I still cannot get my example working:
Manifest:
{
"name": "hh",
"description": "hh!",
"manifest_version": 2,
"version": "0.0.0.1",
"content_scripts": [
{
"matches": [ "http://*/*", "https://*/*" ],
"js": [ "background.js" ],
"all_frames": true,
"run_at": "document_end"
}
],
"permissions": ["storage", "notifications"],
"icons": { "128": "neoprice.png" }
}
background.js
var listener = function(evt) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
displayPrice();
var range = selection.getRangeAt(0);
var text = range.cloneContents().textContent;
console.log(text);
}
};
document.addEventListener('dblclick', listener);
function displayPrice(){
chrome.notifications.create(getNotificationId(), {
title: "message.data.name",
iconUrl: 'hh.png',
type: 'basic',
message: "message.data.prompt"
}, function() {});
}
// Returns a new notification ID used in the notification.
function getNotificationId() {
var id = Math.floor(Math.random() * 9007199254740992) + 1;
return id.toString();
}
I was earlier adding the following but I saw people weren't using it, so I removed it
"app": {
"background": {
"scripts": ["background.js", "assets/jquery.min.js"]
}
},
What I am trying to achieve: Whenever they go to ANY page on selecting a word, it fires the function. Later, I wish to use this for a specific page. :)
Tried: How to keep the eventlistener real time for chrome extensions?
Chrome extension double click on a word
https://github.com/max99x/inline-search-chrome-ext
Both don't really work as I want them too. :(
Solution
It seems you are confused with background page and content script. Your background.js is a content script in fact, though its name is "background". While chrome.notifications api can be only called in background page, trying commenting displayPrice function will make your code work.
Next step
Take a look at above tutorials, wdblclick event triggers, use Message Passing to communicate with background page and call chrome.notications api in background page.
What's more
The following code is used in chrome apps rather than chrome extension.
"app": {
"background": {
"scripts": ["background.js", "assets/jquery.min.js"]
}
},