How can I add tools in a tab of an Extjs TabPanel? - extjs

How can I add the buttons (tools) in the header of each tab, in a TabControl?
I just could add tools in the TabPanel, but I want to add in the tabs.
Image
I also tried this, but no success:
var lTabPanel = Ext.create('Ext.tab.Panel', {
width: 400,
height: 400,
renderTo: document.body,
items: [{
title: 'Home',
html: 'Home',
itemId: 'home'
}, {
title: 'Users',
html: 'Users',
itemId: 'users',
hidden: true
}, {
title : 'Tickets',
html : 'Tickets',
itemId : 'tickets',
tools:[{
type:'gear',
tooltip: 'Options',
handler: function(event, toolEl, panel){
// Some code.
}
}]
}]
});
Any idea?
Thanks!

Quite tough actually.
If you check their source code, Ext.tab.Panel is in fact using Card Layout and for each tab, they used Ext.tab.Tab to do the tab buttons.
Then if you check the source code of Ext.tab.Tab, it's in fact extending Ext.button.Button, which is just a modified button.
So if you need to add tools, I afraid the best way is to extend Ext.tab.Tab and write your own tab buttons. You might want to check out how they create closeable buttons in line 233 of /src/tab/Tab.js.
(Ext-4.0.2a)
Cheers
EDIT
So we know Ext.tab.Tab is extending Ext.button.Button, we can make use of this fact, and I have came out with this solution, check this out at fiddle: http://jsfiddle.net/uBxqY/4/
Basically, I have extended Ext.tab.Tab, and modified the buttonWrapper class so to have the arrow css added. Nothing fancy, everything work out of the box.
Also I have overrided the onClick function so the menu won't be expanded when the user click on the tab itself. A little bit dirty, but it works (borrowed prototype.onClick from Ext.button.Split.
Working example: http://jsfiddle.net/uBxqY/4/, or source:
Ext.define('Ext.ux.tab.Tab', {
extend: 'Ext.tab.Tab',
alias: 'widget.ux.menutab',
requires: [
//We just need the onClick from Split button
'Ext.button.Split'
],
/**
* Menu align, if you need to hack the menu alignment
*/
menuAlign: 'tl-bl?',
constructor: function() {
this.callParent(arguments);
//Kind of harsh, we need the click action from
//split button instead.
//Or if you preferred, you can always override this
//function and write your own handler.
this.onClick = Ext.button.Split.prototype.onClick;
},
/**
* Hack the default css class and add
* some resonable padding so to make it looks
* great :)
*/
onRender: function() {
this.callParent(arguments);
//We change the button wrap class here! (HACK!)
this.btnWrap.replaceCls('x-tab-arrow x-tab-arrow-right',
'x-btn-split x-btn-split-right')
.setStyle('padding-right', '20px !important');
}
});
Ext.create('Ext.tab.Panel', {
renderTo: Ext.getBody(),
style: 'margin:10px;',
defaults: {
bodyStyle: 'padding:10px;'
},
plain: true,
items: [{
title: 'Split Tab',
//tabConfig is taken up during tab formation
tabConfig: {
//We use our own custom tab!
xtype: 'ux.menutab',
menu: [{
text: 'Menu item 1'
},{
text: 'Menu item 2'
}]
},
html: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
},{
title: 'Normal Tab',
html: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
}]
});

Thank you for sharing solution!
This is my way (based on yours):
Ext.define('CB.view.ux.TabMenu', {
extend: 'Ext.tab.Tab',
alias: 'widget.tabmenu',
requires: [
'Ext.button.Split'
],
menuAlign: 'tl-bl?',
constructor: function() {
this.callParent(arguments);
this.onClick = Ext.button.Split.prototype.onClick;
},
onRender: function() {
this.callParent(arguments);
this.btnWrap.insertSibling({
tag: 'a',
cls: 'arrow-inside-tab',
href: '#'
}, 'after');
this.btnWrap.addCls(['pdr10']); //padding-right: 10px; to make some place for arrow
}
});
CSS:
.arrow-inside-tab {
display: block;
position: absolute;
width: 11px;
height: 11px;
top: 5px;
right: 4px;
background: url("../js/extjs/resources/ext-theme-classic/images/button/arrow.gif") 1px 0 no-repeat;
}

Related

how to change the position of Checkbox in sweetalert 2

