PDA

View Full Version : ImageButton (extension of Ext.Button)



aconran
24 Feb 2007, 6:22 PM
I wanted to share with everyone my first experience of subclassing in javascript. While building a sample application/tutorial for using the new grid I had a need for a simple button w/ image and some text caption. I thought that Button may provide this functionality but found that it didnt. (I think at least) :-)

You can see an example of it in action here:
http://dev.divergingpath.com/playpen/book-alpha.cfm

The buttons on the left use this new class ImageButton.

Here is ImageButton:


Ext.ImageButton = function(renderTo, config){
Ext.ImageButton.superclass.constructor.call(this, renderTo, config);
};

Ext.extend(Ext.ImageButton, Ext.Button, {
render : function(renderTo){
this.disabledImgPath = this.disabledImgPath || this.imgPath;
var tplHTML = '<div>{imgPath} {imgText:htmlEncode}

</div>';
var tpl = new Ext.Template(tplHTML);
var btn = tpl.append(renderTo, {imgPath: this.disabled ? this.disabledImgPath : this.imgPath, imgWidth: this.imgWidth || "", imgHeight: this.imgHeight || "", imgText: this.text || "", tooltip: this.tooltip || ""}, true);
btn.on("click", this.onClick, this);
if(this.cls){
btn.addClass(this.cls);
}
this.el = btn;
if(this.hidden){
this.hide();
}
},
disable : function(newImgPath){
var replaceImgPath = newImgPath || this.disabledImgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = true;
},
enable : function(newImgPath){
var replaceImgPath = newImgPath || this.imgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = false;
}
});


Example of using Code:


var newBtn = new Ext.ImageButton('book-controls',
{text: 'New',
imgPath: 'New.gif',
imgWidth: 50,
imgHeight: 50,
tooltip: 'New Book',
handler: function() {alert('Creating a new book!');}
});
var editBtn = new Ext.ImageButton('book-controls',
{text: 'Edit',
imgPath: '/playpen/Edit.gif',
disabledImgPath: '/playpen/Edit-inactive.gif',
disabled: true,
imgWidth: 50,
imgHeight: 50,
tooltip: 'Edit Book',
handler: function() {alert('Editing a book!');}
});



Please let me know of any comments/suggestions/bugs!! (Aside from the fact that I already know that I probably shouldn't be using the "Ext." namespace.)

aconran
25 Feb 2007, 10:25 AM
I've attempted to add in a feature to show a cursor of pointer when the button is active and to set the cursor to none when it is enabled. However, seems the style never gets updated when calling setStyle in enable/disable functions

Runing Alpha2 Rev3.
http://dev.divergingpath.com/playpen/book-alpha.cfm



Ext.ImageButton = function(renderTo, config){
Ext.ImageButton.superclass.constructor.call(this, renderTo, config);
};

Ext.extend(Ext.ImageButton, Ext.Button, {
render : function(renderTo){
this.disabledImgPath = this.disabledImgPath || this.imgPath;
var tplHTML = '<div>{imgPath} {imgText:htmlEncode}

</div>';
var tpl = new Ext.Template(tplHTML);
var btn = tpl.append(renderTo,
{imgPath: this.disabled ? this.disabledImgPath : this.imgPath,
imgWidth: this.imgWidth || "",
imgHeight: this.imgHeight || "",
imgText: this.text || "",
cursor: this.disabled ? "none" : "pointer",
tooltip: this.tooltip || ""
},true);
btn.on("click", this.onClick, this, true);
if(this.cls){
btn.addClass(this.cls);
}
this.el = btn;
if(this.hidden){
this.hide();
}
},
disable : function(newImgPath){
var replaceImgPath = newImgPath || this.disabledImgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
Ext.fly(this.el.dom.firstChild).setStyle('cursor', 'none');
this.disabled = true;
},
enable : function(newImgPath){
var replaceImgPath = newImgPath || this.imgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
Ext.fly(this.el.dom.firstChild).setStyle('cursor', 'pointer');
this.disabled = false;
}
});

JeffHowden
25 Feb 2007, 10:49 AM
Looks good. A couple of suggestions:

1) Center align the text under the image for a better look. You may want to bump up the size of that text slightly as well. It looks like maybe your icon isn't centered either.

2) Apply some sort of class on mouseover (and remove onmouseout) to make it more apparent it's an interactive item beyond just the pointer cursor.

3) There's no such cursor property of "none". Instead, use "default".

4) There's something really wacky (in IE7 at least) with the text in the lower pane. I haven't quite worked out what's causing it, but it's all muddied up. PM/IM me if you want a screenshot.

aconran
25 Feb 2007, 10:59 AM
Jeff -

I sent you a PM about the screenshot; I've looked at it in both IE7 and FF2 and looks ok so I'm interested to see whats messed up with it.

