PDA

View Full Version : Ext.ux.button.WindowButton



jmaia
23 Nov 2011, 10:29 AM
Hi there,

Just thought I'd share a component that I came up with on my application. It's mainly a button that has a window config object attached, and some other configuration parameters. When the button is clicked it displays the window.

The window position can be determined by the window itself or can be anchored to the button. There are 8 possible anchor positions and they can be something like:

'tl' - displayed on the top of the button, aligned to the left
'bl' - displayed on the bottom of the button, aligned to the left
'lt' - displayed on the left of the button, aligned to the top
etc.

It still has some room for improvement (for example I'm not dealing with the situations where the anchored window goes outside the boundaries of the browser window) but anyway, fee free to use it, if you need something like this.


/**
* A generic button, that opens up a popup window
*/
Ext.define('Ext.ux.button.WindowButton', {
extend: 'Ext.button.Button',
alias: 'widget.windowbutton',

/**
* @cfg {Object} windowConfig The config object for the window that is to be created. If an xtype is not
* provided in this config object then a plain Ext.window.Window will be used
*/
windowConfig: null,


/**
* @cfg {Boolean} closeOnClickOutside Defines whether the window will be closed automatically when the user
* clicks outside of it. Ignored if the window is modal.
*/
closeOnClickOutside: true,

/**
* @cfg {Boolean} closeOnClickTwice Defines whether the window will be closed automatically when the user
* clicks again on the button.
*/
closeOnClickTwice: true,

/**
* @cfg {String} position Defines where the window will be displayed. Can be either 'anchor', 'window'.
* If 'anchor' the window will be anchored to the button (see anchor config), if 'window' the window will be
* placed on its x and y coordinates. If no x and y are defined it will be centered.
*/
position: 'window',

/**
* @cfg {String} anchor Defines where the window will be anchored in relation to the button. Can be one of the
* following: 'tl', 'tr', 'bl', 'br', 'lt', 'lb', 'rt', 'rb'
*/
anchor: 'tl',

listeners: {
click: function() {
var me = this;

if (! me.isWindowOpen) {
me.openWindow();
}
else {
if (me.closeOnClickTwice) {
me.closeWindow();
}
}
}
},


/**
* @private
*/
initComponent: function() {
var me = this;

me.callParent();

Ext.apply(me, me.initialConfig);
if (me.windowConfig && me.windowConfig.modal) {
me.closeOnClickOutside = false;
}
},

/**
* @private
*/
doWindowDestroy: function(wnd, options) {
var me = this;
me.isWindowOpen = false;
},

/**
* @private
*/
doDocMouseDown: function(evt, element, options) {
var me = this;

if (me.wnd) {
if (!evt.within(me.wnd.el.dom) && !evt.within(me.el.dom)) {
me.closeWindow();
}
}
},

/**
* @private
*/
getWindowXY: function(wnd) {
var me = this;
var xy = [0,0];

if (me.position === 'window') {
xy = [wnd.x, wnd.y];
}
else if (me.position === 'anchor')
{
var box = me.getEl().getBox();
switch (me.anchor) {
case 'rb':
xy[0] = (box.x + box.width + 5);
xy[1] = ((box.y + box.height) - wnd.height);
break;
case 'rt':
xy[0] = (box.x + box.width + 5);
xy[1] = box.y;
break;
case 'lb':
xy[0] = (box.x - wnd.width - 5);
xy[1] = ((box.y + box.height) - wnd.height);
break;
case 'lt':
xy[0] = (box.x - wnd.width - 5);
xy[1] = box.y;
break;
case 'br':
xy[0] = ((box.x + box.width) - wnd.width);
xy[1] = (box.y + box.height + 5);
break;
case 'bl':
xy[0] = box.x;
xy[1] = (box.y + box.height + 5);
break;
case 'tr':
xy[0] = ((box.x + box.width) - wnd.width);
xy[1] = (box.y - wnd.height - 5);
break;
case 'tl':
default:
xy[0] = box.x;
xy[1] = (box.y - wnd.height - 5);
}
}
return xy;
},

/**
* Creates the window object and shows the window
*/
openWindow: function() {
var me = this;

if (me.windowConfig) {
var wnd = Ext.ComponentManager.create(me.windowConfig, 'window');
if (wnd) {
var xy = me.getWindowXY(wnd);
Ext.apply(wnd, {
x: xy[0],
y: xy[1],
animateTarget: me.getEl()
}, {});
wnd.on('destroy', me.doWindowDestroy, me);

wnd.show();
me.isWindowOpen = true;
me.wnd = wnd;

if (me.closeOnClickOutside) {
me.mon(Ext.getDoc(), 'mousedown', me.doDocMouseDown, me);
}
}
}
},

/**
* Closes the window and destroys it's object
*/
closeWindow: function() {
var me = this;

if (me.wnd) {
me.wnd.close();
me.wnd = null;
}

if (me.closeOnClickOutside) {
me.mun(Ext.getDoc(), 'mousedown', me.doDocMouseDown, me);
}
}
});


To use just declare a button like:


{
xtype: 'windowbutton',
text: 'My button',
position: 'anchor',
anchor: 'bl',
windowConfig: {
title: 'My window',
resizable: false,
draggable: false,
layout: 'fit',
width: 300,
height: 205,
items: [{
xtype: 'panel',
html: 'this is my window',
border: false
}]
}


Any suggestions, criticisms, or general feedback will be appreciated.

Regards,

Joao Maia

mitchellsimoens
23 Nov 2011, 11:58 AM
What are the advantages of using this above using a ToolTip?

roman.savko
24 Nov 2011, 2:01 AM
Provide a demo please

jmaia
24 Nov 2011, 2:17 AM
Hi Mitchell,

Probably none for most people, but on the application I am currently developing:

1. I decided I did not want a tooltip because I couldn't really find a way to control what went inside the tooltip. I wanted to put more stuff than just plain html, like panels, etc and I did not want to use html templates because I want to steer away from coding html as much as possible in my app to avoid having some developer inadvertently coding html that does not display correctly on some browser.

2. Tooltips show on mouse over events and not on mouse click events. I know there are extensions for that, however I did not want a tooltip because of reason #1

3. I have lots of places on my app where a button will display a popup window, and I wanted to avoid coding the opening and closing of the window every time. So I decided to join all that behavior together on one component.

These three reasons together are what made me develop this. Anyway, I shared it so that people can use it if they feel they hit the same issues as I did. If not, that's cool all the same.

Regards,

Joao Maia

jmaia
24 Nov 2011, 2:21 AM
Provide a demo please

Hi Roman,

I cannot provide a demo because on the company I work for I don't have access to any server that you can access from outside our network.

Sorry... :(

Joao Maia

Jan (HL)
26 Nov 2011, 12:04 PM
Hey, an absolute new, brilliant and innovative idea: Make a screenshot.

evant
27 Nov 2011, 5:19 AM
FYI tooltip extends a panel, so it's trivial to nest components inside them.

jmaia
28 Nov 2011, 3:22 AM
FYI tooltip extends a panel, so it's trivial to nest components inside them.

Hi.

I'm quite aware of that, but check reason #3 on my post above. There are lots of places where I need a button that opens a popup window, and that has the window's animateTarget set to the button, and that allows the user to close the window when he clicks the button again or when he clicks outside the window.

Furthermore, I want my application to look coherent. I don't want the users clicking on a button and seeing a tooltip panel and on another and seeing a window panel because they look different. So I chose the window panel, so that the look is kept throughout the application.

Because of that I decided to encapsulate this behavior in one component. After all that's one of the main benefits of inheritance.

Regards,

Joao Maia