addon firefox - open window with specific dimensions - javascript

I have made an addon for firefox. I install it but i have two problems.I use windows.open because the panel isn`t suitable for me because if the user want to copy something in it, the panel is disappearing when he leaves it. So i have windows. I have this code:
var widgets = require("sdk/widget");
var windows = require("sdk/windows").browserWindows;
var self = require("sdk/self");
var widget = widgets.Widget({
id: "open window",
label: "test",
contentURL: self.data.url("favicon.ico"),
onClick: function() {
windows.open({
url: "http://www.example.com",
onOpen: function(window) {
}
});
}
});
I don`t know where to put the attributes of width,height,no scroll :/ in order to be displayd as a popup window.
And the second problem is that the button is displayed at the bar of addons.How it is possible to display it at the nav bar next to firebug?

The windows module does not support specifying window features.
You could use the unstable window/utils module and the openDialog function to provides.
Or you could get yourself chrome privileges and re-implement the stuff yourself. The implementation of openDialog is surprisingly pretty straight forward and can be borrowed from easily.
Either way, you'll need to wait for a window to actually fully load (newWindow.addEventListener("load", ...)) before you can safely interact with it. Or get somewhat hackish and listen for the first open event via the windows module.

Related

How can you replicate a chrome browser_action popup using firefox addon sdk?

I'm porting a chrome extension to firefox. I'm trying to create a button that shows a popup HTML just like chrome. This is what I have so far in the main index.js:
var panels = require("sdk/panel");
var buttons = require("sdk/ui/button/action");
var manifest = require('manifest.json');
var url = function(path) {
return self.data.url('../' + path); //get out of the "data" directory
};
var popupButton = buttons.ActionButton({
id: "show-popup",
label: manifest.browser_action.default_title,
icon: {
"16": url("icon16.png"),
"32": url("icon32.png"),
"64": url("icon64.png")
},
onClick: function(){
//this doesn't work for debugging JS
//tabs.open(url(manifest.browser_action.default_popup));
//reload the content, like chrome, and show the popup
popup.contentURL = 'about:blank';
popup.contentURL = url(manifest.browser_action.default_popup);
popup.show();
}
});
var popup = panels.Panel({
contentURL: url(manifest.browser_action.default_popup),
position: popupButton
//contentScriptFile: ... get from HTML?
});
The buttons shows the HTML, however, the javascript which chrome makes you include via <script type="text/javascript" src="..."></script> tags doesn't appear to have access to self.port. Also, there seems to be no way to debug code in a panel. I've seen it suggested you open the HTML as a tab rather than a panel for debugging, but then it's running in a different environment and neither self nor addon are defined.
Unlike chrome, firefox wants you to give the javascript for the panel separately, using contentScript contentScriptFile as a Panel argument. One idea I had was to extract and remove all the <script> tags from the HTML, then give the remaining HTML to the panel and pass in the scripts separately. However, the panel wants a URL and not HTML. Also, it's starting to feel like too much hackery.
How can I replicate the chrome browser_action functionality in firefox? I would like to be able to use the same files in both chrome and firefox and not have a second build script which processes files depending on the target browser.
Is there a better way to debug a panel, like in chrome with right click and inspect?

How to add a right click on my Firefox extension's icon?

