Open responsive view from Firefox WebExtension - firefox

I have a legacy add-on for firefox, that opened tabs in responsive view. To achieve this, I used the functions from the responsive design module available in
try { Components.utils.import("resource://devtools/client/responsivedesign/responsivedesign.jsm", respdsgn);
} catch (e) {
try { Components.utils.import("resource:///modules/devtools/responsivedesign.jsm", respdsgn);
} catch (e) {
respdsgn = null;
}
}
From what I understand, this is no longer possible using the new web extensions api. Is there an alternative api available to turn the responsive view on for a specific tab? Or is it still possible to use the old style somehow?
Thanks for any pointers!

The old style (or a variant) cannot be used to open the responsive view. An API to open the reponsive view doesn't exist (yet) in WebExtensions and there is no feature request pending. If you want, you can create one here: http://bugzilla.mozilla.org/
(select WebExtensions - Untriaged as product)
The closest thing to achieve the same result, is implement the responsive design mode yourself. This shouldn't be hard to do, since you just have to change the width and the height of the "html" element.
Content script:
document.getElementsByTagName("html")[0].width = "250px";
Good luck!

Related

Firefox extension: share state

I have a Firefox overlay extension with a tree in a sidebar.
How can I keep the tree state synchronized in several windows?
For example in first window added new item in tree, how update tree in other windows?
If somebody can show minimal code for it (with use code modules, observers, broadcasters or something else), please help.
I read similar question, but it did not help:
Firefox extension - Share common state between two or more windows
The answer in the question you reference is good, but short on explanation. You should read the references to which it links. I have duplicated those links here.
One way to keep state information outside of a window context is to use JavaScript code modules (JSM). The section Sharing objects using code modules talks briefly about doing this. Once you have set up your JSM to share the data, it is merely a matter of informing each window that a change has been made and it should update the displayed state. This is easily accomplished by using an event which you define. All of the sidebars listen for a particular event in their window. Then there is one function in the JSM which runs through all the windows signalling them that they need to update.
The code to signal could look something like:
Components.utils.import("resource://gre/modules/Services.jsm");
function forEachOpenWindow(todo) {
// Apply a function to all open browser windows
var windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow));
}
}
function signalUpdateNeeded(window){
let event = window.document.createEvent("Event");
event.initEvent("myExtensionName-UpdateAvailable",false,false);
window.dispatchEvent(event);
}
function sendUpdateAvailableToAllWindows(){
forEachOpenWindow(signalUpdateNeeded);
}
Then in the code for the sidebar:
//This imports your JSM, it does not need the .jsm extension, you can use
// whatever extension you want.
Components.utils.import("chrome://MyExtension/content/moduleName.jsm");
window.addEventListener("myExtensionName-UpdateAvailable",
updateDataFromModule, false);
//Instead you may need the following (or another way to get to the
// top window). What is actually needed will depend on the context in
// which your sidebar code is running. You should see below for code to
// access the main browser window from within a sidebar.
//window.top.addEventListener("myExtensionName-UpdateAvailable",
// updateDataFromModule, false);
function updateDataFromModule(){
//Whatever it is you need to do here.
mylocalVariable = myExtensionModule.dataStructure.whatever;
}
Refactoring the first code section above so that it looks like it is in a module that uses one variable to reduce namespace clutter. The code for the module could be something like:
var EXPORTED_SYMBOLS = [ "myExtensionModule" ];
Components.utils.import("resource://gre/modules/Services.jsm");
var myExtensionModule = {
dataStructure: {
whatever: true,
you: 1,
want: ["here.", "It", "is", "your", "data."]
};
forEachOpenWindow: function(todo){
// Apply a function to all open browser windows
var windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
todo(windows.getNext()
.QueryInterface(Components.interfaces.nsIDOMWindow));
}
},
signalUpdateNeeded: function(window){
let event = window.document.createEvent("Event");
event.initEvent("myExtensionName-UpdateAvailable",false,false);
window.dispatchEvent(event);
},
sendUpdateAvailableToAllWindows: function(){
this.forEachOpenWindow(this.signalUpdateNeeded);
}
}
I have not actually tested this, so there may be some errors.
Having either your sidebar code access the main browser window, or the JSM code find which sidebar your code is in (in order to send or listen fro events) may be a bit more complicated than you think. You should see Working with windows in chrome code. Specifically, Accessing the elements of the top-level document from a child window. That section provides the following code to access the main browser window from within a sidebar:
var mainWindow = window
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
An alternative is for your JSM to keep a reference to an object in the data structure on which all of the sidebars place listeners. This could be an object which it creates. If you do use this method and choose to use a window, then you need to make sure that handle releasing the reference if the window is closed. If you don't you could end up with a memory leak.

