How to remove an event listener? - firefox

I use the Mozilla's Add-on Builder. I am looking for a way to remove an event listener in a contentScript. I use the port way to communicate between add-on script code and the content script code.
The problem is the callback on event "response" is called more than once. I want it to be called once and declared in the callback of the event show.
Can someone help me with that?
main.js code:
var Panel = require("panel").Panel;
var popup_panel = Panel({
width: 286,
height: 340,
contentURL: require("self").data.url("popup.html"),
allow: { script: true },
contentScriptWhen: "end",
contentScriptFile : [
require("self").data.url("test.js")
],
onShow: function(){
this.port.emit("show");
var pan = this;
this.port.on("hide", function(){pan.hide();});
}
});
var Widget = require("widget").Widget;
var widget = Widget({
id: "mozilla-icon",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
panel: popup_panel
});
popup_panel.port.on("get", function(){
popup_panel.port.emit("response");
});
Content script (test.js):
self.port.on("show", function(){
console.log("show");
function response(){
console.log("reponse called");
}
self.port.emit("get");
self.port.once("response", response);
self.port.removeListener("response", response);
});
full source code

Finally I found the problem. It is a bug in the add-on kit. In the file api-utils/lib/content/content-worker.js in the function removeListener the index is always -1.
The parameter given in the indexOf is the name of the event and it search a function. It is incorrect.
So to solve the problem I replace the line let index = listeners[name].indexOf(name); by let index = listeners[name].indexOf(callback);.
EDIT
The bug has been fixed. It will publish in the version 1.10 see here

Related

Reload jQgrid on Bootbox closing

I have jQGrid v4.6.0 (I can reproduce the same issue with Free jqGrid) on my page which I can reload using:
$('#jqGrid').trigger('reloadGrid');
It loads data by posting to a server. It posts correctly, gets the returned data correctly, and shows the correct data in the grid.
On the same page I have a link which opens a Bootbox dialog. Calling reloadGrid from within a Bootbox callback seems to make $('#jqGrid').jqGrid "not a function"
bootBoxWindow = bootbox.dialog({
title: "title",
message: "foo",
size: "large",
closeButton: false,
buttons: {
ok: {
label: "Save 2",
className: "btn-success",
callback: function () {
$('#jqGrid').trigger('reloadGrid');
}
}
}
});
When this calls reloadGrid, jqGrid properly posts to my server and retrieves the latest data. However, inside the loadComplete event I can no longer refer to jQuery("#jqGrid").jqGrid.
Example:
jQuery("#jqGrid").jqGrid('showCol', 3);
... calling this inside loadComplete gives error: TypeError: jQuery("#jqGrid").jqGrid is not a function"
I get the same error when using $(this) instead of jQuery("#jqGrid").
I cannot reproduce the issue without Bootbox. If I load the grid, then use this:
setTimeout(function () {
$('#jqGrid').trigger('reloadGrid', [{ current: true }]);
}, 10000);
... there is no error.
The first that I think is that the modal function is outside the jqGrid scope.
Example:
(function($) {
$(function() {
....
var $grid = $("#grid").jqGrid({...});
.....
console.log($grid);
});
})(jQuery);
console.log($grid);
The first console.log will output grid object, the second will throw error.
You may want to look at this article

CKEditor toolbar close button right align

