I need to develop a simple Chrome Extension for work that inspects
Chrome's JS console for a certain value.
Further Explanation:
Basically, the need for this, is I need to know when a certain JS event has completed. I have placed a console.log("complete!") in my code to inform me when it is done.
The problem I am facing, I cannot seem to find a way for a chrome extension to read output from the JS Console.
As far as I know you can't read the console output from JS, not even on a regular webpage. You would have to hijack the console methods and save what is passed to them, and then do searches on the saved data.
From your goal it seems like you simply want to trigger a new event. Which you can do by creating a Event/CustomEvent, setting up a listener for it, and firing off the event whenever you need it to be triggered.
document.addEventListener("eventdone",function(e){
console.log("The events done, now do work here");
});
//then whereever you had console.log("complete!")
var event = new CustomEvent('eventdone', { 'detail': 'Extra data' });
document.dispatchEvent(event);
Demo
document.addEventListener("eventdone",function(e){
document.body.innerHTML = "Event done";
});
document.querySelector("button").addEventListener("click",function(e){
setTimeout(function(){
var event = new CustomEvent('eventdone', { 'detail': 'Extra data' });
document.dispatchEvent(event);
},2000);
});
<button>Click me</button>
Related
I am just detecting the printed status in web browser.
As you can see , browser support the status as cancel or print button.
For seeing if user clicked cancel, print button, I am just using javascript.
but I had not got good result for that.
Are there good way to detect the status ?
window.print() doesn't return any value.
I don't think there's a way to know if the user clicked Save or Cancel. It's more of your operating system's job to watch what's going on in there. There're, however, two event handlers
window.onbeforeprint and
window.onafterprint.
Code Snippet
window.onbeforeprint = function() {
console.log('This will be called before the user prints.');
};
window.onafterprint = function() {
console.log('This will be called after the user prints');
};
Take a look here
I am trying to pass messages between a Firefox Addon worker script and the webpage's javascript. I found this which explains how to send a message to the script and get a reply back, but I want to simply send the message from chrome to the unprivileged code. I have already tried using the following two methods.
I am sending from a worker attached to a panel and I want to receive the message in some javascript that I have injected into the page DOM.
To send
var element = document.createElement("MyExtensionDataElement");
element.setAttribute('detail', "hi");
document.documentElement.appendChild(element);
console.log("created the event", element);
var evt = document.createEvent("Events");
evt.initEvent("MyExtensionEvent1", true, false);
element.dispatchEvent(evt);
To receive
document.addEventListener("MyExtensionEvent", function(e) {
myExtension.myListener(e);
}, false, true);
And also via a simple CustomEvent
To send
var e = new CustomEvent("event",{detail:"string here"});
window.dispatchEvent(e);
To recieve
window.addEventListener("event",function(e){
console.log(e.detail);
});
The first one sends the message but it isnt received, and the second one fails to even create the CustomEvent in the first place. I'd appreciate any help on this matter and do apologize if the question seems amateurish. Im new to Firefox Addon Development.
Your receive is wrong, you need to use add 4th argument and set it to try:
So
window.addEventListener("event",function(e){
console.log(e.detail);
});
Goes to
window.addEventListener("event",function(e){
console.log(e.detail);
}, false, true);
See this topic - initCustomEvent pass data for method doesn't work anymore
Calling document.execCommand('copy'); from the Chrome developer console returns false every time.
Give it a try yourself. Open the console and run it, it never succeeds.
Any idea as to why?
document.execCommand('copy') must be triggered by the user. It's not only from the console, it's anywhere that's not inside an event triggered by the user. See below, the click event will return true, but a call without event won't and a call in a dispatched event also.
console.log('no event', document.execCommand('bold'));
document.getElementById('test').addEventListener('click', function(){
console.log('user click', document.execCommand('copy'));
});
document.getElementById('test').addEventListener('fakeclick', function(){
console.log('fake click', document.execCommand('copy'));
});
var event = new Event('fakeclick')
document.getElementById('test').dispatchEvent(event) ;
<div id="test">click</ha>
See here:https://w3c.github.io/editing/execCommand.html#dfn-the-copy-command
Copy commands triggered from document.execCommand() will only affect
the contents of the real clipboard if the event is dispatched from an
event that is trusted and triggered by the user, or if the
implementation is configured to allow this. How implementations can be
configured to allow write access to the clipboard is outside the scope
of this specification.
As an alternative, use the copy() command that is built in to the Chrome Dev tools. You can't use document.execCommand("copy") because that requires user action to trigger it.
The copy() command allows you to copy any string (or object as JSON). To emulate document.execCommand("copy") you can get the current selection with getSelection().toString():
copy(getSelection().toString())
If you need to actually test document.execCommand("copy") specifically (for example, to debug a script that uses it), and using the debugger isn't ideal for some reason, you can wrap your code in a click handler, and then click your page:
document.body.addEventListener("click", function() {
console.log("copy", document.execCommand("copy"));
}, false);
I believe, copy command requires to be having the focus on the browser, and when you go to Console and execute the command, the current window loses focus. But could be other reasons, as it worked if I give in setTimeout().
This method works in the latest version of safari
const copyUrl = (url, cb) => {
try {
var input = document.getElementById('copyInput')
input.value = url
input.focus()
input.select()
if (document.execCommand('copy', false, null)) {
Message('复制成功')
} else {
Message({
message: '当前浏览器不支持复制操作,请使用Ctrl+c手动复制',
type: 'warning'
})
}
} catch (e) {
Message({
message: `复制出错:${e}`,
type: 'error'
})
}
}
In background page we're able to detect extension updates using chrome.runtime.onInstalled.addListener.
But after extension has been updated all content scripts can't connect to the background page. And we get an error: Error connecting to extension ....
It's possible to re-inject content scripts using chrome.tabs.executeScript... But what if we have a sensitive data that should be saved before an update and used after update? What could we do?
Also if we re-inject all content scripts we should properly tear down previous content scripts.
What is the proper way to handle extension updates from content scripts without losing the user data?
If you've established a communication through var port = chrome.runtime.connect(...) (as described on
https://developer.chrome.com/extensions/messaging#connect), it should be possible to listen to the runtime.Port.onDisconnect event:
tport.onDisconnect.addListener(function(msg) {...})
There you can react and, e.g. apply some sort of memoization, let's say via localStorage. But in general, I would suggest to keep content scripts as tiny as possible and perform all the data manipulations in the background, letting content only to collect/pass data and render some state, if needed.
Once Chrome extension update happens, the "orphaned" content script is cut off from the extension completely. The only way it can still communicate is through shared DOM. If you're talking about really sensitive data, this is not secure from the page. More on that later.
First off, you can delay an update. In your background script, add a handler for the chrome.runtime.onUpdateAvailable event. As long as the listener is there, you have a chance to do cleanup.
// Background script
chrome.runtime.onUpdateAvailable.addListener(function(details) {
// Do your work, call the callback when done
syncRemainingData(function() {
chrome.runtime.reload();
});
});
Second, suppose the worst happens and you are cut off. You can still communicate using DOM events:
// Content script
// Get ready for data
window.addEventListener("SendRemainingData", function(evt) {
processData(evt.detail);
}, false);
// Request data
var event = new CustomEvent("RequestRemainingData");
window.dispatchEvent(event);
// Be ready to send data if asked later
window.addEventListener("RequestRemainingData", function(evt) {
var event = new CustomEvent("SendRemainingData", {detail: data});
window.dispatchEvent(event);
}, false);
However, this communication channel is potentially eavesdropped on by the host page. And, as said previously, that eavesdropping is not something you can bypass.
Yet, you can have some out-of-band pre-shared data. Suppose that you generate a random key on first install and keep it in chrome.storage - this is not accessible by web pages by any means. Of course, once orphaned you can't read it, but you can at the moment of injection.
var PSK;
chrome.storage.local.get("preSharedKey", function(data) {
PSK = data.preSharedKey;
// ...
window.addEventListener("SendRemainingData", function(evt) {
processData(decrypt(evt.detail, PSK));
}, false);
// ...
window.addEventListener("RequestRemainingData", function(evt) {
var event = new CustomEvent("SendRemainingData", {detail: encrypt(data, PSK)});
window.dispatchEvent(event);
}, false);
});
This is of course proof-of-concept code. I doubt that you will need more than an onUpdateAvailable listener.
I have a Firefox extension that modifies the content of the page that the user is looking at. As part of that process the extension needs to trigger a custom event that the extension itself adds to the page source. I am having difficulties passing parameters to that custom event. What am I doing wrong?
Script block inserted into the head of the page:
document.addEventListener("show-my-overlay", EX_ShowOverlay, false, false, true);
function EX_ShowOverlay(e) {
alert('Parameter: ' + e.index);
// ...
}
Code in the extension:
var event = content.document.createEvent("Events");
event.initEvent("show-my-overlay", true, true);
event['index'] = 123;
content.document.dispatchEvent(event);
The event gets triggered successfully, but e.index is undefined.
I managed to get it working by creating an element on the page and then having the event handler find the element and read its attributes, but it didn't feel elegant. I want to do it without the element.
EDIT:
I also tried triggering the event with CustomEvent, but it throws an exception in the handler:
var event = new CustomEvent('show-my-overlay', { detail: { index: 123 } });
content.document.dispatchEvent(event);
function EX_ShowOverlay(e) {
alert('Parameter: ' + e.detail.index);
// ...
}
Permission denied to access property 'detail'
OP has solved their problem using postMessage. For those of us who actually do have to solve it using CustomEvent (being able to specify message types is useful), here's the answer:
Firefox won't allow the page script to access anything in the detail object sent by the content script via CustomEvent unless you clone the event detail into the document first using the Firefox-specific cloneInto() function.
The following does work over here to send an object from the extension to the page:
var clonedDetail = cloneInto({ index: 123 }, document.defaultView);
var event = new CustomEvent('show-my-overlay', { detail: clonedDetail });
document.dispatchEvent(event);
The Mozilla docs have more detail on cloneInto.
You cannot access "expandos" (additional properties defined on a native prototype object) across security boundaries. The security boundary in this case being between the fully privileged chrome (add-on) code and the non-privileged website code.
So you need to pass data using something "standard". The CustomEvent stuff would do, however your code is wrong. You have to call the constructor or initCustomEvent() correctly:
var event = new CustomEvent('show-my-overlay', { detail: { index: 123 } });
content.document.dispatchEvent(event);
Another alternative is the postMessage API.