Good Day!
I've searched and searched again and I didn't find any help for this problem...
Context :
I've developed a Google Chrome extension that is very simple: send email to somebody with one click. To configure this, there is an option page on this extension to set the email address to which to send. My Google Chrome extension is available here (English translation, just the text, not the install).
Users have asked me to make this extension for Firefox so I'm working on it!
I've read tutorials on cfx and it's OK. But I need to have my extension respond to a right-click on my extension's icon in the toolbar. Not on the page, on my icon.
I'm using ActionButton (or ToggleButton) to add my icon to this the toolbar but I can't find a way to add a menu on the right click (there's already the default Firefox context menu but I want to add "Options".)
If somebody has the solution it would be great!
(I'm not familiar with XUL. So, if possible, a JavaScript only solution, please ^^ )
PS : I'm French so please excuse me for my bad English
EDIT : I've found how to set preferences in my "package.json" file but I want my own window.
And if we could "bind" the button "Options" in Add-on Manager to my own window it would be perfect!
EDIT 2 : as it's not clear for everyone I would detail here what I want for my extension :
- simple click (left click) on the icon get the current URL and send it to a mail address (OK for this)
- simple click ONLY DO THIS. This extension aims to be very very simple !
- right click on the icon shows Firefox's context-menu and I want to add "Options" here to show my options page
- Addon Manager could have a "Options" button near "Deactivate" and "Debug" and I want this option button to show my options page.
=> 2 way to see my option page : by the right click or by the addon manager and this is why I need your help !
General UI comments
Using right-click to directly activate your function is contrary to the general UI that is used system wide. Right-click is, system-wide (on some systems), used to open the context menu. In Firefox in the toolbar this is used to bring up the context menu for the toolbar area. This is what your users are generally going to expect to happen when they use right-click. You are probably better off either using something like shift-left-click, or letting the user define what combination is to be used to activate your function. If it is that you are attempting to add an option to the context menu, then that would normally be accessed via right-click.
Alternatives used in other add-ons:
A second section to your button with a down arrow. Clicking on the down arrow opens an expanded action or options menu.
Use the tooltip to display an action or options menu when the mouse is hovered over your button. This is done by creating a custom tooltip by enclosing the popup within a <tooltip id="myTooltip"></tooltip> element and referencing it in the button with <button tooltip="myTooltip"/> (tooltip property, tooltip attribute).
Using right-click
The problem appears to be that the Add-on SDK ActionButton has abstracted away your ability to have listeners for arbitrary events. It also does not give you access to the actual event object which is normally passed to event handlers (listeners). Further, its click event appears to actually be a command event, not a click event. One of the significant differences between a click and a command event is that the command event does not normally fire on a right-click.
You are going to need to gain access to the button outside of the ActionButton interface and add a listener for click events and then in your click event handler, you can make a choice to perform your action based on the state of event.button and event.shiftKey.
Adapting some code based on what I posted as an answer for a different question, you are going to want something like (not tested with modifications):
function loadUi(buttonId) {
if (window === null || typeof window !== "object") {
//If you do not already have a window reference, you need to obtain one:
// Add a "/" to un-comment the code appropriate for your add-on type.
/* Add-on SDK:
var window = require('sdk/window/utils').getMostRecentBrowserWindow();
//*/
/* Overlay and bootstrap (from almost any context/scope):
var window=Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
//*/
}
forEachCustomizableUiById(buttonId, loadIntoButton, window);
}
function forEachCustomizableUiById(buttonId ,func, myWindow) {
let groupWidgetWrap = myWindow.CustomizableUI.getWidget(buttonId);
groupWidgetWrap.instances.forEach(function(windowUiWidget) {
//For each button do the load task.
func(windowUiWidget.node);
});
}
function loadIntoButton(buttonElement) {
//Make whatever changes to the button you want to here.
//You may need to save some information about the original state
// of the button.
buttonElement.addEventListener("click",handleClickEvent,true);
}
function unloadUi(buttonId) {
if (window === null || typeof window !== "object") {
//If you do not already have a window reference, you need to obtain one:
// Add a "/" to un-comment the code appropriate for your add-on type.
/* Add-on SDK:
var window = require('sdk/window/utils').getMostRecentBrowserWindow();
//*/
/* Overlay and bootstrap (from almost any context/scope):
var window=Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
//*/
}
forEachCustomizableUiById(buttonId, unloadFromButton, window);
}
function unloadFromButton(buttonElement) {
//Return the button to its original state
buttonElement.removeEventListener("click",handleClickEvent,true);
}
function handleClickEvent(event) {
If( (event.button & 2) == 2 && event.shiftKey){
event.preventDefault();
event.stopPropagation();
doMyThing();
}
}
function doMyThing() {
//Whatever it is that you are going to do.
}
As should be implied by the above code, you will need to make sure to remove your listener when uninstalling/disabling your add-on. You will also want to make sure that loadUi() gets called when a new window opens so that your handler is added to the new button.
Adding to the context menu
There is no direct way to change the context menu just for your icon. The ID for the context menu is toolbar-context-menu. What you can do is add items to the context menu which are normally hidden="true". When you get the event that the right-click has happened on your icon you can change the state of hidden for those items you added. Then in an event handler that is called on the the popuphidden event for the context menu (<menupopup id="toolbar-context-menu">) you can set the state of hidden="true" for the <menuitem> element(s) which you have added to the <menupopup id="toolbar-context-menu"> in each browser window.
Something along the lines of:
function loadIntoContextMenu(win){
let doc = win.ownerDocument;
let contextPopupEl = doc.getElementById("toolbar-context-menu");
contextPopupEl.insertAdjacentHTML("beforeend",
'<menuitem label="My Item A" id="myExtensionPrefix-context-itemA"'
+ ' oncommand="doMyThingA();" hidden="true" />'
+ '<menuitem label="My Item B" id="myExtensionPrefix-context-itemB"'
+ ' oncommand="doMyThingB();" hidden="true" />');
contextPopupEl.addEventListener("popuphidden",hideMyContextMenuItems,true);
}
function unloadFromContextMenu(win){
let doc = win.ownerDocument;
let contextPopupEl = doc.getElementById("toolbar-context-menu");
let itemA = doc.getElementById("myExtensionPrefix-context-itemA");
let itemB = doc.getElementById("myExtensionPrefix-context-itemB");
contextPopupEl.removeChild(itemA);
contextPopupEl.removeChild(itemB);
contextPopupEl.removeEventListener("popuphidden",hideContextMenuItems,true);
}
function setHiddenMyContextMenuItems(element,text){
//The element is the context menu.
//text is what you want the "hidden" attribute to be set to.
let child = element.firstChild;
while(child !== null){
if(/myExtensionPrefix-context-item[AB]/.test(child.id)){
child.setAttribute("hidden",text);
}
child = child.nextSibling;
}
}
function showContextMenuItems(event){
//The target of this event is the button for which you want to change the
// context menu. We need to find the context menu element.
let contextmenuEl = event.target.ownerDocument
.getElementById("toolbar-context-menu");
setHiddenMyContextMenuItems(contextmenuEl,"false");
}
function hideContextMenuItems(event){
//This is called for the popuphidden event of the context menu.
setHiddenMyContextMenuItems(event.target,"true");
}
//Change the handleClickEvent function in the code within the earlier section:
function handleClickEvent(event) {
If( (event.button & 2) == 2){
//don't prevent propagation, nor the default as the context menu
// showing is desired.
showContextMenuItems(event);
}
}
Again, I have not tested this. It should demonstrate one way to accomplish what you desire.
However, given that we are talking about the context-menu, it is probably better to use the contextmenu event rather than the click event and testing for a right-click. In which case, we would change some of the functions above to be the following:
function loadIntoButton(buttonElement) {
//Make whatever changes to the button you want to here.
buttonElement.addEventListener("contextmenu",handleContextmenuEvent,true);
}
function handleContextmenuEvent(event) {
showContextMenuItems(event);
}
You can obtain each open primary browser window through the use of nsIWindowMediator. The following function, from MDN, will run the function you pass to it once for each open window:
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));
}
}
In the Add-on SDK:
function forEachOpenWindow(todo) // Apply a function to all open browser windows
var windows = require("sdk/windows");
for (let window of windows.browserWindows) {
todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow));
}
}
You can add a listener which calls loadIntoContextMenu for new windows with the following code (also from MDN):
Components.utils.import("resource://gre/modules/Services.jsm");
Services.wm.addListener(WindowListener);
var WindowListener =
{
onOpenWindow: function(xulWindow)
{
var window = xulWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
function onWindowLoad()
{
window.removeEventListener("load",onWindowLoad);
if (window.document.documentElement.getAttribute("windowtype") == "navigator:browser"){
loadIntoContextMenu(window);
//It would be better to only do this for the current window, but
// it does not hurt to do it to all of them again.
loadUi(buttonId);
}
}
window.addEventListener("load",onWindowLoad);
},
onCloseWindow: function(xulWindow) { },
onWindowTitleChange: function(xulWindow, newTitle) { }
};
I have implemented a menu-button that has a primary and secondary action. Although it isn't right/left click, the button has two sides:
This allows you to associate two different actions with your button without altering the usual context menu flow of Firefox. Download the files on GitHub and store them in your lib folder.
Usage is similar to other button types. Include the following code in main.js (or any js file in the lib directory)
const { MenuButton } = require('./menu-button');
var btn = MenuButton({
id: 'my-menu-button',
label: 'My menu-button',
icon: {
"16": "./firefox-16.png",
"32": "./firefox-32.png"
},
onClick: click
});
The click function will be passed the same state object as the toggle and action buttons, and will be passed an additional boolean argument: isMenu. It should be used like so
function click(state, isMenu) {
if (isMenu) {
//menu-button clicked
} else {
//icon clicked
}
}
I tried your extension on Chrome after answering this question and see that my answer probably isn't what you're looking for, so I'll make a different suggestion (leaving the other answer up because I think it is useful for people looking for multiple actions on a single button).
One thing I would say is that (some) Chrome users know that the Options menu item refers to the extension and not browser options. Those users know that the menu item is there, and use it to change their extension settings. Firefox users wouldn't expect that to be the case, because the context menu actions all affect the browser, not the extension. In the same way, (some) Firefox users know that to change their extension settings, they must navigate to about:addons (or Tools/Addons) and click the Preferences button next to the extension. This is the expected route to changing your preferences. So I would argue that adding a context-menu option is very complicated and not a good solution.
Instead, if your users haven't yet set their preferences, I think you should do what you already do in Chrome: create a Panel, associate it with your button (by using position: button in the panel constructor), and tell your users that they need to set their preferences by navigating to Tools/Addons. If you use the simple prefs module, a Preferences button will appear next to your extension and the options that you set in your package.json will be editable there.
Unfortunately, this is a very basic page, and won't look like the nice HTML options page you made.
Bonne chance.
Besides all the reservations in the other answers and without reusing the existing toolbar contextmenu, here is how:
const utils = require('sdk/window/utils');
const window = utils.getMostRecentBrowserWindow();
const doc = window.document;
const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
const { getNodeView } = require("sdk/view/core");
let ButContext = doc.createElementNS(XUL_NS,'menupopup');
ButContext.setAttribute("id","customIDString");
menuitem = doc.createElementNS(XUL_NS,"menuitem");
menuitem.setAttribute("label", "customLabelString");
ButContext.appendChild(item);
var myBut = require("sdk/ui/button/action").ActionButton({
id: "myButton",
label: "Right click me!"
// And other options
});
//Here is the context magic
getNodeView(myBut).setAttribute('context', "customIDString");
//either ; gets removed together with the button
getNodeView(myBut).appendChild(ButContext);
//or ; the correct place but needs to be removed manually
doc.getElementById("mainPopupSet").appendChild(ButContext);