How to access the content of a webpage displayed in a tab from a Firefox addon

In a Firefox extension, I am attempting to add a form into the web page by inserting DOM elements, and then process any data that the user enters in the form.
I have tried several methods, but have been unable to get my form inserted into the webpage's document. I tried using the different types of add-ons, Overlay (XUL) and the Add-on SDK, but I have not been able to get it to work.
Overlay/XUL: I investigated and found nothing that specifically showed me how to change the contents of a web page.
Using the Addons SDK: The only working code which I found was the demo code in "Modifying Web Pages Based on URL" which appeared to give:
var html = sth;
$("body").html(html);
I tried:
$('.id_of_ele').html('I want to show');
It doesn't work.
So far the only thing which has gotten me close is to use unsafeWindow.document, but I believe that is a really a bad idea, and the code looks really bad.
How do I access the the document of a webpage from a Firefox extension?
If you are looking for examples of known working code, you can always download one or more extensions from Mozilla Add-ons which do something close to what you want to accomplish and look at how they do it. Obviously, you should look at the license (linked on each extensions page) to see what the legal status of the code it. There are literally thousands of working examples there. The vast majority of which have code which is licensed in a way which permits you to re-use it.
The jQuery accesses which you are trying to use rely on the document variable pointing to the document which you are wanting to modify. In the context in which you are running, a Firefox add-on, the document variable may, by default, point to a document which is an ancestor of the webpage you are interested in or not be defined at all. What document actually is will depend on the context from which your add-on code was invoked. In a Firefox add-on, the document variable will almost never, by default, point to the content of a web page. You have to remember that you are writing code that is intended to run in a context that is much larger (entire browser/user agent) than that which is used for content scripts on a webpage (context within the browser is restricted to only the content of the webpage from which the script was run, or data which is obtained from references originating from within the page).
Gaining access to the document for the currently selected tab:
Changing the content document is very easy. You can change it just like you would from any JavaScript. The issue that you may find frustrating is obtaining a reference to the document.
Firefox overlay and restartless/bootstrapped have a great amount of power over the entire browser. However, the context, and what window points to, or even if it is defined, depends greatly on how the JavaScript was invoked. This can be both confusing and frustrating. On MDN, there is a document "Working with windows in chrome code" which describes many of the issues.
From extensions you have access to all windows and tabs. However, what you probably want is just some code that works to get you access to the current selected document.
This should work from all contexts to get you a reference to the document for the currently selected tab:
var selectedTabWindow = Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
var selectedTabDocument = selectedTabWindow.content.document;
If you have code which you are converting from a content script which just expects to find window and document objects, you could write something like:
if (typeof window === "undefined") {
var window;
} else {
//Keep a reference to whatever was defined as window.
var originalWindow = window;
}
//Get the window from the most recently selected tab.
window = Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
//Now that we have a window for the most recently selected tab,
// get the document for it.
if (typeof document === "undefined") {
var document;
} else {
//Keep a reference to whatever was defined as document.
var originalDocument = document;
}
document = window.content.document;
//Now that we have a window for the most recently selected tab,
// get the gBrowser for it.
if (typeof gBrowser === "undefined") {
var gBrowser;
} else {
//Keep a reference to whatever was defined as gBrowser.
var originalGBrowser = gBrowser;
}
gBrowser = window.gBrowser;
The above will, obviously, overwrite any currently variables currently defined as window, document and gBrowser. Depending on the context in which you are running, and the scope in which you define these this could be either a good thing, or it might be a bad idea to change that reference. For example, if the code is running in a popup window then window is a reference to window of the popup. In that case, you can get a reference to the window from which the popup was opened with:
var windowWhichOpendedThisOne = window.opener;
var documentForWindowWhichOpendedThisOne = window.opener.content.document;
If you are in an event handler, then you can get the window for the target of the event from:
var windowInWhichEventTargetExists = event.view;
Choosing what to do based on the URL:
Once you have the correct document it should be quite easy to choose what to do based on the document's URL:
var currentUrl = document.location.href;

