Chrome extension browse file (Chrome v33) - javascript

I had browsing for files working in chrome extensions but suddenly it stopped working (im guessing because of a chrome upgrade (to v33?))
i have looked around and all answers seem outdated...
here are my files (i got it from this: Upload File as a Form Data through chrome extension)
manifest.json:
{
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"name": "yoyo",
"manifest_version": 2,
"version": "1.0.0",
"browser_action": {
"default_title": "Test Extension",
"default_popup": "popup.html"
},
"permissions": [
"https://www.example.com/uploads"
]
}
popup.html:
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<input type="button" id="button" value="Browse and Upload" />
</body>
</html>
popup.js:
document.addEventListener('DOMContentLoaded', function () {
document.getElementsByTagName('input')[0].addEventListener('click', function () {
chrome.runtime.sendMessage({ action: 'browseAndUpload' }, function(response){});
window.close();
});
});
background.js:
var uploadURL = 'https://www.example.com/uploads';
/* Creates an `input[type="file]` */
var fileChooser = document.createElement('input');
fileChooser.type = 'file';
fileChooser.addEventListener('change', function () {
var file = fileChooser.files[0];
var formData = new FormData();
formData.append(file.name, file);
var xhr = new XMLHttpRequest();
xhr.open('POST', uploadURL, true);
xhr.addEventListener('readystatechange', function (evt) {
console.log('ReadyState: ' + xhr.readyState,
'Status: ' + xhr.status);
});
xhr.send(formData);
form.reset(); // <-- Resets the input so we do get a `change` event,
// even if the user chooses the same file
});
/* Wrap it in a form for resetting */
var form = document.createElement('form');
form.appendChild(fileChooser);
/* Listen for messages from popup */
chrome.runtime.onMessage.addListener(function (msg) {
if (msg.action === 'browseAndUpload') {
fileChooser.click();
}
});

Related

How to use ExecuteScript and MutationObserver for a Chrome extension Manifest V3?

The Manifest V3 JavaScript Chrome extension only has one button. When the button is clicked the browser should go to multiple pages and perform an action on each page before going to the next one.
What's currently happening, is the browser jumping to the last page and not performing any action.
How to fix my code, so that the extension visits each page one by one (in the same tab), then waits on the page until a button is detected, clicks the button, checks if the button is clicked, and then goes to the next page?
Manifest.json:
{
"name": "Twitch Follower",
"version": "0.1",
"manifest_version": 3,
"description": "Automatically follows Twitch users.",
"action": {
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"tabs",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"host_permissions": [
"https://www.twitch.tv/*"
]
}
popup.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css#2/out/water.css">
</head>
<body>
<button id="start">Start</button>
<script src="popup.js"></script>
</body>
</html>
popup.js:
start.addEventListener("click", async () => {
chrome.runtime.sendMessage({ start: true });
});
background.js:
const list = ["https://www.twitch.tv/hello1", "https://www.twitch.tv/hello2"];
function clickFollow() {
document.querySelector("button[data-a-target='follow-button']").click();
}
function handleFollowButton(followButton) {
setTimeout(clickFollow, 1000);
}
// Check for a button
async function checkButton() {
const findButton = new Promise((resolve, reject) => {
const observerConfig = { attributes: true, attributeOldValue: true };
const observer = new MutationObserver((mutations) => {
const followButton = document.querySelector("button[data-a-target='follow-button']");
const unfollowButton = document.querySelector("button[data-a-target='unfollow-button']");
// If follow button is found, click it
if (followButton) {
handleFollowButton(followButton);
}
// If unfollow button is found, end observing and continue
if (unfollowButton) {
unfollowButtonFound = True;
observer.disconnect();
resolve;
}
});
window.setTimeout(() => {
if (!unfollowButtonFound) {
reject;
}
}, 5000);
observer.observe(document, {
childList: true,
subtree: true,
});
});
await findButton;
return true;
}
// When the start button is clicked
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.start === true) {
// Loop through every link
for (const link of list) {
console.log(link);
// Open the link and inject the script
chrome.tabs.update({ url: link }, (tab) => {
chrome.scripting.executeScript(
{
target: { tabId: tab.id },
func: checkButton,
},
(result) => {
console.log(results);
}
);
});
}
}
});

