addFixedBar (vs. addChild) changes behavior of button in Heading - dojox.mobile

HTML
<div id="activities"></div>
<div id="activity-edit"></div>​
JavaScript
require([
'dojo/ready', 'dojo/dom', 'dijit/registry', 'dojox/mobile/parser', 'dojox/mobile/deviceTheme', 'dojox/mobile/compat', 'dojox/mobile/Icon', 'dojox/mobile/ScrollableView', 'dojox/mobile/Heading', 'dojox/mobile/ToolBarButton', 'dojox/mobile'
],
function(ready, dom, registry, parser, deviceTheme, compat, Icon, ScrollableView, Heading, ToolBarButton, mobile) {
ready(function() {
var view_activities = new ScrollableView(null, 'activities');
view_activities.selected = true;
var heading = new Heading({
label: 'Activities',
fixed: 'top'
});
view_activities.addFixedBar(heading);
var button = new ToolBarButton({
icon: 'mblDomButtonWhitePlus',
style: 'float:right;',
moveTo: 'activity-edit',
onClick: function(e) {
click_activity_edit(e, 0);
}
});
heading.addChild(button);
var view_activity_edit = new ScrollableView(null, 'activity-edit');
view_activities.startup();
});
this.click_activity_edit = function(e, activityid) {
var view_activity_edit = registry.byId('activity-edit');
view_activity_edit.destroyDescendants(false);
heading = new Heading({
id: 'heading-activity-edit',
label: 'Activity',
fixed: 'top'
});
view_activity_edit.addChild(heading);
var button = new ToolBarButton({
label: 'Cancel',
moveTo: 'activities',
transitionDir: -1,
arrow: 'left'
});
heading.addChild(button);
button = new ToolBarButton({
label: 'Save',
style: 'float:right;',
moveTo: 'activities',
transitionDir: -1,
onClick: function(e) {
click_activity_save(e, activityid, function() {
data.get_activities(request, handle_getActivities);
});
}
});
heading.addChild(button);
view_activity_edit.startup();
};
parser.parse();
});​
Steps to recreate the behavior:
Click the "+" button, click "Cancel", click the "+" button again, click "Cancel" again and the button no longer works.
If you replace addFixedBar with addChild, the button works as expected every time. I would do this, but I need the Heading to be fixed given that it is on a ScrollableView.
I understand that addFixedBar adds the widget to the domNode and not the containerNode, but I don't understand why that affects the behavior of the button and only on the second pass. My guess is that it has something to do with the destroyDescendants call not actually removing the Heading when using addFixedBar. I tried destroying the Heading manually after calling destroyDescendants, but that didn't work. The heading is undefined/null on the second pass whether I get the Heading by "dom" or "registry".
Any help or explanation is appreciated.
EDIT
Here is the JSFiddle: http://jsfiddle.net/MPUvk/

The key is the startup() calls.
The view_activity_edit.startup() call will work only once (startup() sets an internal _started flag and does nothing when it is already set). The second time the view is created, startup() does nothing.
The different behaviors between addFixedBar and addChild are because addChild calls startup() internally, whereas addFixedBar does not.
So to fix, just add heading.startup() after the addFixedBar call, that should work.
Another possibility would be to reset view_activity_edit._started = false when you destroy the view.

Related

Firefox Addon SDK onMouseover Event for a Button

