ExtJS 5.0 - adding button as overlay to component - javascript

We are working with software supplied by a third party, and we are not allowed to modify it, can use only overrides.
I would like to create a new button and overlay it on top of a text input so that they are close together.
I'm having trouble getting the overlay to align, instead it appears top left on the screen. So of course it doesn't align to the text input. Sample code is below, in this case implemented in the view initComponent override after this.callParent([]); is called.
var viewport = Ext.ComponentQuery.query('viewport')[0];
var overlay = viewport.add({
xtype: 'panel',
fullscreen: true,
left: 0,
top: 0,
width: 120,
height: 40,
items:[{
xtype: 'button',
text: 'Find Address',
handler: function() {
alert('Got it!');
}
}],
styleHtmlContent: true
});
var textField = this.query('*[itemId=textField]')[0];
overlay.showBy(textField, 'c-c?');
I've tried using floating: true and lots of other approaches.
Once I get it to position properly, is there a way to have the button respond to tab order correctly? That is, tab out of the text field, then have the button get focus?

As I understand from your question, you have trouble with setting position to a component. If it is the problem, you can set xy coordinate. Look at this fiddle:
https://fiddle.sencha.com/#fiddle/tpl
viewport.down('#idOverlay').setXY([150, 140]);
Edit:
Ext.define('OverriddenViewport', {
override: 'ExampleViewPort',
initComponent: function() {
// Set up first
this.callParent([]);
this.add(overlay);
this.addListener('afterrender', function(viewport) {
viewport.down('#idOverlay').setXY([220,50]);
viewport.down('#idButton').addListener('blur', function(button) {
viewport.down('#idTextfield').focus();
console.log('textfield is focussed');
});
viewport.down('#idTextfield').addListener('blur', function(button) {
viewport.down('#idButton').focus();
console.log('button is focussed');
});
});
}
});

If you can access the source (just to look around) you maybe can create an override of the corresponding class. Create a override, and copy all of the code of the class (form?) into your override.
Here some additional info about creating overrides in ExtJs:
http://moduscreate.com/writing-ext-js-overrides/
https://sencha.guru/2014/12/04/abstract-vs-override/
In your override create a trigger (on the field you want to expand) with your functionality:
{
fieldLabel: 'My Custom Field',
triggers: {
foo: {
cls: 'my-foo-trigger',
handler: function() {
console.log('foo trigger clicked');
}
}
}
}

Related

How to show tooltip for grid cells?

I have a grid and when doing a mouseover on a cell a tooltip shows up for each cell. That works great. However, I have couple issues:
1) I only want to show tooltips for cells under the flag column.
2) If a cell doesn't have a value don't show a tooltip.
3) Finally how to make the tooltip go away only when doing a mouseout from the cell
Thanks a lot in advance!
Here's my working code: LIVE DEMO
Code snippet:
grid.tip = Ext.create('Ext.tip.ToolTip', {
target: view.el,
delegate: '.x-grid-cell',
trackMouse: true,
listeners: {
beforeshow: function updateTipBody(tip) {
if (!Ext.isEmpty(grid.cellIndex) && grid.cellIndex !== -1) {
header = grid.headerCt.getGridColumns()[grid.cellIndex];
tip.update(grid.getStore().getAt(grid.recordIndex).get(header.dataIndex));
}
}
}
});
1) You have to add a custom CSS class to your grid cells through a renderer and then use that CSS class as a delegate for your tooltip.
2) You have full control over the cells you want to add the CSS class to based on the value or other record values in the renderer. Do not add the custom CSS class to the grid cell if the value is empty.
3) hideDelay: 0 on the tooltip.
Required code changes:
dataIndex: 'color',
renderer: function(v, meta) {
if(v) meta.tdCls = 'customCls';
return v;
}
and
target: view.el,
delegate: '.customCls',
trackMouse: true,
hideDelay: 0,
However, there seem to be issues with the uievent, at least in Firefox, that you should be aware of. The event is not always fired as expected, sometimes it is not fired again when moving between columns of the same row, sometimes it is fired with columnIndex = -1 when moving between rows. The following screenshot has been taken on your sample page:
There is another, less hacky and more supported possibility to implement this: Add quicktips directly in the renderer.
For this, remove all your custom tooltip code.
Add to the renderer a data-qtip attribute:
dataIndex: 'color',
renderer: function(value, meta, record) {
if(value) meta.tdAttr='data-qtip="'+value+'"';
return value;
}
You can modify the hideDelay in the QuickTipManager as shown in the sample code from the QuickTipManager documentation:
// Init the singleton. Any tag-based quick tips will start working.
Ext.tip.QuickTipManager.init();
// Apply a set of config properties to the singleton
Ext.apply(Ext.tip.QuickTipManager.getQuickTip(), {
hideDelay: 0
});
Relevant fiddle
You don't need to wrire an extra code for tool tip just for Flag column write render function and in the write a condition to show only for not empty values.
like
{
text: 'Flag',
flex: 1,
dataIndex: 'color',
renderer: function(value, meta, record) {
if(!Ext.isEmpty(value))
meta.tdAttr='data-qtip="'+value+'"';
return value;
}
}