Chrome Extension gives two errors: Uncaught TypeError and Unchecked runtime.lastError

I am facing two errors on Chrome extension that I am building:
Error 1:
Uncaught TypeError: Cannot set properties of null (setting 'onclick')
Context
_generated_background_page.html
Stack Trace
popup.js:3 (anonymous function)
Error 2:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
Context
_generated_background_page.html
Stack Trace
_generated_background_page.html:0 (anonymous function)
I have already checked the questions on this site that address these two errors and I tried the solutions provided in them, but I am still facing the two errors.
My original code:-
popup.js (tried changing from onclick to onClicked for error 1, tried putting this code in window.onload for error 2)
let populateBtn = document.getElementById('populateBtn');
let textArea = document.getElementById('productList');
populateBtn.onclick = function(element) {
let color = element.target.value;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
if(!textArea.value)
{
chrome.tabs.executeScript(
tabs[0].id,
{code: 'alert("Please, populate the order list!");'});
return;
}
chrome.tabs.sendMessage(tabs[0].id, {data: textArea.value.replace(/\t/g,'').split("\n")}, function(response) {
});
});
};
background.html (tried putting <script> after </body> tag for error 1)
<body>
<p>Gina's Bakery Bulk Order</p>
<textarea id="productList"></textarea>
<button id="populateBtn">Create Order</button>
<script src="popup.js"></script>
</body>
app.js (tried chrome.runtime.connect for error 2)
chrome.runtime.onInstalled.addListener(function() {
});
inject.js (tried chrome.runtime.onConnect.addListener for error 2)
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
let failed = [];
request.data.forEach(element => { // itterate over all products
if(element.includes('-')){
let data = element.split('-');
let quantity = data[0].toLowerCase().replace("gb", "").trim();
let ID = data[1].trim();
let elementName = 'pid_' + ID.replace(".", "_");
if(document.getElementsByName(elementName).length > 0)
document.getElementsByName(elementName)[0].value = quantity;
else
failed.push("<td>GB-"+ ID +"</td><td>" + quantity + "</td>");
}
});
if(failed.length > 0){
//alert("Order unsuccessful! One or more products are not ordered: " + failed.join(", "));
let modal = document.createElement("div");
modal.setAttribute("id", "failedOrderModal");
modal.setAttribute("style", "position:fixed;width:250px;left:50%;top:100px;background-color:#fff;border-radius:10px;padding:10px;z-index:10000;color:#000;border: 1px solid red;text-align:center;");
let head = document.createElement("h2");
head.innerText = "Order unsuccessful! One or more products were not found!";
modal.appendChild(head);
let table = document.createElement("table");
let tbody = document.createElement("tbody");
table.appendChild(tbody);
let tr = document.createElement("tr");
tr.innerHTML = "<td>ITEM</td><td>QTY</td>";
tbody.appendChild(tr);
failed.forEach(failedItem => {
tr = document.createElement("tr");
tr.innerHTML = failedItem;
tbody.appendChild(tr);
});
modal.appendChild(table);
let closeBtn = document.createElement("button");
closeBtn.setAttribute("type", "button");
closeBtn.innerText = "Close";
closeBtn.onclick = function(){
document.getElementById("failedOrderModal").remove();
}
modal.appendChild(closeBtn);
document.body.appendChild(modal);
}
else
{
alert("All products were successfuly populated!");
}
sendResponse({result: "ok"})
return true;
});
manifest.json
{
"name": "Gina's Bakery Order",
"version": "1.0",
"description": "Helps automate orders from ginas-bakery.com.au",
"permissions": ["activeTab", "declarativeContent", "storage"],
"background": {
"scripts": ["app.js", "popup.js"],
"persistent": false
},
"icons": {
"16": "images/ginas-bakery_16.png",
"32": "images/ginas-bakery_32.png",
"48": "images/ginas-bakery_48.png",
"128": "images/ginas-bakery_128.png"
},
"browser_action": {
"default_popup": "background.html"
},
"content_scripts": [
{
"matches": ["*://www.ginas-bakery.com.au/order/"],
"js": ["inject.js"]
}
],
"manifest_version": 2
}
None of the above mentioned solutions worked.
The background script page is an invisible hidden page, so running visible scripts like app.js or popup.js there is meaningless. Remove background section from manifest.json and rename your background.html to popup.html both on the disk and in manifest.json.
manifest.json:
{
"name": "Gina's Bakery Order",
"version": "1.0",
"permissions": ["activeTab", "declarativeContent", "storage"],
"browser_action": {"default_popup": "popup.html"},
"manifest_version": 2
}
Content scripts run only when the page loads, so if you just reloaded or installed/updated the extension without reloading the tab, the content scripts won't run there.
Although you can inject them explicitly, it's much better to switch to programmatic injection on demand (use executeScript instead of content_scripts) because you can do it without requiring any host permissions when installing the extension.
popup.js:
const textArea = document.getElementById('productList');
const btn = document.getElementById('populateBtn');
btn.onclick = () => {
const data = textArea.value.replace(/\t/g, '').split('\n');
chrome.tabs.query({active: true, currentWindow: true}, ([tab]) => {
chrome.tabs.sendMessage(tab.id, {data}, () => {
if (chrome.runtime.lastError) {
chrome.tabs.executeScript({file: 'inject.js'}, () => {
chrome.tabs.sendMessage(tab.id, {data});
});
}
});
});
};
Since you're not using the response in sendMessage, don't send it in the first place, i.e. remove sendResponse({result: "ok"}); return true; from inject.js.

