PDA

View Full Version : QuickTips Enhancements



ejsmith
13 Nov 2007, 8:32 PM
I have made some enhancements to the QuickTips classes. The main feature is that you can register global attribute handlers. Say your system manages support cases and you show lists of support cases all over the place and when you hover any of them, you want to display more information about that case. Now you can just add a ext:caseid="1" to any element and QuickTips will see that attribute once you register it and call a tooltip renderer method to build the tooltip information and pass the attribute value in for you to lookup the case information.

Here is an example:


Ext.QuickTips.init();
Ext.QuickTips.registerAttributeHandler({
attribute: 'caseid',
renderer: caseTipRenderer
});
Ext.QuickTips.registerNamedConfig('myconfig', {
width: 200,
align: 'tl-bl?',
offsets: '0,3'
});

function caseTipRenderer(o)
{
// load dynamic tip information here using o.value.
o.title = 'Rendered Tip ' + o.value;
o.text = 'Blah...';

return o;
}
Then any tag that has a ext:caseid attribute will show a tooltip:


<div id="attribute-tip" class="tip-target" ext:caseid="1" ext:config="myconfig">Handler Tip</div>
I would love to see this get added to Ext. Is there any chance of this patch getting committed or should I consider refactoring this to be a stand alone set of classes?

dantheman
14 Nov 2007, 6:35 AM
+1000000

:D

--dan

brian.moeskau
14 Nov 2007, 9:48 AM
Hi Eric,

It would not go into 2.0 at this point, but we'll take a look at your mod, and if it makes sense to add, we'll see about maybe 2.1.

devnull
14 Nov 2007, 11:39 AM
Wow, I want to try this, but there are many reasons why patching library code is a really bad idea from a developement perspective. and between your ide "fixing" things and the patch process, that patch file is very hard to read.
I will attempt to convert this to an include file that either overrides or extends the quicktip class, but it will probably take awhile...

galdaka
14 Nov 2007, 12:38 PM
Hi,

Is posible live example?

Is a automatically way for apply this patch?

Thanks in advance,

devnull
14 Nov 2007, 1:49 PM
I am not sure if this is the right way to do it, but it does appear to work:


Ext.override(Ext.QuickTip,{
/**
* @cfg {Array} attrHandlers Array of attribute handlers.
*/
attrHandlers: {},

/**
* @cfg {Array} namedConfigs Array of named configs.
*/
namedConfigs: {},
tagConfig: {
namespace: "ext",
attribute: "qtip",
width: "qwidth",
target: "target",
title: "qtitle",
hide: "hide",
cls: "qclass",
align: "qalign",
config: "config",
offsets: "offsets"
},
onTargetOver : function(e){
if(this.disabled){
return;
}
this.targetXY = e.getXY();
var t = e.getTarget();
if(!t || t.nodeType !== 1 || t == document || t == document.body){
return;
}
if(this.activeTarget && t == this.activeTarget.el){
this.clearTimer('hide');
this.show();
return;
}
if(t && this.targets[t.id]){
this.activeTarget = this.targets[t.id];
this.activeTarget.el = t;
this.delayShow();
return;
}
var ttp, et = Ext.fly(t), cfg = this.tagConfig;
var ns = cfg.namespace;
for (var attr in this.attrHandlers) {
attrHandler = this.attrHandlers[attr];
attrValue = et.getAttributeNS(ns, attrHandler.attribute);
if (attrValue) {
autoHide = et.getAttributeNS(ns, cfg.hide);
this.activeTarget = {
el: t,
value: attrValue,
config: et.getAttributeNS(ns, cfg.config),
offsets: et.getAttributeNS(ns, cfg.offsets),
width: et.getAttributeNS(ns, cfg.width),
autoHide: autoHide != "user" && autoHide !== 'false',
title: et.getAttributeNS(ns, cfg.title),
cls: et.getAttributeNS(ns, cfg.cls),
align: et.getAttributeNS(ns, cfg.align),
attrHandler: attrHandler
};
this.delayShow();
return;
}
}
if(this.interceptTitles && t.title){
ttp = t.title;
t.qtip = ttp;
t.removeAttribute("title");
e.preventDefault();
} else{
ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
}
if(ttp){
var autoHide = et.getAttributeNS(ns, cfg.hide);
this.activeTarget = {
el: t,
text: ttp,
config: et.getAttributeNS(ns, cfg.config),
offsets: et.getAttributeNS(ns, cfg.offsets),
width: et.getAttributeNS(ns, cfg.width),
autoHide: autoHide != "user" && autoHide !== 'false',
title: et.getAttributeNS(ns, cfg.title),
cls: et.getAttributeNS(ns, cfg.cls),
align: et.getAttributeNS(ns, cfg.align)
};
this.delayShow();
}
},
showAt : function(xy){
var t = this.activeTarget;
if(t){
if (t.config && this.namedConfigs[t.config]) t = Ext.applyIf(t, this.namedConfigs[t.config]);
if (t.attrHandler) {
t = t.attrHandler.renderer(t);
}
if(!this.rendered){
this.render(Ext.getBody());
}
if(t.width){
this.setWidth(t.width);
this.measureWidth = false;
} else{
this.measureWidth = true;
}
this.setTitle(t.title || '');
this.body.update(t.text);
this.autoHide = t.autoHide;
this.dismissDelay = t.dismissDelay || this.dismissDelay;
if(t.cls){
if(this.lastCls){
this.el.removeClass(this.lastCls);
}
this.el.addClass(t.cls);
this.lastCls = t.cls;
}
if(t.align){ // TODO: this doesn't seem to work consistently
var offsets = [];
if (t.offsets) {
offsets = t.offsets.split(',');
for (var i = 0; i < offsets.length; i++) {
offsets[i] = parseInt(offsets[i]);
}
}
if (offsets.length == 2){
xy = this.el.getAlignToXY(t.el, t.align, offsets)
} else {
xy = this.el.getAlignToXY(t.el, t.align)
}
this.constrainPosition = false;
} else{
this.constrainPosition = true;
}
}
Ext.QuickTip.superclass.showAt.call(this, xy);
},
registerAttributeHandler: function(config){
if (config && config.attribute && config.renderer) {
this.attrHandlers[config.attribute] = config;
}
},

unregisterAttributeHandler: function(attr){
delete this.attrHandlers[attr];
},

registerNamedConfig: function(name, config){
if (name && config) {
this.namedConfigs[name] = config;
}
},

unregisterNamedConfig: function(name){
delete this.namedConfigs[name];
}
})
Ext.QuickTips = function(){
var tip, locks = [];
return {
/**
* Initialize the global QuickTips instance and prepare any quick tips.
*/
init : function(){
if(!tip){
tip = new Ext.QuickTip({elements:'header,body'});
}
},

/**
* Enable quick tips globally.
*/
enable : function(){
if(tip){
locks.pop();
if(locks.length < 1){
tip.enable();
}
}
},

/**
* Disable quick tips globally.
*/
disable : function(){
if(tip){
tip.disable();
}
locks.push(1);
},

/**
* Returns true if quick tips are enabled, else false.
* @return {Boolean}
*/
isEnabled : function(){
return tip && !tip.disabled;
},

/**
* Gets the global QuickTips instance.
*/
getQuickTip : function(){
return tip;
},

/**
* Configures a new quick tip instance and assigns it to a target element. See
* {@link Ext.QuickTip#register} for details.
* @param {Object} config The config object
*/
register : function(){
tip.register.apply(tip, arguments);
},

/**
* Removes any registered quick tip from the target element and destroys it.
* @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
*/
unregister : function(){
tip.unregister.apply(tip, arguments);
},

/**
* Alias of {@link #register}.
* @param {Object} config The config object
*/
tips :function(){
tip.register.apply(tip, arguments);
},

/**
* Removes this quick tip from its element and destroys it.
* @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
*/
registerAttributeHandler : function(config){
tip.registerAttributeHandler(config);
},

/**
* Removes this attribute from the list of attribute handlers and destroys it.
* @param {String} attr The name of the attribute handler to be removed.
*/
unregisterAttributeHandler : function(attr){
tip.unregisterAttributeHandler(attr);
},

registerNamedConfig : function(name, config){
tip.registerNamedConfig(name, config);
},

unregisterNamedConfig : function(name){
tip.unregisterNamedConfig(name);}
}
}();