I tried to use the cursor prop of default instead of none and still get the same result; pulling the element up in firebug shows that the style never gets changed.

I'm really lacking in the css skills but I'll try to get two styles together for active/inactive images and then I could just use Element's "addClassOnOver" what a convenient method!!

I also tried to use the the new Fx "frame" method which looked great when you moused over however the proxy created over top of it made it so that you were clicking the effect and not the actual button so the event handler broke :-)

Aaron

aconran
25 Feb 2007, 9:28 PM
I have some more details about extending existing classes in a blog entry here:
http://www.divergingpath.com/index.cfm/2007/2/25/Ext-BookMgr-Extending-functionality-with-Extextend

lumar
26 Feb 2007, 10:48 AM
I think that the existing Ext.Button class already supports this. In fact, it supports the following modes:

1. Button with text only (this is the default)
2. Button with Icon only (CSS class: x-btn-icon)
3. Button with Icon and Text. (CSS class: x-btn-text-icon)

Also, the default style for buttons have additional CSS classes wrapped around it to give it a nice border. However, in your case we need to remove them and instead have the supplied icon take precendence. Here is what I did to create the same buttons you used in your example without having to extend the Ext.Button class:

Here is the JS snippet to create a button with a caption (NOTE the cls attribute):


var buttonEL= Ext.get('book-controls');
var newButton = new Ext.Button(buttonEl, {text: 'New',
icon: 'New.gif',
tooltip: 'New Book',
cls: 'mybutton-text-icon'
});
...


Here the snippet to change the default style rules for the button class:



/* remove the default left,center and right images from the button border*/
.mybutton-text-icon .x-btn-left, .mybutton-text-icon .x-btn-right, .mybutton-text-icon .x-btn-center{
background: 0;
}

/* now customize the new button that has a caption below the icon */
.mybutton-text-icon .x-btn-center .x-btn-text {
background-position: 0 2px;
background-repeat: no-repeat;
padding-left:0px;
padding-top:50px;
padding-bottom:0px;
padding-right:0px;
height: 65px;
width: 50px;
}


I'm not saying that your implementation is incorrect I just wanted to share that with CSS you can customize the default style for Ext.Button without having to extend it in JS. This is what rocks with Ext widgets -- not only is it rich with JS behaviors and effects but they can be fully customized with JS or CSS or both ( thanks to Jack for an awesome library :D )

aconran
26 Feb 2007, 5:03 PM
Lumar -

Thanks for sharing your implementation of this, as I said I am quite a novice at css. How would you recommend implementing the 'inactive' image state or disabled w/o modifying or extending the source? I could see maybe using a single sprite image and using offsets to toggle between active/inactive; however you'd have to check when the Button is disabled to calculate what style to apply.

Thanks,
Aaron

lumar
26 Feb 2007, 6:03 PM
whenever you need to disable/enable the button you can do the following:




// define the disable CSS class somewhere like
disabledClass : "x-item-disabled"

// do this when you need to disable the button
button.getEl().addClass(disabledClass );

// do this when you need to enable the button
button.getEl().removeClass(disabledClass );

fecund
7 Mar 2007, 1:48 PM
Just want to point out there's yet another way- instead of hiding the extra images with css, you can define a custom template. Use a "template" in the config. The default is:


<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>
<td class="x-btn-left"> </td><td class="x-btn-center"><button class="x-btn-text" ext:qtip="{1:htmlEncode}">{0}</button></td><td class="x-btn-right"> </td>
</tr></tbody></table>

Edit to your heart's desire. {0} is the button text, {1} lets you get at the options, if I'm not mistaken.

sunil
7 Mar 2008, 4:53 AM
I have used this code to implement two image buttons in my login screen, the image is not rendering(displaying) in my login.jsp. Does this is a conflict of Version?


I wanted to share with everyone my first experience of subclassing in javascript. While building a sample application/tutorial for using the new grid I had a need for a simple button w/ image and some text caption. I thought that Button may provide this functionality but found that it didnt. (I think at least) :-)

You can see an example of it in action here:
http://dev.divergingpath.com/playpen/book-alpha.cfm

The buttons on the left use this new class ImageButton.

Here is ImageButton:


Ext.ImageButton = function(renderTo, config){
Ext.ImageButton.superclass.constructor.call(this, renderTo, config);
};