Chrome Extension execute script doesn't render browser content value

All I am trying to do change the value of popup.html on the basis of Specific URL. So I am sending message to background.js when user click on change ID of H2 from popup.html render the content by using specific JavaScript file
manifest.json
{
"manifest_version": 2,
"name": "Helpfullio",
"version": "0.1",
"content_scripts": [{
"matches": [
"*://google.com/*/*",
],
"js": ["jquery-3.2.1.js"]
}],
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"permissions": ["tabs","http://*/*", "https://*/*"]
}
popup.html
<html>
<head>
</head>
<body>
<h2 id="change">Change ___________</h2>
<script src="popup.js"></script>
</body>
</html>
popup.js
function clickHandler(e) {
chrome.runtime.sendMessage({directive: "popup-click"}, function(response) {
// this.close(); finishes processing request
});
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('change').addEventListener('click', clickHandler);
})
background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
switch (request.directive) {
case "popup-click":
chrome.tabs.query({
'active': true, 'lastFocusedWindow': true
}, function (tabs) {
var url = tabs[0].url;
var result = url.split('/');
var hostname = result[2];
if("bitlock" == hostname){
chrome.tabs.executeScript(null, {
file: "render.js",
// allFrames: true
});
}else{
hrome.tabs.executeScript(null, {
file: "secondrender.js",
// allFrames: true
});
}
sendResponse({});
});
break;
default:
alert("Unmatched request of '" + request + "' from script to background.js from " + sender);
}
}
);;
JavaScript doesn't render the content of popup.html as it is not finding the elementID "change" . SO here how can I give reference of popup.html file in render.js file
render.js
document.getElementById("change").textContent = 'new text';

Logon to a remote system via a Chrome extension