Ext.override(Ext.Tip,{
defaultOffsets : [0,0],
showBy : function(el, pos, offsets){
if(!this.rendered){
this.render(Ext.getBody());
}
this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign, offsets || this.defaultOffsets));
}
})

My understanding of prototyping and extending objects isnt that great, so I would appreciate if anyone could explain the proper way to add the extra functions to Ext.QuickTips rather than completely overwriting it.
The next thing to figure out is how to add the "ext:caseid=1" tag dynamically, specifically to a grid cell via a custom renderer function.

devnull
14 Nov 2007, 2:40 PM
well that was easy enough, just set the attr property of the passed in metaData object within the renderer :)
now to see if it will be possible to fetch tip data via xhr, this will get interesting due to the async nature...

ejsmith
14 Nov 2007, 5:26 PM
Yeah, I struggled with whether I should try and extend or patch as well. I'm still learning the Ext component model and I ran into some issues extending and ideally I'd like to see this included with Ext by default, so that is why I decided to go the patch route.

I would really love to hear some experts opinions on whether your code is the right way to extend the default objects. Hopefully one of the Ext devs will respond. :)

devnull
15 Nov 2007, 9:53 AM
I am reasonably sure that most of it is correct. At least the methods used match what I have seen in other extensions.
The problem I ran into is adding new functions to a class.
Override cant be used, since there is no original function to override.
It cant be prototyped in this case, since .prototype is only available for objects that were created via the "new" keyword.
Adding the new function directly as a new property results in scoping issues; the new function cannot access previously defined private members (in this case 'tip').
Replacing the entire Ext.QuickTips class isnt a huge problem since it is small, but can cause problems in the future if changes are issued to functions that we did not change (but had to include).
I would really like to know the proper way around this problem :)

I did manage to shoehorn in a way of dynamically updating the quicktip body after making an xhr request too. had to make a small modification to your code and add an additional callback function, but its pretty specific to my needs.

benny_boi
5 Dec 2007, 2:23 AM
Just want to add my support and adoration to this extension. I agree that it would be more desirable to see this as an extension of the base Ext rather than a patch because I prefer to be able to update the base framework without worrying if I've clobbered an important change to the functionality. Absolutely love this feature though.

Ext Dev Team - Can i put in a vote for this in 2.1? (Love your work x 10000000000 by the way!)

Thanks for sharing your work so far guys! :-)

galdaka
5 Dec 2007, 2:31 AM
Live example please!!

Thanks in advance,

Wolfgang
14 Dec 2007, 2:50 AM
...
I did manage to shoehorn in a way of dynamically updating the quicktip body after making an xhr request too. had to make a small modification to your code and add an additional callback function, but its pretty specific to my needs.

This sound interesting. What you mind sharing your code for this?