Firefox extension: Access to main document from sidebar - javascript

I'm brand new to writing Firefox extensions and I'm trying to create a sidebar which searches for certain elements in the main document and shows info about them in the sidebar. I followed the instructions here to create the sidebar with no problems.
Problem I'm having now is accessing the main window or document in my sidebar.js file.
The docs here say to use
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
But that gives me this error:
TypeError: window.QueryInterface is not a function
I'm getting the warning:
The Components object is deprecated. It will soon be removed.
Which makes me think even if the code above worked for me it's not the best method.

The error messages indicate that your code is running in an unprivileged javascript context. .QueryInterface() is XPCOM code, i.e. accessing internal browser components which is only available to privileged code.
It is generally not advisable to for "leaf content" (windows/sidebars spawned by addons) to have direct control. Instead your addon main code should coordinate the individual views. Your sidebar should be dumb, just pass messages to addon code and the addon then modifies the content of the tab.
Due e10s various parts of the browser may end up running in separate processes in the future and will not have direct access to each other.
If you're not developing with the addon-sdk - which is designed with message-passing as its primary way of gluing components together - you will have to use the message manager to wire your addon, sidebar and content scripts together.

Use tabs.create() | MDN as in:
browser.tabs.create({url:"https://www.google.com"});
I also used that documentation and I also got that error. The documentation is too old.

browser.tabs.create({url:"https://www.google.com"})
will work fine

Related

Webextension inline install chrome.runtime.connect issues