ckeditor disable element, prevent user from adding content to it

I've added a plugin that allows the user to add a specially styled div via a dialog. The issue now is, this element should not be clickable inside the edtior. The problem is the users manage it to click inside the div and enter text there and by this screw it up.
I've already spent some time searching the documentation but couldn't find the right approach to do this yet. I'm not asking for code, just some advice how to do it, a pointer to the right API method would be good enough for me. I guess I can somehow access the elements or intercept an users click and prevent them from adding something to my element somehow, I just couldn't yet figure out how to do it.
Use the Widget System.
Widget Tutorial.
Demos.
I've finally managed to get this done by making the elements content not editable. When I create the element in my dialog:
hrElement.setAttribute('contenteditable', false);
When loading the plugin:
init: function (editor) {
editor.on('contentDom', function () {
var stiching = (this.document.getElementsByTag('div'));
console.log(stiching);
for(var i=0;i<stiching.count();i++){
if (stiching.getItem(i).hasClass('stitching')) {
stiching.getItem(i).setAttribute('contenteditable', false);
}
}
});
}
I'm pretty sure this is not the most best solution (don't like to iterate over the elements) but at least it works for me now. Any suggestions how to improve it for future cases are welcome.

Disable X-Frame-Option on client side

I would like to disbale the X-Frame-Option Header on client side on Firefox(and Chrome).
What I've found:
Overcoming "Display forbidden by X-Frame-Options"
A non-client side solution isn't suitable for my purpose
https://bugzilla.mozilla.org/show_bug.cgi?id=707893
This seems to be pretty close. I tried creating the user.js in the profile dir with the code user_pref("b2g.ignoreXFrameOptions", true);
but it didn't work. The second last entry seems to imply compiling ff with modified code? If this is the case, it's also not a possible solution for me.
I just wrote a little HTML Page with some JS that loops a list of YouTube videos by successively loading them into an iframe. I know youtube supports playlists but they suck and I dont want to download the videos.
Also, it would be nice if the browser only ignores the X-Frame-Option for local files. This would somewhat minimize the security hole I tear open by disabling this. As for Chrome, a solution would be nice but isn't that important.
I guess another approach would be to intercept incoming TCP/IP packets which contain a HTTP Respone and remove this header line but this is quite an overkill.
[edit]
Using youtube.com/embed is a bad workaround since a lot of videos dont allow to be embedded...
This can be easily achieved using an HTTP Observer through a Firefox extension. That observer will look something like this:
let myListener =
{
observe : function (aSubject, aTopic, aData)
{
if (aTopic == "http-on-examine-response")
{
let channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
try
{ // getResponseHeader will throw if the header isn't set
let hasXFO = channel.getResponseHeader('X-Frame-Options');
if (hasXFO)
{
// Header found, disable it
channel.setResponseHeader('X-Frame-Options', '', false);
}
}
catch (e) {}
}
}
}
You can find further info such as how to install the observer on MDN[1][2]
[1] : https://developer.mozilla.org/en/docs/Observer_Notifications#HTTP_requests
[2] : https://developer.mozilla.org/en-US/docs/Setting_HTTP_request_headers#Registering
Using diegocr code, I've created an Firefox add-on to allow the displaying of webpages that have X-Frame-Options in their header, so they will be displayed when accessed via an iframe. It can be downloaded/installed here: https://addons.mozilla.org/en-US/firefox/addon/ignore-x-frame-options/
The Firefox extension mentioned by René Houkema in the other answer no longer works anymore so I created a new one.
https://addons.mozilla.org/fr/firefox/addon/ignore-x-frame-options-header/
This extension is also compatible with Quantum.
Source & updates:
https://github.com/ThomazPom/Moz-Ext-Ignore-X-Frame-Options

Safari 5 Extension: How can I detect when a window's current tab has changed?