Inject one line of JavaScript from firefox addon

I am completely new to FF extension creation, and I will be rather specific.
When I run a JS command in, for example, Firefox's built-in sandbox, it works just fine, so I would like to make a FF addon where on click the same JS command would execute. The command basically works in a web page:
javascript:$('.plus').click();
I suppose it doesn't have to work like this:
var Widget = require("widget").Widget;
var tabs = require('tabs');
exports.main = function() {
new Widget({
id: "user-widget-1",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(event) {
javascript:$('.plus').click();
}
});
};
Thanks.
$(.plus) is jQuery syntax so you probably want to load jQuery as a content script into your widget. And you want to run your code as a content script as well, e.g.:
var data = require("sdk/self").data;
new Widget({
id: "user-widget-1",
label: "My Mozilla Widget",
contentURL: "http://example.com/foo.html",
contentScriptFile: [data.url("jquery.js"), data.url("myScript.js")]
});
And data/myScript.js would be something like:
$(document).ready(function() {
$('.plus').click()
});
If you don't want the click to happen when the document loads but rather on a specific event happening in your extension, you might want to look into communicating with content scripts. I also recommend reading a general overview of content scripts.
Use Page-Mod to inject content-scripts into a web page, content-script linked in a widget only works in the widget content. Moreover the widget API is deprecated from FF 29, I suggest you to use a Action button instead.

