Unknown error on chrome.tabs.executeScript - javascript

I need to run a script on an external page.
I'm trying to consume the Dropbox API (JavaScript and HTML only).
I'm using JsOAuth to work with OAuth.
Code
This application is a pair of type Packaged Apps to Google Chrome.
Authorise
//Request token
chrome.windows.create({url: url, type:"popup"}, function(win){
chrome.tabs.executeScript(win.id, { file: "contentScript.js" }, function(){
console.log("Callback executeScript!!");
});
});
url = Request token url
contentScript.js
$(document).ready(function() {
console.log("Script injected!!!");
})
Error in console
Error during tabs.executeScript: Unknown error.
chromeHidden.handleResponseextensions/schema_generated_bindings.js:94
openAuthoriseWindowscripts.js:297
g.fetchRequestTokenjsOAuth-1.3.3.min.js:1
g.init.request.q.onreadystatechange
Attempts
As the external page can not jQuery, an effort was to remove the reference to jQuery
contentScript.js
console.log("Script injected!!!");
Error in console
Error during tabs.executeScript: Unknown error.
chromeHidden.handleResponse
Another attempt was to inject the script via code:
//Request token
chrome.windows.create({url: url, type:"popup"}, function(win){
chrome.tabs.executeScript(win.id, { code: "console.log('Script injected!!')" }, function(){
console.log("Callback executeScript!!");
});
});
But the error was the same as above

I'm not sure whether you are wanting to inject the script into the tab opening the window, or the new tab you just opened. In any event, I made an effort to answer both questions below. First, please note that you should not attempt to load the script into the window object. The window can contain multiple tabs, and each tab has their own scripting environment. Inject your script into a tab of the newly opened window.
Outcome 1: Injecting the Script into the tab you Just Opened
The code below should load the script into all of the tabs of a window since win.tabs gives an array of tabs. For a newly opened window, there is usually only one tab.
chrome.windows.create({url: "https://google.com", type:"popup"}, function(win){
chrome.tabs.executeScript(win.id.tabs,
{ code: "console.log('new tab context');" });
});
Outcome 2: Injecting the Script into the tab opening the window
Record the id of the tab opening the new window, then inject the script on the callback
var openingTabId = ASSIGN_THE_TAB_ID;
chrome.windows.create({url: "https://google.com", type:"popup"}, function(win){
chrome.tabs.executeScript(openingTabId,
{ code: "console.log('opening tab context');" });
});
Notice that I used the code object to pass code without using a script file.

Related

Firefox extension: Open window and write dynamic content