I have a Safari 5 extension that contains a toolbar. Whenever the current tab changes, that toolbar should be updated. I would like to do something like this from my bar's script:
safari.self.browserWindow.addEventListener("activeTab", tabChanged, false);
However, that doesn't seem to work. I have tried a number of other event names as well:
activeTab
activeTabChanged
onActiveTab
onActiveTabChanged
tab
tabChanged
onTab
onTabChanged
selectionChanged
onSelectionChanged
Does anybody know how to detect when the active tab changes?
Not that this is in any way related, but it looks like I would do this in Chrome with:
chrome.tabs.onSelectionChanged.addListener(tabChanged);
Safari 5.1 has several new events for extensions, including an "activate" event that fires when a window or tab is focused.
https://developer.apple.com/documentation/safariextensions/safariactivateevent
That's the event you are looking for. I'm not sure, but i think is a new addition to the extensions api. You can put in global.html or in the popover.html
safari.application.addEventListener("activate", activateHandler, true);
function activateHandler(event) {
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage('someId', false);
}
I agree with #imiaou 's answer: from looking at Apple's docs there doesn't seem to be a way to do this :(.
Since I needed to detect tab changes for my extension (which I'm porting over from Chrome), I did the following polling-based workaround which seems to be working fine (in my global page):
var prevActiveTab;
setInterval("poorMansOnTabChange()", 1500); //poll every 1.5 sec
function poorMansOnTabChange() {
var curTab = safari.application.activeBrowserWindow.activeTab;
if (curTab != prevActiveTab) {
prevActiveTab= curTab;
console.log("active tab changed!");
//do work here
}
}
I'm unhappy with constantly polling the browser, but I see no other way around this until Apple adds support for these tab-events. If your extension can live with a relatively relaxed tab-switch event trigger latency then this could be a reasonable workaround for now (1.5 sec. max latency is acceptable for my extension, and it doesn't feel like its slowing down the browser).
While Safari doesn't have Chrome's specific tab-related API, it does have a perfect solution to this problem.
#Galt was 99% of the way there, with the idea to add an event listener to your injected JavaScript and to dispatchMessage that information to your extension.
The event handler you're looking for is named focus, and gets fired every time a tab or window gets selected.
In your injected code:
var tabInFocus = function( event )
{
safari.self.tab.dispatchMessage("tabFocusSwitched","");
}
window.addEventListener("focus", tabInFocus, false);
You can then update your extension's UI, with the data relevant to safari.application.activeBrowserWindow.activeTab
I found this method works better than focus event, it can be managed in the background page:
safari.application.addEventListener("validate", PopUp.validateCommand, false);
var PopUp = {
activeTab : null,
// commands are validated before being excecuted
validateCommand : function(aEvent) {
// this is a hack for detecting tab switches, safari does not have a dedicated API like Chrome
if(PopUp.activeTab !== null){
if(PopUp.activeTab !== safari.application.activeBrowserWindow.activeTab){
$.each(safari.application.browserWindows, function(aIndex, aWindow) {
$.each(aWindow.tabs, function(aIndex, aTab) {
// message all tabs about the focus switch event
if (aTab !== safari.application.activeBrowserWindow.activeTab && aTab.page) {
aTab.page.dispatchMessage("tabUnfocused");
}else{
aTab.page.dispatchMessage("tabFocused");
}
});
});
}
}
// set the new active tab
PopUp.activeTab = safari.application.activeBrowserWindow.activeTab;
}
}
This code will help to trace the change in URL :-
Write this code Inject.js , in side function
function trackURL() {
alert("beforeNavigate "+safari.application.activeBrowserWindow.activeTab.url);
setTimeout(function() {
alert("afterNavigate "+safari.application.activeBrowserWindow.activeTab.url);
}, 500);
}
safari.application.addEventListener("beforeNavigate", trackURL, true);
It seems Apple doesn't provide much API for us manipulating tabs like Chrome does.
Currently, there is no way to detect tab event.
Unlike chrome which provides a special API for events like window and tab changes, you can still do it with safari extensions.
You simply have to have your injected javascript set up event listeners for the events that you want.
Then if that info is needed by global or other parts of the extension, you can pass the info in messages using the postMessage command.
injected.js:
window.addEventListener("load", loaded, false);
safari.self.tab.dispatchMessage("somethinghappened","load");

Resources