I'm looking for a way to find if it is possible to change the position of the checkbox in sweetalert 2 from the center to the upper position? I used this code:
(async () => {
const { value: accept } = await Swal.fire({
title: 'Terms and conditions',
input: 'checkbox',
inputValue: 1,
inputPlaceholder:
'Yes, I agree to receive an email, including educational materials, product and company announcements, and community even information, from T&C. I can unsubscribe at any time. I would like to opt into receiving marketing communications as outlined above.',
confirmButtonText:
'Continue <i class="fa fa-arrow-right"></i>',
inputValidator: (result) => {
return !result && 'You need to agree with T&C'
}
})
if (accept) {
Swal.fire('You agreed with T&C :)')
}
})()
The result of this code is this:
I would like to change the checkbox from the center to the position of the word "Yes".
Use the customClass param to achieve the custom placement for the input:
Swal.fire({
input: 'checkbox',
inputPlaceholder: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
customClass: {
input: 'top-checkbox'
}
})
.top-checkbox input {
align-self: flex-start;
margin: 3px 10px 0 0 !important;
}
<script src="https://cdn.jsdelivr.net/npm/sweetalert2#11"></script>

In Angular JS, is there a way to watch for changes to the DOM without using scope.watch?

I am attempting to create an angularjs bootstrap accordion that scrolls the accordion to the top when opened.
These solutions are close to what I would like to do:
AngularJS / ui-bootstrap accordion - scroll to top of active (open) accordion on click
https://www.peterbouda.eu/making-an-angular-ui-bootstrap-accordion-scrolling-to-top-when-opening.html
However, they use a timeout or scope watches. I would like to avoid using these unless absolutely necessary.
Is there a way to accomplish this without using $watch or setTimeout?
Here is a plunk of what i am trying to do, this is using the $watch: https://plnkr.co/edit/XQpUdrdjqaCGom4L9yIJ
app.directive( 'scrollTop', scrollTop );
function scrollTop() {
return {
restrict: 'A',
link: link
};
}
function link( scope, element ) {
scope.collapsing = false;
var jqElement = $( element) ;
scope.$watch( function() {
return jqElement.find( '.panel-collapse' ).hasClass( 'collapsing' );
}, function( status ) {
if ( scope.collapsing && !status ) {
if ( jqElement.hasClass( 'panel-open' ) ) {
$( 'html,body' ).animate({
scrollTop: jqElement.offset().top - 30
}, 500 );
}
}
scope.collapsing = status;
} );
}
The directive can be simplified to:1
app.directive( 'scrollTop', function scrollTop($timeout) {
return {
restrict: 'A',
link: postLink
};
function postLink(scope, elem, attrs) {
elem.on("click", function(e) {
if (scope.status.isOpen) {
$timeout(function() {
$( 'html,body' ).animate({
scrollTop: elem.offset().top - 30
}, 500 );
});
}
});
}
})
<uib-accordion>
<div heading="Section Title" is-open="status.isOpen"
ng-repeat="section in vm.sections"
scroll-top
uib-accordion-group>
<uib-accordion-heading>
<div ng-class="{isOpen: vm.isOpen}">
<h3>{{section.sectionTitle}}</h3>
<p>{{section.sectionSubHeader}}</p>
</div>
</uib-accordion-heading>
<div class="clearfix">
<b>Index+1={{$index+1}}</b>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</div>
</uib-accordion>
The $timeout is necessary because the browser needs to render the DOM with the newly opened and closed elements before it can compute the proper scroll offset.
The DEMO on PLNKR
I have found a way to do this from the controller.
I added a function that is triggered on ng-click to report the is-open status of the accordion.
Using the component lifecycle hook $doCheck I was able to watch for changes to the state of vm.isOpen. $doCheck runs on the end of every digest cycle, so I did not need to set a $scope.watch or $timeOut
The $doCheck runs essentially the same code as the directive in the question
app.controller('homeController', function($state, $element, sections, $transitions) {
var vm = this;
vm.$onInit = function() {
vm.sections = sections.getSections();
};
function updateOpenStatus() {
vm.collapsing = false;
vm.isOpen = vm.sections.some(function(item) {
return item.isOpen;
});
}
vm.$doCheck = function() {
if (vm.isOpen) {
var elem = $element.find('.panel-collapse');
var status = elem.hasClass('collapsing');
if (vm.collapsing && !status) {
var parentElem = elem.closest('.panel-open');
if (elem.parent().hasClass('panel-open')) {
$('html,body')
.stop()
.animate({
scrollTop: parentElem.offset().top - 52
}, 'fast');
}
}
vm.collapsing = status;
}
};
});
I updated the uib-accordion to call the function in the controller
<uib-accordion>
<div heading="Section Title" is-open="section.isOpen" ng-repeat="section in vm.sections" scroll-top uib-accordion-group>
<uib-accordion-heading>
<div ng-class="{isOpen: section.isOpen}" ng-click="vm.toggleOpen()">
<h3>{{section.sectionTitle}}</h3>
</div>
</uib-accordion-heading>
<div class="clearfix">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</div>
</uib-accordion>
Updated Plnkr: https://plnkr.co/edit/5EqDfmVOa0hzFfaQqdI0?p=preview