With the coming of multi-process Firefox, I have decided to revamp my addon. It is a toolbar addon that was built on XUL. Now I want to build it using the Addon SDK.
The old XUL overlay allowed for onMouseOver events for buttons. But the new addon SDK only has the one listener for click.
How can I get an onMouseOver (Hover) event for a toolbar button?
Maybe there is some way to add css (:hover) to the button element?
I found this, and am working on getting it in order, but maybe there's a better way?
Here is what I have so far:
var {Cu, Cc, Ci} = require("chrome");
Cu.import('resource://gre/modules/Services.jsm');
var aDOMWindow = Services.wm.getMostRecentWindow('navigator:browser');
aDOMWindow.addEventListener('mouseover', onSpatMouseover, true);
function onMyMouseover(event){
if (event.target.nodeName == 'toolbarbutton'){
console.log(event.explicitOriginalTarget.nodeName);
if(event.currentTarget.nodeName == '#MyButton'){
console.log("found the button");
}
}
}
But it does not yet find #MyButton.
First of all, error message you're getting already tells you how to make it work.
But it's not necessarily what you need anyway, usually sdk/view/core provides access to the underlying XUL elements through one of its 3 methods.
Here is a complete example of how to do this. There are two functions, actually, one for mouseover and one for mouseout. If you change the icon of a button using mouseover, you need mouseout to change it back to normal.
const { browserWindows } = require("sdk/windows");
const { CustomizableUI } = require('resource:///modules/CustomizableUI.jsm');
const { viewFor } = require("sdk/view/core");
const { ActionButton } = require("sdk/ui/button/action");
var myButton = ActionButton({
id: "mybutton",
label: "My Button",
icon: { "16": "./icon-16.png", "32":"./icon-32.png", "64": "./icon-64.png" },
onClick: function(state) {
console.log("My Button was clicked");
}
});
//create a mouseover effect for a control
exports.MouseOver = (whatbutton, whatwindow, whatfunction) =>{
CustomizableUI.getWidget( viewFor(whatbutton).id ).forWindow(whatwindow).node.addEventListener('mouseover', whatfunction, true);
};
exports.MouseOut = (whatbutton, whatwindow, whatfunction) =>{
CustomizableUI.getWidget( viewFor(whatbutton).id ).forWindow(whatwindow).node.addEventListener('mouseout', whatfunction, true);
};
function myMouseOverFunction(){
console.log("mousing over...");
}
function myMouseOutFunction(){
console.log("mousing out...");
}
//add events to the browser window
for(let w of browserWindows){
exports.MouseOver(mybutton, viewFor(w), myMouseOverFunction);
exports.MouseOut(mybutton, viewFor(w), onMouseOutFunction );
}

Updating UI of firefox addon using sdk

I am writing a simple firefox addon using addon-sdk-1.17 . I am having trouble updating the UI of my addon. If I do a cfx run, the addon looks normal, but if I do "cfx xpi" and load it into a profile that already has a previous version of the addon, well thats where I run into problems.
A simple example of this can be seen by an example mozilla has in their toolbar tutorial. It can be found at: https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/ui_toolbar
If I package (cfx xpi) the following code (assuming the icons and html file exist), it works as expected:
var { ActionButton } = require('sdk/ui/button/action');
var { Toolbar } = require("sdk/ui/toolbar");
var { Frame } = require("sdk/ui/frame");
var previous = ActionButton({
id: "previous",
label: "previous",
icon: "./icons/previous.png"
});
var next = ActionButton({
id: "next",
label: "next",
icon: "./icons/next.png"
});
var play = ActionButton({
id: "play",
label: "play",
icon: "./icons/play.png"
});
var frame = new Frame({
url: "./frame-player.html"
});
var toolbar = Toolbar({
title: "Player",
items: [previous, next, play, frame]
});
But if i want to add an additional button to it and I decide to change the url of the frame, they don't update to the toolbar. For example, after loading the above addon into my profile, if I make the following changes to the main.js:
var { ActionButton } = require('sdk/ui/button/action');
var { Toolbar } = require("sdk/ui/toolbar");
var { Frame } = require("sdk/ui/frame");
var previous = ActionButton({
id: "previous",
label: "previous",
icon: "./icons/previous.png"
});
var next = ActionButton({
id: "next",
label: "next",
icon: "./icons/next.png"
});
var play = ActionButton({
id: "play",
label: "play",
icon: "./icons/play.png"
});
var mute = ActionButton({
id: "mute",
label: "mute",
icon: "./icons/mute.png"
});
var frame = new Frame({
url: "./new-frame-player.html"
});
var toolbar = Toolbar({
title: "Player",
items: [previous, next, play, mute, frame]
});
The toolbar will not have either (frame-player.html or new-frame-player.html) loaded on the toolbar, and the mute button will not be located on the toolbar either. Again, this works fine for "cfx run" or if I install the addon to a profile that doesn't have the previous version of the addon.
I assume there is something dumb I am doing or there is an easy solution, but I haven't seen documentation on this anywhere. Not sure if I just overlooked something or what.
The "problem" here is, that Firefox saves the location where buttons had been manually placed, even when the extension is uninstalled. You can reset this data by hitting "Restore Defaults" in the cutomization tab.
Alternatively you can force-move your frame using the CustomizableUI.jsm:
var CustomizableUI = require("resource:///modules/CustomizableUI.jsm");
CustomizableUI.addWidgetToArea(frame.id, "inner-" + toolbar.id);
Or if you want to move a button:
var CutomizableUI = require("resource://modules/CustomizableUI.jsm");
var { getNodeView } = require("sdk/view/core");
CustomizableUI.addWidgetToArea(getNodeView(button).id, "inner-" + toolbar.id);