Open link in new tab does not work in IE10

I am using window.open in jquery to open a link in a new tab. Works fine for me in chrome/safari/firefox, but it does not work in IE10.
$('.div').click(function() {
$(this).target = "_blank";
window.open('http://url/15M');
return false;
});
How can I fix this?
The browser itself will decide when it's appropriate to open a new tab versus a new window, though you can influence its decision via browser settings. That being said, there are often times certain things we can do to encourage one way over the other. In this particular instance, I was able to get IE10 to open a window by passing along width and height values:
$("button").on("click", function () {
window.open("http://msdn.microsoft.com", "popup", "width=640,height=480");
});
Keep in mind that you ultimately have no control over whether something opens in a new tab, or a new window. That is entirely up to the user's machine; so don't bake any user experience dependencies into this assumption.
Try following:
$('.div').click(function() {
window.open('http://url/15M', '_blank');
return false;
});

window.open won't work in Phonegap 1.7.0

I'm working with Phonegap on a mobile device. And its issues and bugs are too much to solve. One of them is:
window.open('new_window.html','well','width=300,height=200');
(I have already created a new_window.html under assets/www/.)
it appears a full screen window, and of course. If I set scroll bar option is true, it's still no use. The system is like a dummy.
I have searched the solution for several days, trying use iframe/frame to replace it. But they are not appropriate or no use. In my development environment, I just want to let the user press a button and a small window pops out. I can set the tile, location, size...
Any alternatives or suggestions?
Thanks.
You could try setting the size on the actual page that is popping up and try window.open() again, if that does not work try:
window.location.href = "newindow.html";
If that does not work either and you could try using a jQuery Dailog box (need to import the jQuery Library found here jQuery) as the popup, code would be something like this:
$(document).ready(function()
{
$('#buttonID').click(function()
{
$help.dialog('open');
return false;
});
var $help = $('<div></div>')
.html('Your HTML copy goes here!')
.dialog
({
autoOpen: false,
height:200,
width: 300,
title: 'Window Title'
});
});
You are treating it like a web browser when it is not a web browser. You can use the ChildBrowser plugin from https://github.com/phonegap/phonegap-plugins/tree/master/Android/ChildBrowser

Categories