Api-platform accessing embedded relations in hydra:member

I'm using Api-Platform and React as client.
I have a Forum entity which contains other objects : an author (User entity) and a category (Category entity).
I embedded these entities with #Groups annotations to retrieve them more easily.
For instance, when I fetch /api/forums/ on Postman I get this result :
{
"#context": "/api/contexts/Forum",
"#id": "/api/forums",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "/api/forums/79",
"#type": "Forum",
"id": 79,
"subject": "Sujet numéro 0",
"message": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"category": {
"#id": "/api/categories/183",
"#type": "Category",
"title": "Category 2"
},
It seems good : we can see my category object is linked to Forum in hydra:member array, and a "title" field.
But I noticed that the result I really get is different in my react app for all my nested objects.
I only get the IRIs..
For instance with the same request :
...
fetch('forums')
.then(response =>
response
.json()
.then(retrieved => ({ retrieved, hubURL: extractHubURL(response) }))
)
.then(({ retrieved, hubURL }) => {
retrieved = normalize(retrieved);
...
I get this result :
{
"#context": "/api/contexts/Forum",
"#id": "/api/forums",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "/api/forums/79",
"#type": "Forum",
"id": 79,
"subject": "Sujet numéro 0",
"message": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"category": "/api/categories/183",
Every other fields have disapeared on "category", and I don't get why.
Could anyone help me with that ?
Thanks in advance
I found the solution (how silly of me), so I share you the tip :
In src/utils/dataAccess file, there is a normalize function :
export function normalize(data) {
if (has(data, 'hydra:member')) {
// Normalize items in collections
data['hydra:member'] = data['hydra:member'].map(item => normalize(item));
return data;
}
// Flatten nested documents
return mapValues(data, value =>
Array.isArray(value)
? value.map(v => get(v, '#id', v))
: get(value, '#id', value)
);
}
It appears that this function is called after each fetch :
return fetch(id)
.then(response =>
response
.json()
.then(retrieved => ({ retrieved, hubURL: extractHubURL(response) }))
)
.then(({ retrieved, hubURL }) => {
//retrieved = normalize(retrieved);
dispatch(loading(false));
dispatch(success(retrieved));
....
As you can see, I just commented the normalize line (useless in my case). Do that wherever it is needed, and everything should work again !

How to pass an Argument to Method in Perl

I'm trying to use this Perl Method: HTML::Highlight - A module to highlight words or patterns in HTML documents.
The methode itself isn't acctualy the problem but the way how I can pass a Attribute.
Example which works:
use HTML::Highlight;
$text = 'Lorem ipsum Velit ullamco ex anim quis Duis laboris ut proident velit eu dolor Ut amet proident aliqua minim officia sunt commodo veniam dolor id reprehenderit reprehenderit non nulla incididunt mollit exercitation minim commodo ut quis laboris ex proident.';
# create the highlighter object
my $hl = new HTML::Highlight (
words => [
'ex',
'ul',
],
wildcards => [
undef,
],
colors => [
'red; font: bold',
],
debug => 0
);
my $hl_document = $hl->highlight($text);
print $hl_document;
What I'd like to do is something like this:
use HTML::Highlight;
$text = 'Lorem ipsum Velit ullamco ex anim quis Duis laboris ut proident velit eu dolor Ut amet proident aliqua minim officia sunt commodo veniam dolor id reprehenderit reprehenderit non nulla incididunt mollit exercitation minim commodo ut quis laboris ex proident.';
# create the highlighter object
#keywords = "ex", "ul";
my $hl = new HTML::Highlight (
words => #keywords,
wildcards => [
undef,
],
colors => [
'red; font: bold',
],
debug => 0
);
my $hl_document = $hl->highlight($text);
print $hl_document;
As you can see in the code snippet above, I'd like to pass an existing array to the object.
How can I do that correctly?
Currently I get an exeption like that:
HTML::Highlight - "words" and "wildcards" parameters must be references to arrays at C:\Skripts\Perl\syntax_highlight.pl line 8.
As said in error message, pass a reference:
my $hl = HTML::Highlight->new(
words => \#keywords,
# here __^
wildcards => [
undef,
],
colors => [
'red; font: bold',
],
debug => 0
);

How Can I Make a Nested Scrollable Panel in ExtJS?

I'm new to ExtJS, and I'm trying to create a nested, scrollable panel within a window. Unfortunately, none of the answers I've researched so far have provided a solution to this particular problem (or I'm just not understanding them).
Extjs scrollable panel
Autoscroll on parent panel, when there is overflow on child panels.Extjs
Extjs 4.1 What layout for 3 components scrollable
Here is a set of examples that contains a scrollable panel ('Framed Panel: Width 280/Height 180'):
http://docs.sencha.com/extjs/4.2.1/extjs-build/examples/panel/panel.html
Evidently, this technique doesn't work when nesting panels inside a window, as per my sample code below (using version 4.2.1.883):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Nested Scrollable Panel Demo</title>
<script type="text/javascript" src="ext/ext-all-dev.js"></script>
<link rel="stylesheet" href="ext/resources/css/ext-all.css" />
<script type="text/javascript">
Ext.onReady(function(){
var btnTest = Ext.create("Ext.Button",{
text : "Scrollable Nested Panel Test",
renderTo: Ext.getBody()
});
btnTest.on('click', function(){
var html_text = '<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed metus nibh, sodales a, '+
'porta at, vulputate eget, dui. Pellentesque ut nisl. Maecenas tortor turpis, interdum non, sodales non, iaculis ac, '+
'lacus. Vestibulum auctor, tortor quis iaculis malesuada, libero lectus bibendum purus, sit amet tincidunt quam turpis '+
'vel lacus. In pellentesque nisl non sem. Suspendisse nunc sem, pretium eget, cursus a, fringilla vel, urna.<br/><br/>'+
'Aliquam commodo ullamcorper erat. Nullam vel justo in neque porttitor laoreet. Aenean lacus dui, consequat eu, adipiscing '+
'eget, nonummy non, nisi. Morbi nunc est, dignissim non, ornare sed, luctus eu, massa. Vivamus eget quam. Vivamus tincidunt '+
'diam nec urna. Curabitur velit. Lorem ipsum dolor sit amet.</p>';
var win = Ext.create("Ext.window.Window",{
title : "Main Window",
width : 300,
height : 200,
maximizable : true,
defaults: {
xtype : "panel",
height : 60,
collapsible : true,
autoscroll : true
},
items : [{
title : "Menu",
html : 'menu panel content'
},{
html: html_text,
frame : true,
width : '100%',
height : 300
}]
});
win.show();
});
});
</script>
</head>
<body>
<h1>Nested Scrollable Panel Demo</h1>
</body>
</html>
How can I get this to work, where the content of the second panel will scroll, like the panel entitled 'Framed Panel: Width 280/Height 180' in the linked example above?
If you add autoScroll: true to the window configuration the content of the window will be scrollable. (Example below)
However, like Evan is pointing out, if you want the content of the second panel to be scrollable you don't set a height on the panel and add the autoScroll: true property to the second panel, add a flex and vbox layout to the window. (second example)
First Example
Live Example
Ext.onReady(function(){
var btnTest = Ext.create("Ext.Button",{
text : "Scrollable Nested Panel Test",
renderTo: Ext.getBody()
});
btnTest.on('click', function(){
var html_text = '<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed metus nibh, sodales a, '+
'porta at, vulputate eget, dui. Pellentesque ut nisl. Maecenas tortor turpis, interdum non, sodales non, iaculis ac, '+
'lacus. Vestibulum auctor, tortor quis iaculis malesuada, libero lectus bibendum purus, sit amet tincidunt quam turpis '+
'vel lacus. In pellentesque nisl non sem. Suspendisse nunc sem, pretium eget, cursus a, fringilla vel, urna.<br/><br/>'+
'Aliquam commodo ullamcorper erat. Nullam vel justo in neque porttitor laoreet. Aenean lacus dui, consequat eu, adipiscing '+
'eget, nonummy non, nisi. Morbi nunc est, dignissim non, ornare sed, luctus eu, massa. Vivamus eget quam. Vivamus tincidunt '+
'diam nec urna. Curabitur velit. Lorem ipsum dolor sit amet.</p>';
var win = Ext.create("Ext.window.Window",{
title : "Main Window",
width : 300,
height : 200,
maximizable : true,
autoScroll: true,
defaults: {
xtype : "panel",
height : 60,
collapsible : true,
autoscroll : true
},
items : [{
title : "Menu",
html : 'menu panel content'
},{
html: html_text,
frame : true,
width : '100%',
height : 300
}]
});
win.show();
});
});
Second Example
Live Example
var win = Ext.create("Ext.window.Window",{
title : "Main Window",
width : 300,
height : 200,
maximizable : true,
layout: {
type: 'vbox',
align: 'stretch'
},
defaults: {
xtype : "panel",
collapsible : true,
autoscroll : true
},
items : [{
title : "Menu",
html : 'menu panel content'
},{
html: html_text,
frame : true,
flex: 1,
autoScroll: true
}]
});

Resources