PDA

View Full Version : Simple plugin to change tooltip based on enabled/disabled state of component



anup
Jun 29, 2011, 6:21 PM
Hi,

I've recently found myself repeatedly needing the following: I have a bunch of buttons in a toolbar (though this could apply perhaps to any component) which, when disabled has a different tooltip to when it is enabled (e.g. when disabled, adds a hint to explain why it is disabled and what you may need to do etc).

I could have inherited Ext Button and added some code there, but then I'd have to do something similar for other components where I may want to do something similar (e.g. menu items maybe). So instead, I opted for a looser coupling approach using a simple plugin.

This example is very simplistic but I put it here for a) suggestions for improvement, and b) for you to take and change as you need:

First the plugin JS script:



Ext.ux.ToggleTooltipOnEnabledState = Ext.extend(Object, {
constructor: function(config) {
Ext.apply(this, config);
},

init: function(cmp) {
function setTooltip(html) {
var tooltipOptions;

if (cmp.tooltip != null)
cmp.tooltip.destroy();

if (html == undefined)
return;

tooltipOptions = Ext.apply({
constrainPosition: true,
title : this.tooltipTitle,
html : html,
target : cmp
}, this.tooltipOptions);

cmp.tooltip = new Ext.ToolTip(tooltipOptions);
}

cmp.on({
disable : { fn: setTooltip.createDelegate(this, [this.tooltipWhenDisabled]) },
enable : { fn: setTooltip.createDelegate(this, [this.tooltipWhenEnabled]) }
});
}
});

Ext.reg('Ext.ux.ToggleTooltipOnEnabledState', Ext.ux.ToggleTooltipOnEnabledState);


Next, an example usage:


<ext:Button ID="Btn1" runat="server" Text="Btn1: This button will have tooltips on it" Icon="Lightbulb">
<Plugins>
<ext:GenericPlugin ID="ToggleTooltipOnEnabledState" runat="server" InstanceName="Ext.ux.ToggleTooltipOnEnabledState">
<CustomConfig>
<ext:ConfigItem Name="tooltipOptions" Value="{ constrainPosition: true, width:150 }" Mode="Raw" />
<ext:ConfigItem Name="tooltipTitle" Value="Title" Mode="Value" />
<ext:ConfigItem Name="tooltipWhenDisabled" Value="Tooltip when disabled" Mode="Value" />
<ext:ConfigItem Name="tooltipWhenEnabled" Value="Tooltip when enabled" Mode="Value" />
</CustomConfig>
</ext:GenericPlugin>
</Plugins>
<Listeners>
<AfterRender Handler="this.setDisabled(true);" />
</Listeners>
</ext:Button>

<ext:Button ID="Btn2" runat="server" Icon="Add" Text="Enable btn1">
<Listeners>
<Click Handler="#{Btn1}.setDisabled(false);" />
</Listeners>
</ext:Button>

<ext:Button ID="Btn3" runat="server" Icon="Delete" Text="Disable Btn1">
<Listeners>
<Click Handler="#{Btn1}.setDisabled(true);" />
</Listeners>
</ext:Button>


(Note, if you only wanted a tooltip when disabled (or when enabled) you could omit the appropriate ConfigItem above)

Finally an example with all of it together (copy paste into an ASPX and run it)


<%@ Page Language="C#" %>
<%@ Register assembly="Ext.Net" namespace="Ext.Net" tagprefix="ext" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Test plugin that toggles tooltip based on enabled state</title>

<ext:ResourcePlaceHolder ID="ResourcePlaceHolder1" runat="server" Mode="ScriptFiles" />

<script type="text/javascript">
Ext.ux.ToggleTooltipOnEnabledState = Ext.extend(Object, {
constructor: function(config) {
Ext.apply(this, config);
},

init: function(cmp) {
function setTooltip(html) {
var tooltipOptions;

if (cmp.tooltip != null)
cmp.tooltip.destroy();

if (html == undefined)
return;

tooltipOptions = Ext.apply({
constrainPosition: true,
title : this.tooltipTitle,
html : html,
target : cmp
}, this.tooltipOptions);

cmp.tooltip = new Ext.ToolTip(tooltipOptions);
}

cmp.on({
disable : { fn: setTooltip.createDelegate(this, [this.tooltipWhenDisabled]) },
enable : { fn: setTooltip.createDelegate(this, [this.tooltipWhenEnabled]) }
});
}
});

Ext.reg('Ext.ux.ToggleTooltipOnEnabledState', Ext.ux.ToggleTooltipOnEnabledState);
</script>
</head>
<body>
<form id="HtmlForm" runat="server">
<ext:ResourceManager ID="ResourceManager1" runat="server" />