Jquery ui dialog widget add buttons

I wanted to add new button to the dialog, with out loosing the previous buttons.
I had used the following code which didn't work ....
menu.dialog("open");
var buttons = menu.dialog("option", "buttons");
//$.extend(buttons, {text: label, click: function(){ alert("Added New Poker Face"); } });
buttons[label] = function () { alert("Addded New poker Face"); };
menu.dialog("option", "buttons", buttons);
I had even used extend to overwrite the buttons list, which is commented above no luck
plz any work around for this
The doc says the return value of .dialog("option", "buttons") can either be an object {label1: click1, label2: click2, ...} or an array [{"text": label1, "click": click1}, {"text": label2, "click": click2}, ...].
Have you checked the format of buttons ? If it is an array, you should .push() your new button.
We can do something like below that worked for me.....
//gets the list of buttons.
var buttons = menu.dialog("option", "buttons");
//Adds the new button to the existing list of buttons.
buttons.push({ text: label, click: function () { alert("Addded New poker Face"); } });
//Gives the new list of buttons to the dialog to display.
menu.dialog("option", "buttons", buttons);

jquery ui tooltip manual open /close

is there a way to manually open close the jquery ui tooltip? I just want it to react to a click event toggling on/off. You can unbind all mouse events and it will rebind them when calling .tooltip('open'), even though that should not initialize or set events imo, since if you try to run .tooltip('open') without initializing, it complains loudly about not being initialized.
jltwoo, can I suggest to use two different boolean switches to enable auto-open and auto-close? With this change your code will look like this:
(function( $ ) {
$.widget( "custom.tooltipX", $.ui.tooltip, {
options: {
autoShow: true,
autoHide: true
},
_create: function() {
this._super();
if(!this.options.autoShow){
this._off(this.element, "mouseover focusin");
}
},
_open: function( event, target, content ) {
this._superApply(arguments);
if(!this.options.autoHide){
this._off(target, "mouseleave focusout");
}
}
});
}( jQuery ) );
In this way, initializing the tooltip as:
$(someDOM).tooltipX({ autoHide:false });
it shows by itself when the mouse is over the element but you have to manually close it.
If you want to manually control both open and close actions, you can simply use:
$(someDOM).tooltipX({ autoShow:false, autoHide:false });
If you want to just unbind the events and woudn't like to make your own custom tooltip.
$("#some-id").tooltip(tooltip_settings)
.on('mouseout focusout', function(event) {
event.stopImmediatePropagation();
});
$("#some-id").attr("title", "Message");
$("#some-id").tooltip("open");
mouseout blocks the tooltop disappearing by moving the mouse cursor
focusout blocks the tooltop disappearing by keyboard navigation
The tooltip have a disable option. Well i used it and here is the code:
$('a').tooltip({
disabled: true
}).click(function(){
if($(this).tooltip('option', 'disabled'))
$(this).tooltip('option', {disabled: false}).tooltip('open');
else
$(this).tooltip('option', {disabled: true}).tooltip('close');
}).hover(function(){
$(this).tooltip('option', {disabled: true}).tooltip('close');
}, function(){
$(this).tooltip('option', {disabled: true}).tooltip('close');
});
Related to my other comment, I looked into the original code and achieved manual open/close by extending the widget and adding a autoHide option with version JQuery-UI v1.10.3. Basically I just remove the mouse listeners that were added in _create and the internal _open call.
Edit: Separated autoHide and autoShow as two separate flags as suggested by #MscG
Demo Here:
http://jsfiddle.net/BfSz3/
(function( $ ) {
$.widget( "custom.tooltipX", $.ui.tooltip, {
options: {
autoHide:true,
autoShow: true
},
_create: function() {
this._super();
if(!this.options.autoShow){
this._off(this.element, "mouseover focusin");
}
},
_open: function( event, target, content ) {
this._superApply(arguments);
if(!this.options.autoHide){
this._off(target, "mouseleave focusout");
}
}
});
}( jQuery ) );
Now when you initialize you can set the tooltip to manually show or hide by setting autoHide : false:
$(someDOM).tooltipX({ autoHide:false });
And just directly perform standard open/close calls in your code as needed elsewhere
$(someDOM).tooltipX("open"); // displays tooltip
$(someDOM).tooltipX("close"); // closes tooltip
A simple hotfix, until I have the time to do official pull request, this will have to do.
Some compilation from other SO questions.
Example
Show tooltip on hint click, and hide tooltip on elsevere click
$(document).on('click', '.hint', function(){ //init new tooltip on click
$(this).tooltip({
position: { my: 'left+15 center', at: 'center right' },
show: false,
hide: false
}).tooltip('open'); // show new tooltip
}).on('click', function(event){ // click everywhere
if(!$(event.target).hasClass('hint'))
$(".hint").each(function(){
var $element = $(this);
if($element.data('ui-tooltip')) { // remove tooltip only from initialized elements
$element.tooltip('destroy');
}
})
});
$('.hint').on('mouseout focusout', function(event) { // prevent auto hide tooltip
event.stopImmediatePropagation();
});