Ext.extend(Ext.ImageButton, Ext.Button, {
render : function(renderTo){
this.disabledImgPath = this.disabledImgPath || this.imgPath;
var tplHTML = '<div>{imgPath} {imgText:htmlEncode}

</div>';
var tpl = new Ext.Template(tplHTML);
var btn = tpl.append(renderTo, {imgPath: this.disabled ? this.disabledImgPath : this.imgPath, imgWidth: this.imgWidth || "", imgHeight: this.imgHeight || "", imgText: this.text || "", tooltip: this.tooltip || ""}, true);
btn.on("click", this.onClick, this);
if(this.cls){
btn.addClass(this.cls);
}
this.el = btn;
if(this.hidden){
this.hide();
}
},
disable : function(newImgPath){
var replaceImgPath = newImgPath || this.disabledImgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = true;
},
enable : function(newImgPath){
var replaceImgPath = newImgPath || this.imgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = false;
}
});


Example of using Code:


var newBtn = new Ext.ImageButton('book-controls',
{text: 'New',
imgPath: 'New.gif',
imgWidth: 50,
imgHeight: 50,
tooltip: 'New Book',
handler: function() {alert('Creating a new book!');}
});
var editBtn = new Ext.ImageButton('book-controls',
{text: 'Edit',
imgPath: '/playpen/Edit.gif',
disabledImgPath: '/playpen/Edit-inactive.gif',
disabled: true,
imgWidth: 50,
imgHeight: 50,
tooltip: 'Edit Book',
handler: function() {alert('Editing a book!');}
});