How to Change CSS of Custom Template JointJS Element?

I've been using JointJS for a while now and I'm trying to create an HTML template for my elements. So I've been using the tutorial but it didn't quit do it for me.
The thing I'm trying to accomplish is to adjust the color of the HTML element when an action has been performed, like double clicking the element. I did notice the way that the text is changed in the tutorial, but there is no example of changing any colors.
Edit
I've tried this to get a starting color on the element:
joint.shapes.html = {};
joint.shapes.html.OdinElement = joint.shapes.basic.Rect.extend({
defaults: joint.util.deepSupplement({
type: 'html.Element',
attrs: {
rect: { stroke: 'none', 'fill-opacity': 0 }
}
}, joint.shapes.basic.Rect.prototype.defaults)
});
// Create a custom view for that element that displays an HTML div above it.
// -------------------------------------------------------------------------
joint.shapes.html.OdinElementView = joint.dia.ElementView.extend({
template: [
'<div class="html-element">',
'<button class="delete">x</button>',
'<label></label>',
'<span></span>', '<br/>',
'</div>'
].join(''),
initialize: function() {
_.bindAll(this, 'updateBox');
joint.dia.ElementView.prototype.initialize.apply(this, arguments);
this.$box = $(_.template(this.template)());
this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
// Update the box position whenever the underlying model changes.
this.model.on('change', this.updateBox, this);
// Remove the box when the model gets removed from the graph.
this.model.on('remove', this.removeBox, this);
this.updateBox();
},
render: function() {
joint.dia.ElementView.prototype.render.apply(this, arguments);
this.paper.$el.prepend(this.$box);
this.updateBox();
return this;
},
updateBox: function() {
// Set the position and dimension of the box so that it covers the JointJS element.
var bbox = this.model.getBBox();
// Example of updating the HTML with a data stored in the cell model.
this.$box.find('label').text(this.model.get('label'));
this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)', background: this.model.get('color')}); // I've tried to add it like a background
},
removeBox: function(evt) {
this.$box.remove();
}
});
//add a new element like this
new joint.shapes.html.OdinElement({
position: { x: 80, y: 80 },
size: { width: 200, height: 50 },
label: 'label',
color: '#ff0000'
});
I've also tried to set it like the text is set in the label, but I've no idea if there is a function for that.
Does anyone have any idea how to do this?
Thanks a lot!
Tim
I found the answer myself!
Apparently it is not allowed to create a different element in the html variable than the given Element. So I had to change the joint.shapes.html.OdinElement to joint.shapes.html.Element and the joint.shapes.html.OdinElementView to joint.shapes.html.ElementView
Now it works all fine :)
Thanks for your help!

jQuery ui dialog box always positioned to top left

My jquery UI dialog box always gets positioned to top left no matter what I specify in the position attribute. I tried adding a css position to the div too. But it was of no use.
Can someone help me with this? Thanks.
$("<div>----Play again?---</div>").dialog({
title: 'Game Over!',
height: 'auto',
width: 'auto',
autoOpen: false,
draggable: true,
modal: false,
position: 'center',
buttons:{
"Yes": function() {
startGame();
$(this).dialog('close');
},
"No": function() {
alert('\nYour Score is: '+score+'\nGood Bye '+playerName+'!');
$(this).dialog('close');
}
}
});
I'm pretty sure you shouldnt need to set a position:
$("#dialog").dialog();
should centre by default.
I did have a look at the article, and also checked what it says on the official jquery-ui site about positioning a dialog : and in it were discussed 2 states of: initialise and after initialise.
Code examples - (taken from jQuery UI 2009-12-03)
Initialize a dialog with the position option specified.
$('.selector').dialog({ position: 'top' });
Get or set the position option, after init.
//getter
var position = $('.selector').dialog('option', 'position');
//setter
$('.selector').dialog('option', 'position', 'top');
I think that if you were to remove the position attribute you would find it centres by itself else try the second setter option where you define 3 elements of "option" "position" and "center".

Modifing the "X" close button of highslide popups