Making a panel only available for certain URLs

Chrome has something called "Page Actions", and I'm roughly trying to replicate that functionality with the Firefox Addon SDK/Jetpack. There's probably a better approach than what I've tried so far, and I'm open to suggestions.
Using tabs, I'm able to listen for tab ready and activate events, and if the tab's URL matches, the addon widget should be enabled; if not, disabled. I've got to the point where I can change the icon when appropriate, but I'd like to disable the panel as well.
Strategy 1: Steal the click event and only show the panel if we're on the right page; otherwise, ignore. Problem is, according to the docs, manually showing the panel causes it not to be anchored, a bug that's not had much progress on it.
Strategy 2: Set the contentURL to null when disabling. Get an error whining about it not being an URL.
Strategy 3: Use a different HTML document for the disabled state. Setting panel.contentURL to another URL doesn't work after going to a different page?
Here's the code:
const widgets = require("widget");
const Panel = require("panel").Panel;
const tabs = require("tabs");
const data = require("self").data;
const prefs = require("simple-prefs").prefs;
var panel = Panel({
width: 480,
height: 640,
contentURL: data.url("panel.html"),
contentScriptFile: [data.url('jquery.min.js'), data.url('panel.js')],
onMessage: function (msg) { console.log(msg) }
});
var widget = widgets.Widget({
id: "icon",
label: "Export",
contentURL: data.url("icon.png"),
panel: panel
});
function enable() {
widget.contentURL = data.url('icon.png');
panel.contentURL = data.url("panel.html");
}
function disable() {
widget.contentURL = data.url('icon_disabled.png');
panel.contentURL = data.url("panel_disabled.html");
}
function on_change_tab(tab) {
console.log(tab.url);
if (/http:\/\/example.com\/.*/.exec(tab.url)) {
console.log('ENABLE');
enable();
} else {
console.log('DISABLE');
disable();
}
console.log(panel.contentURL);
}
tabs.on('ready', on_change_tab);
tabs.on('activate', on_change_tab);
Related, but should have the anchoring problem? How to reload a widget popup panel with firefox addon sdk?
In case you still haven't solved your issue (and for anyone else having a similar problem):
I had a similar issue and resolved it by using erikvold's ToolbarButton package. Once you've installed that and its dependencies, something like this in your main.js file should work.
var pan = require("panel").Panel({
width: 400,
height: 600,
contentURL: "http://stackoverflow.com"
//maybe some more options here
});
var button = require("toolbarbutton").ToolbarButton({
id: "myButton",
label: "My Button",
image: data.url("someicon.png"),
panel: pan //This binds the panel to this toolbarbutton
});
I hope you can find some way to adapt this to your project.
toolbarbutton.ToolbarButton({
id: "MyAddon",
label: "My Addon",
tooltiptext: "My Addon Tooltip",
image: data.url("logo.png"),
onCommand: function() {
var dictionary_panel = require("panel").Panel({
width:630,
height:600,
contentURL: data.url("HtmlPage.html"),
contentScriptWhen: 'ready',
contentScriptFile: [data.url("style.css"),data.url("jquery-1.7.1.js"),
data.url("javascriptquezz.js"),data.url("create.js")]
});
dictionary_panel.show();
}
});

Resources