I have developed a Chrome Extension and it's mostly compatible to firefox web-extensions API. Just one problem:
In Chrome Extension i have popup.js and background.js. User click's a button, popup.js does chrome.sendMessage to background.js where data is received and afterwards (popup.html may be closed meanwhile) i just call in background.js:
newWin = window.open("about:blank", "Document Query", "width=800,height=500");
newWin.document.open();
newWin.document.write('<html><body><pre>' + documentJson + '</pre></body></html>');
// newWin.document.close();
so that works fine in Chrome extension but not in firefox. I read here (https://javascript.info/popup-windows) that for safety reasons firefox will only open with a "button click event". And if i move above code to popup.js, inside button-click-evenListener, it will open this way (but i dont have the data prepared yet, thats really not what i want)
So i tried everything i found but i dont get the chrome.tabs.executeScript running. Here is my code with comments:
popup.js
// working in firefox and chrome (popup.js)
const newWin = window.open("about:blank", "hello", "width=200,height=200");
newWin.document.write("Hello, world!");
// not working firefox: id's match, he enters function (newWindow) but document.write doing nothing (but no error in log)
// not working chrome: doesnt even enter "function (newWindow)""
chrome.windows.create({
type: 'popup',
url: "output.html"
}, function (newWindow) {
console.log(newWindow);
console.log(newWindow.id);
chrome.tabs.executeScript(newWindow.tabs[0].id, {
code: 'document.write("hello world");'
});
});
background.js
(created local output.html and gave several permissions in Manifest.json - tabs, activeTab, output.html, , about:blank)
// opening but executeScript not working in firefox: Unchecked lastError value: Error: The operation is insecure.
// opening but executeScript not working in chrome: Unchecked runtime.lastError: Cannot access contents of url "chrome-extension://plhphckppghaijagdmghdnjpilpdidkh/output.html". Extension manifest must request permission to access this host
chrome.tabs.create({
// type: 'popup',
url: "output.html"
}, function (newWindow) {
console.log(newWindow);
console.log(newWindow.id);
chrome.tabs.executeScript(newWindow.id, {
code: 'document.write("hello world");'
});
});
How can I get the data into the new window/popup from background.js - i can open an empty page from there, so it's only about getting executeScript() running
Thanks to #wOxxOm for pointing me to a data URI to transport the json document into the browser from background.js.
While searching for a javascript method to build a data URI i found this thread, with the suggestion to create a Blob :
https://stackoverflow.com/a/57243399/13292573
So my solution is this:
background.js
var documentJson = JSON.stringify(documents, null, 2)
let a = URL.createObjectURL(new Blob([documentJson]))
chrome.windows.create({
type: 'popup',
url: a
});

Firefox Extension: Error calling executeScript on file but not code

I'm trying to execute a script in a new tab when that tab is opened.
In my background script I have:
var listener = function (tab) {
browser.tabs.executeScript(null, { file: "content_scripts/contentScript.js" });
}
browser.tabs.onCreated.addListener(listener);
In contentScript.js:
function foo() {
console.log("Executed");
}
foo();
From this I get the following error:
Error: Permission denied to access property "chrome"
If I simply execute code rather than call a js script, ex:
browser.tabs.executeScript(null, { code: "console.log("Executed") });
This does not cause the error. Any idea what is causing this?
It doesn't work properly because apparently this bug has not been fixed and still exists in Firefox 59.
You can work around the issue by letting the tab load for some milliseconds before running executeScript on it.
I have tested this an it works for me:
(Remember that this does not work for new blank tabs as in "about:newtab". These can not be accessed for security reasons.)
background.js
var listener = function (tab) {
setTimeout(()=>{
browser.tabs.executeScript(tab.id, {file: "/content_scripts/contentScript.js"}).then(()=>{
console.log("Executed!")
}).catch(err=>{
console.error("Not executed:")
console.error(err)
})
},1000) // Add a delay because of this bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1254003
}
browser.tabs.onCreated.addListener(listener);
content_scripts/contentScript.js
function foo() {
console.log("Executed");
alert("Executed!");
}
foo();
manifest.json
{
"description": "Test executeScript api",
"manifest_version": 2,
"name": "ExecuteScript-Test",
"version": "1.0",
"permissions": [
"activeTab",
"tabs",
"<all_urls>"
],
"background": {
"scripts": ["background.js"]
}
}
If FF developers docs it's said:
In Firefox, relative URLs passed into tabs.executeScript() or
tabs.insertCSS() are resolved relative to the current page URL. In
Chrome, these URLs are resolved relative to the add-on's base URL. To
work cross-browser, you can specify the path as an absolute URL,
starting at the add-on's root, like this:
/path/to/script.js
so this should do the trick, but in fact FF48 due to unknown reasons both insertCSS() and executeScript() don't want to execute. At the same time I've found if to execute code with these functions calls in debugger in step-by-step mode, they triggered normally. So it looks like FF bug.
Can't comment, so sorry this isn't a real answer ...
I'm not seeing the same results. Provided details in case anything jumps out at you as being different from how I ran it and how you are running it.
In background script (located in the extension root directory), on extension startup, both:
var temp = function (tab) {
browser.tabs.executeScript(null, { file: "src/js/asdf.js" });
};
browser.tabs.onCreated.addListener(temp);
and
browser.tabs.onCreated.addListener(function (tab) {
browser.tabs.executeScript(null, { file: "src/js/asdf.js" });
});
register correctly (no errors on startup).
The file src/js/asdf.js exists, is the correct relative path from background.js, and contains your foo method and call.
When I create a new blank tab (which by definition cannot have content scripts attached), I see the expected error in the console (albeit from undefined instead from background.js):
Error: Missing host permission for the tab
When I create a new blank tab with content from the beginning (i.e., context click to open a link in a new tab), I see the expected result (Executed in the console log).
When I create a new tab from within the extension, I also see the expected result (Executed in the console log.
Potentially relevant manifest info:
asdf.js is not web accessible
permissions include tabs and <all_urls>
there are no content scripts defined in manifest.json
Running Firefox 59.0.2 (64-bit) on Mac 10.13.4

How to communicate with a webpage via browser plugin

How can I communicate from a JavaScript code of a webpage to the main code of the add-on?
For example, something like this: If some element is clicked, in the corresponding event handler of the page script, which is the syntax that can be used to send some message to the main code?
Specifically, something like this, where the frame now must be replaced by a generic webpage. Is it possible?
Edit: I have tried the suggested code, but how I had said, the application returns this error:
console.error: sherlock:
Message: ReferenceError: document is not defined
Stack:
A coding exception was thrown in a Promise resolution callback.
See https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise
Full message: ReferenceError: document is not defined
Previously my question, I had infact tried something similar without any effect.
Yes it is possible.
document.onload = function() {
var elementYouWant = document.getElementById("someID");
elementYouWant.onclick = console.log("Yup.. It was clicked..");
};
Reference.
The answer to the question is not as trivial as it may seem at first sight. I had also thought of a logic of the type described in the Pogrindis' response.
But here, in the case of interaction between the main script (i.e. that of the add-on) and generic script of arbitrary documents, the pattern is different.
In summary, the interaction takes place in this way:
It is required the API page-mod.
Through the property includes of the object PageMod you create a reference to the document, specifying the URI (wildcards are allowed).
Via the contentScriptFile property it is set the URL of the .js file that will act as a vehicle between the main code and that of the document.
Here's an example that refers to the specific needs of the context in which I am. We have:
an add-on code (the main code);
a Sidebar type html document (gui1.html) loaded in the file that I
use as a simple UI (I advise against the use of Frames, since it does
not support many typical HTML features - eg the click on a link,
etc.) containing a link to a second document (gui2.html) which will then
be loaded into the browser tab (I needed this trick because the
Sidebar does not support localStorage, while it is necessary for me);
a script in the document.
We must create an exchange of information between the two elements. In my case the exchange is unidirectional, from the page script to the main one.
Here's the code (main.js):
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "resource://path/to/document/gui2.html",
contentScriptFile: data.url("listen.js"),
onAttach: function(worker) {
worker.port.on("gotElement", function(elementContent) {
console.log(elementContent);
});
}
});
and in the html page script:
<script type="text/javascript">
[...]
SOWIN = (navigator.userAgent.toLowerCase().indexOf("win") > -1) ? "win" : "nix";
if (SOWIN == "win") {
window.postMessage("win","*");
} else {
window.postMessage("Linux","*");
}
[...]
</script>
Finally in the JS file (listen.js) to be attached to the page script:
window.addEventListener('message', function(event) {
self.port.emit("gotElement", event.data);
}, false);
This is just a small example, but logic I would say that it is clear. The uploaded content scripts are not accessible directly from main.js (i.e. the add-on), but you can create a bidirectional communication through the exchange of messages. To achieve this we have to put ourselves in listening the event Attach of the page-mod. Then, it is passed a worker object to the listener; that worker may be used by the add-on for the exchange of messages.
Here are the references to have an exhaustive picture:
Interacting with page scripts
Communicating with other scripts
page-mod
port
Communicating using "port"
postMessage
Communicating using postMessage

Ti.App.fireEvent not working; error Uncaught TypeError: Cannot read property 'App' of undefined

I have a simple Titanium app which opens a webview, and loads a URL. I want the links to open in the default browser, not the app.
I have some jQuery code which adds a click event to all links in the page.
<script>
jQuery('a').click(function() {
console.log("Handler for .click() called for URL: " + this.href);
Ti.App.fireEvent('ynOpenURL', {url: this.href });
});
In the app.js file I have:
var win = Ti.UI.createWindow();
var mywebview = Ti.UI.createWebView({
url : 'http://xxxx.xxxxx.com/',
enableZoomControls: false
});
win.add(mywebview);
win.open();
Ti.App.addEventListener('ynOpenURL', function(e) {
Ti.API.info('yyyyyy');
Ti.API.info(e.url);
if (Ti.Platform.canOpenURL(e.url)){
Ti.Platform.openURL(e.url);
} else {
alert("Cannot open URL");
}
When I run the app on my Android (4.4) the web page loads correctly.
When I click a link on the phone I get the following in the console:
Handler for .click() called for URL: http://xxx.xxxxx.xxx/
Uncaught TypeError: Cannot read property 'App' of undefined (xxxx)
None of the Titanium console events are logged, only the javascript events in the webpage.
As you mentioned that the webview is loading remote url. So Ti.* or Titanium.* are not available at your remote server.
What you can do is :
Create a html file within the app and load the data via ajax and use fireEvent.
Load the data via titanium http client and use Ti.Platform.openURL accordingly.
Edit : Quote from Titanium WebView Docs
Remote Scripts
Scripts downloaded from remote web servers cannot access the Titanium namespace.
To interact with remote content, wait until the content is loaded, then use the evalJS method to execute a JavaScript expression inside the web view and retrieve the value of an expression.

Crossrider extension, ready code do not run

I started using crossrider, actuly I have just registered my self
/************************************************************************************
This is your Page Code. The appAPI.ready() code block will be executed on every page load.
For more information please visit our docs site: http://docs.crossrider.com
*************************************************************************************/
appAPI.ready(function($) {
// Place your code here (you can also define new functions above this scope)
// The $ object is the extension's jQuery object
alert("My new Crossrider extension works! The current page is: " + document.location.href);
});
And this does not alerts me when page loads.

Categories

Resources