I'm using highslide in conjunction with highcharts and I want to modify the close button, more specifically, I want to call an additional function when a user clicks that "X" button.
When I inspect that "X" button, I get this in my console
<span>Close</span>
I want to do something like this
<span>Close</span>
But I am unable to find where the code for that is located.
I have tried adding this to my header in the html file itself, in addition to the highslide.config.js to manually override but it has not worked.
hs.registerOverlay({
html: '<div class="closebutton" onclick="return hs.close(this)" title="Close"></div>',
position: 'top right',
fade: 2 // fading the semi-transparent overlay looks bad in IE
});
Could somebody give me a helping hand?
////////////////////////////// updated
Thanks to Jeff B, I was able to accomplish the desired task using code that looks like this (although the example shown by Jeff B also works):
cursor: 'pointer',
point: {
events: {
click: function(event) {
hs.htmlExpand(null, {
pageOrigin: {
x: this.pageX,
y: this.pageY
},
headingText: this.ticker,
maincontentText: '<b>Detail:</b> ' + this.info,
width: 250
});
alert('function goes here');
hs.Expander.prototype.onBeforeClose = function(sender) {
alert('function goes here');
}
},
}
},
Why modify the button? Highslide provides an onBeforeClose prototype:
hs.Expander.prototype.onBeforeClose = function (sender) {
myotherfunction();
}
There is also an onAfterClose prototype if you want different timing.
onBeforeClose Documentation
Demo: http://jsfiddle.net/xjKFp/

jQuery UI Dialog, adding elements next to a button

One of the nice things about the jQuery UI Dialog is that it has an option for Buttons, which automatically positions them correctly. I just wonder: Can I somehow place elements next to the buttons? I have a little Ajax-Loader gif that I would like to display in the lower left corner of the dialog, while the buttons stay at the lower right?
I know I can just remove the buttons and create them manually in HTML, but as jQuery takes care of positioning and styling already for me, I'd like to keep that functionality if it makes sense.
$("#newProjectDialog").dialog({
bgiframe: true,
resizable: false,
width: 400,
modal: true,
overlay: {
backgroundColor: '#000',
opacity: 0.5
},
buttons: {
'Create': function() {
$("#ajax-loader").show();
// Make the Ajax Call and whatever else is needed
$(this).dialog('destroy');
},
Cancel: function() {
$(this).dialog('destroy');
}
}
});
All you basically need to do is
//depending on what #ajax-loader is you maybe need to style it (float:left, ...)
$("#ajax-loader").clone(true).appendTo("div.ui-dialog-buttonpane").show();
Below a fancier version with a few considerations incorporated.
I imagine #ajax-loader to look similar to this
<div id='ajax-loader'><img src='loader.gif' /><span>loading...</span></div>
or just this
<img id='ajax-loader' src='loader.gif' />
javascript can look like this
...
'Create': function() {
var btnpane = $("div.ui-dialog-buttonpane");
//prevent bad things if create is clicked multiple times
var there = btnpane.find("#ajax-loader").size() > 0;
if(!there) {
$("#ajax-loader").clone(true).appendTo(btnpane).show();
// Make the Ajax Call and whatever else is needed
// if ajax call fails maybe add $("#ajax-loader", btnpane).remove();
$(this).dialog('destroy');
}
},
...
A note
You should call .dialog('destroy') in the complete event of the ajax request else the dialog may get destroyed before the ajax request finished and the user may not even see the "loader".
How about just inserting your spinner before the first ui-dialog-button?
buttons: {
'Create' : function() {
$('<img src="spinner.gif" style="float: left;" />').insertBefore('.ui-dialog-buttonpane > button:first');
...ajax stuff...
$(this).dialog('destroy');
}
}
The best way to do this, is to create another button, make it totally transparent with no border, and add the animated gif as its background image. By using another button, you can easily locate its position relative to all your other buttons.
First, to be able to style buttons more, you need to create them with one level higher of definition. So instead of:
buttons: {
'Create': function() {
$("#ajax-loader").show();
// Make the Ajax Call and whatever else is needed
$(this).dialog('destroy');
},
Cancel: function() {
$(this).dialog('destroy');
}
}
Do it like this (notice square brackets and one more level of indent):
buttons: [
{
id: 'create-button',
class: 'create-button-class',
text: 'Create',
click: function() {
$("#ajax-loader").show();
// Make the Ajax Call and whatever else is needed
$(this).dialog('destroy');
}
},
text: 'Cancel',
click: function() {
$(this).dialog('destroy');
}
}
]
You can assign an id and class to each button or not. If you assign either id and/or class, then you can apply CSS styling to it.
<style>
.create-button-class{
height:50px;
width:50px;
left:-300px; /* Pushes it left, change value for desired location. */
}
.ui-dialog .ui-dialog-buttonpane #create-button {
color: transparent; /* no inner color and also hides text */
border: none; /* removes border */
background-image:url(images/spinner-gif-25px.gif); /*replaces default image */
background-size: 50px;
background-repeat: no-repeat;
}
</style>
If you like, create a normal additional button and use CSS property left to push it as far left in the button panel as you like, before making it transparent and no border.

Categories