Please let me know of any comments/suggestions/bugs!! (Aside from the fact that I already know that I probably shouldn't be using the "Ext." namespace.)

siyuan
20 Jun 2008, 5:25 AM
Ext.namespace('Ext.ux');
Ext.ux.ImageButton = function(cfg) {
Ext.ux.ImageButton.superclass.constructor.call(this, cfg);
};

Ext.extend(Ext.ux.ImageButton, Ext.Button, {
onRender : function(ct, position) {
this.disabledImgPath = this.disabledImgPath || this.imgPath;
var tplHTML = '<div><img src="{imgPath}" border="0" width="{imgWidth}" height="{imgHeight}" alt="{tooltip}" style="cursor: {cursor};"/> {imgText:htmlEncode}<br/><br/></div>';
var tpl = new Ext.Template(tplHTML);
var btn, targs = {
imgPath : this.disabled ? this.disabledImgPath : this.imgPath,
imgWidth : this.imgWidth || "",
imgHeight : this.imgHeight || "",
imgText : this.text || "",
cursor : this.disabled ? "default" : "pointer",
tooltip : this.tooltip || ""
};

btn = tpl.append(ct, targs, true);

btn.on("click", this.onClick, this);

if (this.cls) {
btn.addClass(this.cls);
}
this.el = btn;
if (this.hidden) {
this.hide();
}
},
disable : function(newImgPath) {
var replaceImgPath = newImgPath || this.disabledImgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = true;
},
enable : function(newImgPath) {
var replaceImgPath = newImgPath || this.imgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = false;
}
});
Ext.reg('imagebutton', Ext.ux.ImageButton);

Ext.onReady(function(){
new Ext.Viewport({
items: [{
xtype : 'imagebutton',
imgPath : 'images/add.gif',
imgWidth : 32,
imgHeight : 32,
text : 'test',
handler : function(btn){
Ext.MessageBox.alert('test','ImageButton');
}
}]
});
});

Tomxp
23 Jun 2008, 7:59 AM
Thx for this image buttons!

How can I add formBind property. The button should only be enabled if validation of my form is correct.

Tom

Tomxp
27 Jun 2008, 3:07 AM
Or is there an another solution for normal extjs Button with image layout? ... :-/

wwwtd
9 Dec 2008, 1:13 AM
Ext.namespace('Ext.ux');
Ext.ux.ImageButton = function(cfg) {
Ext.ux.ImageButton.superclass.constructor.call(this, cfg);
};

Ext.extend(Ext.ux.ImageButton, Ext.Button, {
onRender : function(ct, position) {
this.disabledImgPath = this.disabledImgPath || this.imgPath;
var tplHTML = '<div><img src="{imgPath}" border="0" width="{imgWidth}" height="{imgHeight}" alt="{tooltip}" style="cursor: {cursor};"/> {imgText:htmlEncode}<br/><br/></div>';
var tpl = new Ext.Template(tplHTML);
var btn, targs = {
imgPath : this.disabled ? this.disabledImgPath : this.imgPath,
imgWidth : this.imgWidth || "",
imgHeight : this.imgHeight || "",
imgText : this.text || "",
cursor : this.disabled ? "default" : "pointer",
tooltip : this.tooltip || ""
};

btn = tpl.append(ct, targs, true);

btn.on("click", this.onClick, this);

if (this.cls) {
btn.addClass(this.cls);
}
this.el = btn;
if (this.hidden) {
this.hide();
}
},
disable : function(newImgPath) {
var replaceImgPath = newImgPath || this.disabledImgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = true;
},
enable : function(newImgPath) {
var replaceImgPath = newImgPath || this.imgPath;
if (replaceImgPath)
this.el.dom.firstChild.src = replaceImgPath;
this.disabled = false;
}
});
Ext.reg('imagebutton', Ext.ux.ImageButton);

Ext.onReady(function(){
new Ext.Viewport({
items: [{
xtype : 'imagebutton',
imgPath : 'images/add.gif',
imgWidth : 32,
imgHeight : 32,
text : 'test',
handler : function(btn){
Ext.MessageBox.alert('test','ImageButton');
}
}]
});
});


hi~I have a problem that tooltip don't display when I add in imageButton.how to do it to make tooltip display

spiderweb
30 Apr 2009, 4:57 AM
i have problems with IE7 rendering an image button

it works excellent with FF2 and FF3

im using your example

thanks

Mairym13
20 Jul 2009, 2:25 AM
I think that the existing Ext.Button class already supports this. In fact, it supports the following modes:
1. Button with text only (this is the default)
2. Button with Icon only (CSS class: x-btn-icon)
3. Button with Icon and Text. (CSS class: x-btn-text-icon)
Also, the default style for buttons have additional CSS classes wrapped around it to give it a nice border. However, in your case we need to remove them and instead have the supplied icon take precendence. Here is what I did to create the same buttons you used in your example without having to extend the Ext.Button class:


Hello,
I have encountered a few problems while passing from extjs 2.2 to extjs 3.0. first of all, I have lost all background color and border of my buttons (they are normal-type buttons, only text). I have tried many ways to redefine them, but every attempt failed.
I have already posted my problem here with much more details:
http://www.developpez.net/forums/d779997/webmasters-developpement-web/javascript/bibliotheques-frameworks/ext-js/problemes-extjs-2-2-vers-extjs-3-0-a/#post4497780
but no one could help.

Do you have an idea of how I could correct my problem?

Thanks a lot.

livelymanoj
3 Aug 2010, 9:58 AM
Nice to see so many replies on how to render an Ext image button. I have further looked into it and come with very simple way to render a button. You just need one simple template and one CSS class. I have completely made it hassle free and removed the default table template. You can place any number of image icons in a single div horizontally.
My sample code:


<style type="text/css">
.btnIcon
{
height: 20px !important;
width: 70px !important;
background-image: url(image/btnTest.gif) !important;
}
</style>
<div id='btnTest'></div>
<script type="text/javascript">
(function(){
function init(){
var imageBtnTpl = new Ext.Template('<span class="x-btn {3}" id="{4}"><button type="{0}"></button></span>');
imageBtnTpl.compile();
var cfg = {
xtype: 'button',
applyTo: 'btnTest',
template:imageBtnTpl,
iconCls:'btnIcon'
};
var btnTest = Ext.ComponentMgr.create(cfg);
} // init
Ext.onReady(init);
})();
</script>

Let me know if you find any problem with this. HTH.
Thanks - Manoj

mvdbergh
4 Jan 2011, 12:32 AM
[..]
Thanks - Manoj
Hi Manoj,

I've used your code to create the following implementation of an ImageButton, maybe useful for others as well:


Ext.ns('my.namespace.input');

my.namespace.input.ImageButton = Ext.extend(Ext.Button, {
initComponent: function(){

var imageBtnTpl = new Ext.Template('<span class="x-btn {3}" id="{4}"><button type="{0}"></button></span>');
imageBtnTpl.compile();

if(this.mouseOverClass){
// store the iconCls for the mouseOut event
this.buttonClass = this.iconCls;
}

Ext.applyIf(this, {
template: imageBtnTpl,
listeners: {
'mouseOver': function(button, event){ if(this.mouseOverClass) this.setIconClass(this.mouseOverClass); },
'mouseOut': function(button, event){ if(this.mouseOverClass) this.setIconClass(this.buttonClass); }
}
});

my.namespace.input.ImageButton.superclass.initComponent.call(this);
}
});

Ext.reg('imagebutton', my.namespace.input.ImageButton);
Of course you should adjust the namespace to your own.

The class above can be used like this:


<style type="text/css">
.btnIcon {
height: 70px !important;
width: 70px !important;
background-image: url(/myButton.png) !important;
}

.btnIconOver {
height: 70px !important;
width: 70px !important;
background-image: url(/myButtonMouseOver.png) !important;
}
</style>
<script type="text/javascript">
Ext.onReady(function() {
new Ext.Window({
items: [
{
xtype: 'imagebutton',
iconCls: 'btnIcon',
mouseOverClass: 'btnIconOver'
},
new my.namespace.input.ImageButton({
iconCls: 'btnIcon',
mouseOverClass: 'btnIconOver'
})
]
}).show();
});
</script>
Improvements and comments are of course welcome.

Edit: This code is written for ExtJS 3.3.1.