I want to add a close a button in CK Editor (v4.4) and want to align it right, below screen shot shows the end product.
With the help of documentation from CKEditor website I was able to create a simple close plugin. With the help of little jQuery hack I am able align it right but if possible I would like to align it using standard toolbar creation approach rather then below hack.
Current working hack
<script>
$(document).ready(function () {
var rteComment = CKEDITOR.replace("txtPluginDemo", {
toolbar: [
['NumberedList', '-', 'Image'],
['Save'],
['CKClose'],
],
toolbarCanCollapse: false,
allowedContent: 'p img ol br',
disallowedContent: 'script',
extraAllowedContent: 'img[*]{*}(*)',
extraPlugins: 'ckclose',
image_previewText: "Image preview will be displayed here.",
disableNativeSpellChecker: false,
//If true <p></p> will be converted to <p>&nbsp,</p>
fillEmptyBlocks: true,
removePlugins: 'contextmenu,liststyle,tabletools',
skin: 'moonocolor',
});
rteComment.on("close", function (evt) {
alert("Ok time to close it.");
return true;
});
rteComment.on("instanceReady", function (evt) {
//THIS IS HACK
$(".cke_button__ckclose").closest(".cke_toolbar").css({ "float": "right" });
});
})
</script>
I am hoping that there will be some option in the below code which will let me specify the my css class here.
CKEDITOR.plugins.add('ckclose', {
// Register the icons. They must match command names.
icons: 'ckclose',
// The plugin initialization logic goes inside this method.
init: function (editor) {
// Define an editor command that inserts a timestamp.
editor.addCommand('closeEditor', {
// Define the function that will be fired when the command is executed.
exec: function (editor) {
if (editor.fire("close")) {
editor.destroy();
}
}
});
// Create the toolbar button that executes the above command.
editor.ui.addButton('CKClose', {
label: 'Discard changes and close the editor',
command: 'closeEditor',
toolbar: 'insert'
});
}
});
Below image is the Inspect Element View from Firefox.
I got help from the above answer slightly change the code its worked for me
CKEDITOR.on("instanceReady", function (evt) {
$(".cke_button__custom").closest(".cke_toolbar").css({ "float": "right" });
});
"custom" is my button name. Thank you,
You can put this piece
rteComment.on("instanceReady", function (evt) {
$(".cke_button__ckclose").closest(".cke_toolbar").css({ "float": "right" });
});
rignt inside
init: function( editor ) {
(e.g., before its closing bracket). That should be enough.
Also, you don't need to put initialization info in a SCRIPT tag of your main file. It can be cleaner to use config.js
http://docs.ckeditor.com/#!/guide/dev_configuration
Also, see an interesting example of a plugin here:
How to add an ajax save button with loading gif to CKeditor 4.2.1. [Working Sample Plugin]

Find URL of current tab. Making a FireFox Browser add-on

I'm making a Firefox Browser Add-on and need to find the url of the current tab
I've tried this post Opening a URL in current tab/window from a Firefox Extension but it tells me that 'window' is not defined. (I think because I am making an add-on rather than an extension.)
Here's what I've tried to do:
var widgets = require('widget');
var tabs = require('tabs');
var widget1 = widgets.Widget({
id: "widget1",
label: "widget1",
contentURL: "http://www.mozilla.org/favicon",
onClick: function() {
console.log(tabs.url);
}
})
I've made a widget such that when I click it the url of the current tab should be 'console.log'ed.
Doesn't seem to happen! Keep getting "info: undefined" which clearly means that tabs.url isn't returning anything. But this seems to be the way to use it according to https://addons.mozilla.org/en-US/developers/docs/sdk/1.5/packages/addon-kit/docs/tabs.html
Anyone have any ideas?
Thanks,
Will
You're almost there:
const { ActionButton } = require("sdk/ui/button/action");
const clipboard = require("sdk/clipboard");
const tabs = require('sdk/tabs');
let button = ActionButton({
id: "my-button-id",
label: "Button Label",
icon: {
"32": "chrome://mozapps/skin/extensions/extensionGeneric.png"
},
onClick: function(state) {
let url = tabs.activeTab.url;
console.log("active tab url:", url);
require("sdk/notifications").notify({
title: "Active Tab's Url is "+url,
text: "Click to copy.",
onClick: function() {
clipboard.set(url);
}
});
}
});
You should check out the documentation on the tabs module.
Note: I've updated this code example to use the new ui modules available since Firefox 29 - the 'widget' module used in the original question was valid at the time but has since been deprecated and then removed.

"sessionstore-state-read" observer not working

Im currently making a firefox extension that will let you choose what tabs you want to reopen after startup, instead of opening everything (it opens about:sessionrestore page). My JS code looks like this:
Edit: code updated with working version
chrome.manifest
component {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} components/myextension.js
contract #example.com/MyExtension;1 {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
category profile-after-change MyExtension #example.com/MyExtension;1
components/myextension.js
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const CI = Components.interfaces, CC = Components.classes, CR = Components.results;
// class declaration
function MyExtension () {}
MyExtension.prototype = {
classDescription: "My Firefox Extension",
classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
contractID: "#example.com/MyExtension;1",
QueryInterface: XPCOMUtils.generateQI([CI.nsIObserver]),
// add to category manager
_xpcom_categories: [{
category: "profile-after-change"
}],
observe: function(aSubject, aTopic, aData)
{
var obs = CC["#mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
switch (aTopic)
{
case "profile-after-change":
obs.addObserver(this, "sessionstore-state-read", false);
break;
case "sessionstore-state-read":
aSubject.QueryInterface(CI.nsISupportsString);
let newData = { windows: [{ tabs: [{ entries: [{
url: "about:sessionrestore",
formdata: { "#sessionData": aSubject.data }
}] }] }] };
aSubject.data = JSON.stringify(newData);
break;
default:
throw Components.Exception("Unknown topic: " + aTopic);
}
}
};
if (XPCOMUtils.generateNSGetFactory)
var NSGetFactory = XPCOMUtils.generateNSGetFactory([EmbarrassedObserver]);
else
var NSGetModule = XPCOMUtils.generateNSGetModule([EmbarrassedObserver]);
It works fine with sessionstore-state-write (commented lines), but i want to do it with the sessionstore-state-read event, cuz i dont want to edit what it writes to the disk. The problem is, when i change to the read event, my observer stops working. My guess is i register the observer too late (after the session is read), so i tried to register it as soon as possible (when the extension is first loaded, insted of window load event), but it still wont work. Any idea how to get it working?
You need to write your extension as an XPCOM component that listens to the profile-after-change notification (the first notification that extensions are allowed to listen to). Then your component will be able to listen to the sessionstore-state-read notification.

Custom Event For Custom JQuery Plugin

I made this jQuery plugin called removable when you click the objects button it slides up and should trigger a custom event like onDone.
Here's what I did (The codeing format is based on jQuery's http://docs.jquery.com/Plugins/Authoring):
init: function(){
return this.each(function(){
$('a', this).click(function(){
$(this).parent().slideUp(function(){
// Somehow trigger the onDone method
})
});
})
},
onDone: function(){
// Default action
},
and this is what I've done when calling the plugin
$('li').removable({
onDone: function(){
// Overwrite default action
},
})
How can this be done?
If all you need is to call it at the end of the animation, just pass it as the second argument to slideUp or even just call it with $(foo).MyPlugin.onDone() inside the callback function.
otherwise look at trigger and bind jQuery functions - you can use any string you want for those event types so you can trigger and bind a MyPluginDone event
EDIT: based on comments you want something simpler -
As it states in the article you quoted, the best way to provide override-able defaults to options is to have your plugin accept an options object, then to get the combined defaults+overrides you do:
var combinedOpts = $.extend({},defaults,overrides);
and get all the values to use from there...
Try this one.
(function($){
jQuery.fn.extend({
removable: function(options) {
var defaults = {
onDone: function(){alert('default action');}
};
var options = $.extend(defaults, options);
return this.each(function() {
$('a', this).click(function(){
$(this).parent().slideUp(function(){
options.onDone.call();
});
});
});
}
});
})(jQuery);
$('li').removable({
onDone: function(){
alert('Overwrite default action');
},
})

Resources