This is my first extension and I suspect the way I've gone about structuring the order of calling code is not completely right. I would appreciate pointers please - hopefully I'm fairly close as it has taken weeks of study, trial and error to get this far :-) XMLHttpRequest does not seem to call the system and the extension crashes a lot.
In the popup.html, there's a SignIn button which opens the 'popup' form signin.html via a listener in background.js. The signin page contains a form with a username & password inputs, and a signin button. Clicking this button calls signin.js to pickup the data from the form, and calls a routine in background.js to connect to the system (could this be the issue - since this was all kicked off from the background.js in the first place???)
In the code,e I'm connecting to Google so I know I have a website that works - I'll deal with the logon part later. Thanks.
manifest.json:
{
"name": "logon test",
"description": "logon test",
"version": "1.0",
"manifest_version": 2,
"icons": { "128": "images/logon.png" },
"browser_action": {
"default_icon": "images/logon.png",
"default_title": "logon test",
"default_popup": "popup.html" },
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"background",
"storage",
"activeTab",
"nativeMessaging",
"http://www.google.com/*",
"https://www.google.com/*"
]
}
popup.html:
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<button id = "signin">Sign In</button>
</body>
</html>
popup.js:
function onSignIn() {
chrome.extension.sendMessage({'action' : 'signin', 'url' :
'/signin.html'});
} //onSignIn
document.getElementById('signin').addEventListener('click', onSignIn);
**signin.html:**
<html>
<body>
<form>
<input name="userid" type="text" id="userid" value="User ID">
<input name="password" type="password" id="password">
<input type="submit" name="submit" id="submit" value="Login">
</form>
<script src="signin.js"></script>
</body>
</html>
signin.js:
document.forms[0].onsubmit = function(e) {
e.preventDefault(); // Prevent submission
var password = document.getElementById('password').value;
var userid = document.getElementById('userid').value;
chrome.runtime.getBackgroundPage(function(bgWindow) {
bgWindow.signIn(password, userid); //background page
window.close(); // Close dialog
});
};
background.js:
function signIn(inPass, inUserid) { //called from signin.html popup
var xhr = new XMLHttpRequest();
if (xhr === null){
alert("Unable to create request");
} else {
xhr.open('GET', 'http://www.google.com/search?q=helloworld',
true);
xhr.onreadystatechange = function() {
var resp = JSON.parse(this.responseText);
alert("result here" + resp);
} //readystate
};
}
xhr.send(null);
} //signin
// button functionality - called from popup.html
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
if (request.action === 'signin') {
chrome.tabs.create({
url: chrome.extension.getURL(request.url),
active: false
}, function(tab) {
chrome.windows.create({
tabId: tab.id,
type: 'popup',
focused: true,
left: 500,
top: 20,
width: 450,
height: 200});
}); //tab
} //if
return true;
});

XMLHttpRequest status 0 in click event handler

I'm writing a Google Chrome extension to take advantage of an API we have written. The problem I'm having is that the popup.html has a login form, and when the submit button is pressed it calls the necessary authentication code, which involves making a couple of XMLHttpRequests to the API server.
The code is as follows:
authenticate.js
function authenticate(username, password)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", "<api-server>/challenge?username=dummyusername", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
alert(xhr.status);
}
};
xhr.send();
}
/*Gets the username and password textboxes from popup.html and passes their values on to authenticate()*/
function getCredentials()
{
authenticate("test", "test");
}
document.addEventListener("DOMContentLoaded", function() {
var submitBtn = document.getElementById("submitBtn");
if (submitBtn != null) {
submitBtn.onclick = getCredentials;
}
});
popup.html
<!doctype html>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<form>
<label for="username">Username:</label>
<input type="text" id="usernameTxt"><br>
<label for="password">Password:</label>
<input type="password" id="passwordTxt"><br><br>
<input type="submit" id="submitBtn" value="Submit">
</form>
<script src="authenticate.js"></script>
</body>
</html>
manifest.json
{
"manifest_version": 2,
"name": "Chrome Extension",
"description": "Chrome Extension",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"<all_urls>",
"activeTab",
"https://ajax.googleapis.com/",
"<api-server>"
]
}
If, however, I replace:
document.addEventListener("DOMContentLoaded", function() {
var submitBtn = document.getElementById("submitBtn");
if (submitBtn != null) {
submitBtn.onclick = getCredentials;
}
});
with:
document.addEventListener('DOMContentLoaded', function() {
getCredentials();
});
it does the right thing, which leads me to believe it's to do with the fact that it's being called from a click event handler and perhaps somehow the permissions haven't been extended to the button.
I saw this post (Chrome Extension: XMLHttpRequest canceled (status == 0)) and added "<all_urls>" to permissions and that has made no difference.
Cancel the click so the form does not submit.
document.getElementById("submitBtn").addEventListener('click', function(evt){
evt.preventDefault();
getCredentials();
});

Categories

Resources