<ext:Window ID="Window1" runat="server" Width="550" Title="Example" ShowOnLoad="true" CenterOnLoad="true" Resizable="false" Closable="false" AutoScroll="true" AutoHeight="true" Padding="6">
<Items>
<ext:Panel ID="TestPanel" runat="server" AutoHeight="true" AutoScroll="true" Layout="Center" PaddingSummary="10px" PreventBodyReset="true">
<TopBar>
<ext:Toolbar ID="Toolbar1" runat="server">
<Items>
<ext:Button ID="Btn1" runat="server" Text="Btn1: This button will have tooltips on it" Icon="Lightbulb">
<Plugins>
<ext:GenericPlugin ID="ToggleTooltipOnEnabledState" runat="server" InstanceName="Ext.ux.ToggleTooltipOnEnabledState">
<CustomConfig>
<ext:ConfigItem Name="tooltipOptions" Value="{ constrainPosition: true, width:150 }" Mode="Raw" />
<ext:ConfigItem Name="tooltipTitle" Value="Title" Mode="Value" />
<ext:ConfigItem Name="tooltipWhenDisabled" Value="Tooltip when disabled" Mode="Value" />
<ext:ConfigItem Name="tooltipWhenEnabled" Value="Tooltip when enabled" Mode="Value" />
</CustomConfig>
</ext:GenericPlugin>
</Plugins>
<Listeners>
<AfterRender Handler="this.setDisabled(true);" />
</Listeners>
</ext:Button>

<ext:Button ID="Btn2" runat="server" Icon="Add" Text="Enable btn1">
<Listeners>
<Click Handler="#{Btn1}.setDisabled(false);" />
</Listeners>
</ext:Button>

<ext:Button ID="Btn3" runat="server" Icon="Delete" Text="Disable Btn1">
<Listeners>
<Click Handler="#{Btn1}.setDisabled(true);" />
</Listeners>
</ext:Button>
</Items>
</ext:Toolbar>
</TopBar>
<Content>
<p>This example demonstrates a plugin that can be applied to components whereby a different tooltip is shown when the component is disabled, compared to when it is enabled</p>

<p>To Test:</p>
<ol>
<li>Hover over first button: should get tooltip for disabled state</li>
<li>Click enable button and hover over first button: should get tooltip for enabled state</li>
<li>Click disable button and hover over first button: should get tooltip for disabled state</li>
</ol>

<p>Limitations/notes:</p>
<ul>
<li>Tested with a button but in theory should work with most other components</li>
<li>Title remains same when state changes; can easily be changed if you need</li>
<li>Other options, such as width as optionally passed in when the plugin is constructed. You'd need to change the plugin if you want to vary it per disabled state.</li>
</ul>
</Content>
</ext:Panel>
</Items>
</ext:Window>
</form>
</body>
</html>


If you can see ways to improve/harden/optimize please do suggest it!

Daniil
Jun 30, 2011, 10:08 AM
Hi anup,

Thanks for sharing!

The code looks fine.

The single thing I can suggest - extending the plugin with .destroy() method. Well, it makes sense if you assume to destroy a component - destroying the plugin will free memory.

For example, please investigate .init() and .destroy() methods of "tabclosemenu" plugin:

<SVN root folder>\Ext.Net\Build\Ext.Net\ux\plugins\tabclosemenu\tab closemenu.js

anup
Jun 30, 2011, 2:29 PM
Thanks for that excellent tip Daniil.

Here's an updated version of the plugin code:



Ext.ux.ToggleTooltipOnEnabledState = Ext.extend(Object, {
constructor: function(config) {
Ext.apply(this, config);
},

init: function(cmp) {
function setTooltip(html) {
var tooltipOptions;

if (cmp.tooltip != null)
cmp.tooltip.destroy();

if (html == undefined)
return;

tooltipOptions = Ext.apply({
constrainPosition: true,
title : this.tooltipTitle,
html : html,
target : cmp
}, this.tooltipOptions);

cmp.tooltip = new Ext.ToolTip(tooltipOptions);
}

cmp.on({
scope : this,
disable : { fn: setTooltip.createDelegate(this, [this.tooltipWhenDisabled]) },
enable : { fn: setTooltip.createDelegate(this, [this.tooltipWhenEnabled]) },
destroy : this.destroy
});
},

destroy: function() {
delete this.tooltipOptions;
delete this.tooltipTitle;
delete this.tooltipWhenDisabled;
delete this.tooltipWhenEnabled;
}
});

In the init, I added a scope of "this" for the events and added a destroy handler.

In the destroy, I delete the objects that this plugin has (though deleting the strings may be overkill, as I think they get destroyed anyway. The tooltipOptions is just an object literal so it may be overkill to have this too as I believe this will get deleted safely during the destroy anyway. If all that is right, the entire destroy I added may be overkill, but the tip is a really handy one for me to keep in mind for more complex plugins!)

Daniil
Jun 30, 2011, 5:00 PM
Well, you are right, it was a tip rather for more complex plugin.

The one thing we'd suggest you to destroy in that plugin is a tooltip:

cmp.tooltip.destroy();

anup
Jun 30, 2011, 6:25 PM
Well, you are right, it was a tip rather for more complex plugin.

Fair point. I found a few other plugins I had written that assigned more complex objects to the plugin and those are now being destroyed. So thanks fro that.


The one thing we'd suggest you to destroy in that plugin is a tooltip:

cmp.tooltip.destroy();

Good point. Thanks also for that :)