I'm having a really weird issue, I've developped a webextension that uses messaging between content script and background script (using chrome.runtime.connect) and nativemessaging.
The issue i'm facing is that when I install the extension (manually from the store beforehand and then connect to my website, everything works as expected, the chrome.runtime.connect works and returns a valid port to the background script.
But when i do an inline install of the extension from my website to get around the fact to have to navigate to have the content script in the webpage, i manually inject the content script into my page using
function injectContentScript() {
var s = document.createElement("script");
s.setAttribute("src", "chrome-extension://<extensionid>/content.js");
document.head.appendChild(s);
}
and the exact same content script but manually injected doesn't behave the same. chrome.runtime.connect returns a null object and chrome.runtime.lastError gives me
Could not establish connection. Receiving end does not exist.
I'm calling on the sender side (content.js - manually injected content script) chrome.runtime.connect(extensionID) where extension id is the id of the extension generated by the chrome webstore. And on the receiving side (background.js - extension background script) chrome.runtime.onConnect.addListener(onPortConnected);
I'm not really sure how to debug this issue, maybe it's a timing issue?
The background script is well executed even with the inline install (i've added logs and debugged it through the background.html in chrome extension manager)
Any help would be greatly appreciated!
You have two scenarios.
Your content script content.js is executed as normal upon navigation, as a content script defined in the manifest.
In this case, it executes in a special JS context attached to the page and reserved for your content scripts. See Execution Environment docs section for explanation. It is isolated from the webpage and is considered part of the extension (albeit with lower privileges).
When you connect from a content script, chrome.runtime.connect() is treated as internal communication between parts of the extension. So while you can provide the extension ID, it is not needed.
More importantly, the event raised in this case is chrome.runtime.onConnect.
Your supposed "inject content script immediately" code called from the webpage does something completely different.
Instead of creating a new execution context, the code is instead added directly to the page; it is not considered part of the extension and has no access to extension API.
Normally, a call to chrome.runtime.connect() would simply fail, as this is not a function exposed to webpages; however, you also declared externally_connectable, so it is exposed specifically to your webpage.
In this case, passing the extension ID is mandatory for the connect. You were doing this already, so the call was succeeding.
However, and that's what made it fail: the corresponding event is no longer onConnect, but onConnectExternal!
What you should be doing is:
Not mixing code that is run in very different contexts.
If you need communication from the webpage to background, always do it from the webpage, not sometimes-from-content-sometimes-from-page.
That way you only have to listen to onConnectExternal and it cuts out the need for a content script (if it was its only function).
See the docs as well: Sending messages from web pages.
You don't have to source the code from chrome-extension://<extensionid>/; you can directly add this to your website's code and potentially avoid web_accessible_resources.
And if you actually want to inject content scripts on first run, see for example this answer.
Related reading: How to properly handle chrome extension updates from content scripts

Javascript acting differently in inappbrowser vs Chrome - Undefined global variables

My problem is that when I use inappbrowser to open my web page, the main javascript file seems to be ignored, even though it is referenced in the Head of the file that I am opening using ref = cordova.InAppBrowser.open('https://MYURLHERE:8484/home/login', '_self', 'location=yes');
I am using chrome://inspect/#devices to inspect the console and I get errors when hitting buttons.. Anything referenced in the main.js file is undefined.. whereas the actual code for the autocomplete and button seems to be executing.
Please note The url is working fine when viewed in the chrome browser. The javascript files seem to load correctly, and all variables are defined correctly. - It is only when I use inappbrowser that I see issues with undefined variables.
My code (cordova app):
ref = cordova.InAppBrowser.open('https://MYURLHERE:8484/home/login', '_self', 'location=yes');
var myInAppBrowserCallback = function(event) {
console.log(event.url, 'LOADED');
};
ref.addEventListener('loadstart', myInAppBrowserCallback);
//Works fine.
My code (from the actual website I'm trying to view in Inappbrowser):
<script src="/Scripts/commonFunctions.js"></script>
var p = 'Hello';
<script src="/Scripts/loginPage.js"></script>
$('#btnLogin').on('click', function() {
alert(p);
});
Returns an alert with undefined.
What I have tried:
Extensive googling! (all the answers seem to be related to javascript not being enabled.. or 404 errors or things like that.. Not with global variables from one js file being undefined in another js file.)
Removing inappbrowser, using window.open.. Won't work as the app needs to execute scripts to inspect localstorage of the site.
Re-installing the android platform using cordova.
Re-installing the plugin.
Checking chrome in the inspector to ensure the files are in sources tab (they are).
Checking that the functions in main.js also exist (they do).
Thanks, JFIT
Summary:
The problem was that a javascript file was trying to load 'SpeechSynthesis' which was undefined only in the inappbrowser.
Details:
The problem with this was confusing but here are the steps I found to debug / solve:
Set up Remote Debugging on the phone so that you can view the console of the phone using chrome://inspect/#devices
View the console of the inappbrowser site (which will show as a seperate page to the inappbrowser instance.
Identify which files are being loaded and remove files until 'undefined' errors disappear.
Add back in the most recent file and start to strip out various functions (especially functions/variables before document.ready (global variables also)
Find the line/variable that way. It was handy for me this way as the actual undefined variable showed up after I removed most of the files.
The actual cause of my error was the speechSynthesis functionality.
The speechsynthesis lines were removed, and I readded all remaining files and everything works. This function works fine in chrome on desktop/android but not in the inappbrowser.

The javascript isomorphic application with IMA.js

I tried creating my first javascript isomorphic application with IMA.js framework (https://github.com/seznam/IMA.js-skeleton
). At first glance I have a few questions:
Calling "gulp.dev" opens new Chrome window.
a) Why Chrome? Can I change it? What if I use Firefox? What if I don't have Chrome at all?
b) Why can't I close the window?
There's recommendation for using IMAError. Why is that?
Why do I have to forward $Utils to props? What is it's function?
How exactly communicates Controller with View?
I will try answer your questions:
IMA.js has unit tests that are launched on file saved. For running IMA.js and your tests is used Karma. Karma need some launcher.
a) Chrome is used as a default launcher for Karma. In karma.conf it is possible to change one loader to another one (Firefox, Opera, ...)
b) You need this browser window for tests. When PhantomJS 2.0 launcher will be released, it will be the default launcher. After this change it will run in background.
IMAError is inherited from native error. But it gives you the option to add other parameters into error data - for example: status code, url etc. It solves some issues with stack, too.
$Utils is the set of utilities, helpers or tools for React components. It allows you to pass whatever you want into the component. For example: Router for link generation, Dictionary for translations, EventBus for firing events to controller etc. $Utils are automatically available in this.utils property inside every component that have $Utils property set.
Controller is setting React state of view. (See https://medium.com/react-tutorials/react-state-14a6d4f736f5) From View to Controller communication you could use EventBus or whatever you want (Dispatcher).

Lazy loading knockoutjs with bookmarklet failing

I'm attempting to fix a bookmarklet I wrote to track the URL changes in a single page application, specifically recording timesheet while using asana. It uses a script loader to embed jQuery and KnockoutJS libraries before init. I'm unable to find the ko object in global scope after the KnockoutJS library has initialized and cannot figure out why. To test, login to https://app.asana.com, open the Google Chrome developer tools' Console tab and try the following code:
var koScript=document.createElement('script');
koScript.type='text/javascript';
koScript.src='//ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js';
document.getElementsByTagName('head')[0].appendChild(koScript);
The Network tab shows the script downloading. The Elements tab shows the script as the last child of the head element. Yet ko remains undefined.
The short version is that:
Asana uses an internal module system that uses module.exports and require - the CommonJS standard you may know from node.js.
The knockout.js file checks the environment to determine if it should be setting window.ko or using module.exports or AMD-style define. If it detects CommonJS-style require it sets properties on exports instead of on a global ko object.
Workaround:
You could temporarily "copy" require off first:
_require = require; require = null
And then it should set window.ko as you're expecting!

flashfirebug getting data from actionscript 3 console

My need was to capture data (text data) from flash in a web page.
The data is always changing (wheather data) and this should be exported do a text file so i could manipulate this data.
I tried do this with and my first approach was using a websniffer like fiddler or wireshark.
I used that but could't get data from both because it is embedded in flash.
I used fidler as man-in-midle with wireshark deciphering the data (with the private key from the site cer) but it didn't worked.
After that i tried using flashfirebug pro (the pro allows to run as3 comands in the console). This addon loads the dom tree and refreshes it. After selecting in the page the desired element with inspector (it shows in the left panel the instance and position in the dom) i have acess to the instance properties (and the only one needed is the "html-text" in the right panel).
My problem with this last approach was that it could not communicate with the local file system (if i make "trace(this.text);" in the console it shows the text value but it just shows in the console). The only way to communicate to the file in the hard drive, that i could think of was to throw some error to the log file but could't do that also.
Does anyone have any idea to work with flashfirebug or have some other approach to do this.
Regards,
if you want to work on local filesystems use adobe air.
if you can't, try to work around the browsers sandbox with javascript as bridge to some browser-plugin/-addon which gives you access to local processes and filesystems. to use javascript from flash the ExternalInterface class is your friend.

Categories

Resources