Code:
Ext.application({
name: 'HelloExt',
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'fit',
items: [{
id: 'workbench-panel',
layout: {
type: 'hbox',
align: 'stretch'
},
items: [{
xtype: 'panel',
id: "hbp1",
cls: "hbpanel",
layout:{
type: 'vbox',
align: 'stretch'
},
flex: 1,
width: 10, height: 10,
border: false,
items:[{
xtype: 'panel',
layout: 'fit',
id: "hbp1vbp1",
title: 'hbp1-vboxpanel1',
cls: 'wbpanel vbpanel',
flex: 1,
width: 10, height: 10,
draggable: true,
html:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eu egestas diam. Quisque vulputate elementum ligula, ut venenatis orci condimentum quis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur suscipit, sapien quis sodales dignissim, ante est commodo nisi, dictum elementum purus orci non tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean mollis sollicitudin urna, eget mattis est egestas id. Suspendisse sed interdum ante. Proin scelerisque metus nec diam aliquam malesuada. Praesent nibh ante, pharetra nec viverra ut, fermentum a neque.</p> <p>Ut id tellus odio, eget elementum elit. Etiam ut erat ac nunc scelerisque aliquam non a elit. Etiam mollis, elit ut tincidunt dapibus, urna elit auctor velit, nec porta nisl tortor sit amet augue. Curabitur tortor ante, suscipit eget hendrerit ac, consectetur sit amet sem. In rhoncus, tellus quis lobortis commodo, velit risus rhoncus urna, eget posuere felis erat quis libero. Donec eu sodales arcu. Ut et lectus libero, et tristique elit. Donec purus turpis, luctus sed sodales in, porttitor id ligula. Etiam varius vestibulum rutrum. Aenean mollis ultricies sem, non rhoncus metus tempor ut. Aenean laoreet arcu suscipit justo fermentum vulputate.</p>",
}],
}, {
xtype: 'splitter'
}, {
xtype: 'panel',
id: "hbp2",
cls: "hbpanel",
layout:{
type: 'vbox',
align: 'stretch'
},
flex: 1,
width: 10, height: 10,
border: false,
items:[{
xtype: 'panel',
layout: 'fit',
id: "hbp2vbp1",
cls: 'wbpanel vbpanel',
title: 'hbp2-vboxpanel1',
flex: 1,
width: 10, height: 10,
draggable: true,
html:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eu egestas diam. Quisque vulputate elementum ligula, ut venenatis orci condimentum quis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur suscipit, sapien quis sodales dignissim, ante est commodo nisi, dictum elementum purus orci non tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean mollis sollicitudin urna, eget mattis est egestas id. Suspendisse sed interdum ante. Proin scelerisque metus nec diam aliquam malesuada. Praesent nibh ante, pharetra nec viverra ut, fermentum a neque.</p> <p>Ut id tellus odio, eget elementum elit. Etiam ut erat ac nunc scelerisque aliquam non a elit. Etiam mollis, elit ut tincidunt dapibus, urna elit auctor velit, nec porta nisl tortor sit amet augue. Curabitur tortor ante, suscipit eget hendrerit ac, consectetur sit amet sem. In rhoncus, tellus quis lobortis commodo, velit risus rhoncus urna, eget posuere felis erat quis libero. Donec eu sodales arcu. Ut et lectus libero, et tristique elit. Donec purus turpis, luctus sed sodales in, porttitor id ligula. Etiam varius vestibulum rutrum. Aenean mollis ultricies sem, non rhoncus metus tempor ut. Aenean laoreet arcu suscipit justo fermentum vulputate.</p>"
}, {
xtype: 'splitter'
}, {
xtype: 'panel',
layout: 'fit',
id: "hbp2vbp2",
cls: 'wbpanel vbpanel',
title: 'hbp2-vboxpanel2',
flex: 1,
width: 10, height: 10,
draggable: true,
html:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eu egestas diam. Quisque vulputate elementum ligula, ut venenatis orci condimentum quis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur suscipit, sapien quis sodales dignissim, ante est commodo nisi, dictum elementum purus orci non tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean mollis sollicitudin urna, eget mattis est egestas id. Suspendisse sed interdum ante. Proin scelerisque metus nec diam aliquam malesuada. Praesent nibh ante, pharetra nec viverra ut, fermentum a neque.</p> <p>Ut id tellus odio, eget elementum elit. Etiam ut erat ac nunc scelerisque aliquam non a elit. Etiam mollis, elit ut tincidunt dapibus, urna elit auctor velit, nec porta nisl tortor sit amet augue. Curabitur tortor ante, suscipit eget hendrerit ac, consectetur sit amet sem. In rhoncus, tellus quis lobortis commodo, velit risus rhoncus urna, eget posuere felis erat quis libero. Donec eu sodales arcu. Ut et lectus libero, et tristique elit. Donec purus turpis, luctus sed sodales in, porttitor id ligula. Etiam varius vestibulum rutrum. Aenean mollis ultricies sem, non rhoncus metus tempor ut. Aenean laoreet arcu suscipit justo fermentum vulputate.</p>"
}]
}]
}],
listeners: {
afterrender: function(_this, eOpts){
// get all the workbench panels
var panels = Ext.get('workbench-panel').select('.wbpanel');
// Configure the cars to be draggable
var workbenchPanels = Ext.get('workbench-panel').select('.wbpanel');
Ext.each(workbenchPanels.elements, function(el) {
var dropTarget = new Ext.dd.DropTarget(el, 'wbpanelsDDGroup');
var dd = Ext.getCmp(el.id).dd;
Ext.dd.DragDropManager.regDragDrop(dd, 'workbenchpanel');
dd.onBeforeDrag = function(data, event){
_this.origPanelData = data.panel;
// get the parent panel
_this.origPanelParent = Ext.getCmp(Ext.get(data.panel.id).parent('.x-panel').id);
// get the parent of the parent panel
_this.origPanelParentParent = Ext.getCmp(_this.origPanelParent.el.parent('.x-panel').id);
_this.origPanelIndex = _this.origPanelParent.items.indexOf(data.panel);
_this.origPanelDimensions = {
header: {
size: Ext.get(dd.id).down('.x-panel-header').getSize()
},
headerText: {
size: Ext.get(dd.id).down('.x-panel-header-text-container').getSize()
},
boxInner: {
size: Ext.get(dd.id).down('.x-box-inner').getSize()
},
body: {
size: Ext.get(dd.id).down('.x-panel-body').getSize(),
position: Ext.get(dd.id).down('.x-panel-body').getPositioning()
},
panel:{
position: Ext.get(dd.id).getPositioning()
}
};
};
dd.onDrag = function(event){
dd.proxy.getProxy().setPositioning(_this.origPanelDimensions.panel.position);
};
dd.onDragEnter = function(event, id){
};
dd.onDragOver = function(event, id){
//note:
// if dragged object is over the left-right side of the element, create a new panel for the parent hbox
// if dragged object is over the top-bottom side of the element, create a new panel for the parent vbox
// desired offset in pixels
var offset = 50;
var targetBox = Ext.getCmp(id);
var targetBoxPosition = targetBox.el.getXY();
var targetBoxSize = targetBox.el.getSize();
var mousePosition = event.getXY();
var targetBoxParent = Ext.getCmp(targetBox.el.parent('.x-panel').id); // and inside each HBox panel is a VBox
var targetBoxParentParent = Ext.getCmp(targetBoxParent.el.parent('.x-panel').id); // the whole workbench area is an HBox
var origPanelParent = Ext.getCmp(Ext.get(dd.id).parent('.x-panel').id);
var origPanelParentParent = Ext.getCmp(origPanelParent.el.parent('.x-panel').id);
if(id != dd.id && targetBox.xtype == 'panel'){
if(!_this.panelAdded){
// on top
if(mousePosition[1] < targetBoxPosition[1] + offset && mousePosition[1] > targetBoxPosition[1]){
var targetBoxIndex = targetBoxParent.items.indexOf(targetBox);
// check if there's a panel on top of the element and isn't the same id as the dragged panel
// targetBoxIndex - 2: to get panel, 2 elements above the placeholder. the first element is the splitter
if(targetBoxIndex == 0 || targetBoxParent.items.items[(targetBoxIndex - 2)].id != dd.id){
if(targetBoxIndex <= 0){
targetBoxIndex = 1;
}
targetBoxIndex -= 1;
// create placeholder to drop on to
var newPanel = targetBoxParent.insert(targetBoxIndex, {
xtype: 'panel',
layout: 'fit',
cls: 'wbpanel vbpanel wbplaceholder',
id: 'wbplaceholder',
flex: 1,
draggable: true,
html:""
});
Ext.dd.DragDropManager.regDragDrop(newPanel.dd, 'workbenchpanel');
_this.placeholderPanel = newPanel;
// if the placeholder have siblings, add a splitter
if(targetBoxParent.items.length > 1){
var newPanelIndex = targetBoxParent.items.indexOf(Ext.getCmp(newPanel.id));
var splitterPosition;
if(newPanelIndex == 0){ // if placeholder is at the top most
splitterPosition = newPanelIndex + 1; // add the splitter below the placeholder
}else{
splitterPosition = newPanelIndex; // add the splitter above the placeholder
targetBoxIndex += 1;
}
var newSplitter = targetBoxParent.insert(splitterPosition, {
xtype: 'splitter'
});
_this.addedSplitter = newSplitter;
_this.addedSplitterIndex = targetBoxParent.items.indexOf(newSplitter);
}
_this.placeholderIndex = targetBoxIndex;
_this.placeholderDimensions = {
size: newPanel.el.getSize(),
location: newPanel.el.getXY()
};
_this.placeholderParent = targetBoxParent;
_this.placeholderParentParent = Ext.getCmp(targetBoxParent.el.parent('.x-panel').id);
_this.panelAddedTargetParent = 'placeholderParent';
_this.panelAdded = true;
}
}else
//on bottom
if(mousePosition[1] > (targetBoxPosition[1] + targetBoxSize.height) - offset && mousePosition[1] < (targetBoxPosition[1] + targetBoxSize.height) + offset){
var targetBoxIndex = targetBoxParent.items.indexOf(Ext.getCmp(id));
// check if there's a panel below the element and isn't the same id as the dragged panel
// targetBoxIndex + 2: to get panel, 2 elements below the placeholder. the first element is the splitter
if(targetBoxIndex == targetBoxParent.items.length - 1 || targetBoxParent.items.items[(targetBoxIndex + 2)].id != dd.id){
// create placeholder to drop on to
var newPanel = targetBoxParent.insert(targetBoxIndex + 1, {
xtype: 'panel',
layout: 'fit',
cls: 'wbpanel vbpanel wbplaceholder',
id: 'wbplaceholder',
flex: 1,
draggable: true,
html:""
});
Ext.dd.DragDropManager.regDragDrop(newPanel.dd, 'workbenchpanel');
_this.placeholderPanel = newPanel;
// if the placeholder have siblings, add a splitter
if(targetBoxParent.items.length > 1){
var newPanelIndex = targetBoxParent.items.indexOf(Ext.getCmp(newPanel.id));
var splitterPosition;
if(newPanelIndex == targetBoxParent.items.length){ // if placeholder is at the bottom most
splitterPosition = newPanelIndex; // add the splitter above the placeholder
}else{
splitterPosition = newPanelIndex + 1; // add the splitter below the placeholder
}
splitterPosition = newPanelIndex;
var newSplitter = targetBoxParent.insert(splitterPosition, {
xtype: 'splitter'
});
_this.addedSplitter = newSplitter;
_this.addedSplitterIndex = targetBoxParent.items.indexOf(newSplitter);
}
_this.placeholderIndex = targetBoxParent.items.items.indexOf(Ext.getCmp(newPanel.id));
_this.placeholderDimensions = {
size: newPanel.el.getSize(),
location: newPanel.el.getXY()
};
_this.placeholderParent = targetBoxParent;
_this.placeholderParentParent = Ext.getCmp(targetBoxParent.el.parent('.x-panel').id);
_this.panelAddedTargetParent = 'placeholderParent';
_this.panelAdded = true;
}
}else
//on left
if(mousePosition[0] < targetBoxPosition[0] + offset && mousePosition[0] > targetBoxPosition[0]){
var targetBoxParentIndex = targetBoxParentParent.items.indexOf(targetBoxParent);
// check if there's a panel on top of the element and isn't the same id as the dragged panel
if((targetBoxParentIndex == 0 || targetBoxParentParent.items.items[(targetBoxParentIndex - 2)].id != origPanelParent.id) ||
(targetBoxParentParent.items.items[(targetBoxParentIndex + 2)].id == origPanelParent.id && origPanelParent.items.length > 1)){
if(targetBoxParentIndex <= 0){
targetBoxParentIndex = 1;
}
// create a new panel
var newPanel = targetBoxParentParent.insert(targetBoxParentIndex - 1, {
xtype: 'panel',
cls: "hbpanel",
layout:{
type: 'vbox',
align: 'stretch'
},
flex: 1,
border: false,
items: [{
xtype: 'panel',
layout: 'fit',
cls: 'wbpanel vbpanel wbplaceholder',
id: 'wbplaceholder',
flex: 1,
draggable: true,
html:""
}]
});
Ext.dd.DragDropManager.regDragDrop(newPanel.items.items[0].dd, 'workbenchpanel');
_this.placeholderPanel = newPanel.items.items[0];
// if the placeholder parent have siblings, add a splitter
if(targetBoxParentParent.items.length > 1){
var newPanelIndex = targetBoxParentParent.items.indexOf(Ext.getCmp(newPanel.id));
var splitterPosition;
if(newPanelIndex == 0){ // if the placeholder parent is at the left most
splitterPosition = newPanelIndex + 1; // add the splitter at the right of the placeholder
}else{
splitterPosition = newPanelIndex; // add the splitter at the left of the placeholder
}
var newSplitter = targetBoxParentParent.insert(splitterPosition, {
xtype: 'splitter'
});
_this.addedSplitter = newSplitter;
_this.addedSplitterIndex = targetBoxParentParent.items.indexOf(newSplitter);
}
_this.placeholderIndex = targetBoxParentParent.items.items.indexOf(Ext.getCmp(newPanel.id));
_this.placeholderDimensions = {
size: newPanel.items.items[0].el.getSize(),
location: newPanel.items.items[0].el.getXY()
};
_this.placeholderParent = newPanel;
_this.placeholderParentParent = Ext.getCmp(newPanel.el.parent('.x-panel').id);
_this.panelAddedTargetParent = 'placeholderParentParent';
_this.panelAdded = true;
}
}else
//on right
if(mousePosition[0] > (targetBoxPosition[0] + targetBoxSize.width) - offset && mousePosition[0] < targetBoxPosition[0] + targetBoxSize.width){
var targetBoxParentIndex = targetBoxParentParent.items.indexOf(targetBoxParent);
// check if there's a panel on top of the element and isn't the same id as the dragged panel
if((targetBoxParentIndex == targetBoxParentParent.items.length - 1 || targetBoxParentParent.items.items[(targetBoxParentIndex + 2)].id != origPanelParent.id) ||
(targetBoxParentParent.items.items[(targetBoxParentIndex + 2)].id == origPanelParent.id && origPanelParent.items.length > 1)){
// create a new panel
var newPanel = targetBoxParentParent.insert(targetBoxParentIndex + 1, {
xtype: 'panel',
cls: "hbpanel",
layout:{
type: 'vbox',
align: 'stretch'
},
flex: 1,
border: false,
items: [{
xtype: 'panel',
layout: 'fit',
cls: 'wbpanel vbpanel wbplaceholder',
id: 'wbplaceholder',
flex: 1,
draggable: true,
html:""
}]
});
Ext.dd.DragDropManager.regDragDrop(newPanel.items.items[0].dd, 'workbenchpanel');
_this.placeholderPanel = newPanel.items.items[0];
// if the placeholder parent have siblings, add a splitter
if(targetBoxParentParent.items.length > 1){
var newPanelIndex = targetBoxParentParent.items.indexOf(Ext.getCmp(newPanel.id));
var splitterPosition;
splitterPosition = newPanelIndex; // add the splitter at the left of the placeholder
var newSplitter = targetBoxParentParent.insert(splitterPosition, {
xtype: 'splitter'
});
_this.addedSplitter = newSplitter;
_this.addedSplitterIndex = targetBoxParentParent.items.indexOf(newSplitter);
}
_this.placeholderIndex = targetBoxParentParent.items.items.indexOf(Ext.getCmp(newPanel.id));
_this.placeholderDimensions = {
size: newPanel.items.items[0].el.getSize(),
location: newPanel.items.items[0].el.getXY()
};
_this.placeholderParent = newPanel;
_this.placeholderParentParent = Ext.getCmp(newPanel.el.parent('.x-panel').id);
_this.panelAddedTargetParent = 'placeholderParentParent';
_this.panelAdded = true;
}
}
// remove added panels and splitters
else{
}
}else{
// check added panel's location and size
// check for mouse is within the area of the added panel
if(mousePosition[0] > _this.placeholderDimensions.location[0] &&
mousePosition[0] < _this.placeholderDimensions.location[0] + _this.placeholderDimensions.size.width &&
mousePosition[1] > _this.placeholderDimensions.location[1] &&
mousePosition[1] < _this.placeholderDimensions.location[1] + _this.placeholderDimensions.size.height){
// mouse is inside the added placeholder, don't do anything
_this.insidePlaceholder = true;
}else{
// remove the placeholder
_this.placeholderParent.remove(_this.placeholderPanel);
if(_this.addedSplitter){
_this.placeholderParent.remove(_this.addedSplitter);
}
if(_this.placeholderParent.items.length <= 0){
_this.placeholderParentParent.remove(_this.placeholderParent);
_this.placeholderParentParent.remove(_this.addedSplitter);
}
_this.placeholderPanel = null;
_this.placeholderIndex = null;
_this.addedSplitter = null;
_this.addedSplitterIndex = null;
_this.placeholderDimensions = null;
_this.placeholderParent = null;
_this.placeholderParentParent = null;
_this.panelAddedTargetParent = null;
_this.panelAdded = false;
_this.insidePlaceholder = false;
}
}
}
};
dd.onDragDrop = function(event, id){
var origPanelParent = _this.origPanelParent;
var origPanelParentParent = _this.origPanelParentParent;
var origPanelData = _this.origPanelData;
var origPanelIndex = origPanelParent.items.indexOf(origPanelData);
var origPanelDimensions = _this.origPanelDimensions;
if(_this.panelAdded){
var placeholderParent = _this.placeholderParent;
var placeholderParentParent = _this.placeholderParentParent;
var placeholderPanel = _this.placeholderPanel;
var placeholderIndex = placeholderParent.items.indexOf(placeholderPanel);
var placeholderDimensions = _this.placeholderDimensions;
var addedSplitter = _this.addedSplitter;
var addedSplitterIndex = _this.addedSplitterIndex;
var panelAddedTargetParent = _this.panelAddedTargetParent;
// get origPanel splitter sibling
if(origPanelParent.items.length > 1){ // check siblings of origPanel
var origPanelSplitter = null;
if(origPanelIndex == 0){ // check if origPanel is the first child
origPanelSplitter = origPanelParent.items.items[origPanelIndex + 1];
}else{
origPanelSplitter = origPanelParent.items.items[origPanelIndex - 1];
}
if(origPanelSplitter.xtype == 'splitter'){
origPanelParent.remove(origPanelSplitter);
}
}
// check if origPanelParent and placeholderParent panels are the same
// if different, apply insert. Otherwise, move the panel
if(origPanelParent.id == placeholderParent.id){
// move the old panel to different location
origPanelParent.move(origPanelParent.items.indexOf(origPanelData) , placeholderIndex);
}else{
// insert the old panel to different location
placeholderParent.insert(placeholderIndex, origPanelData);
// remove the old panel from the old location
origPanelParent.remove(origPanelData);
}
// remove the placeholder
placeholderParent.remove(placeholderPanel.id);
// check if parent panel is empty, then remove parent panel
if(origPanelParent.items.items.length <= 0){
var origPanelParentIndex = origPanelParentParent.items.indexOf(origPanelParent);
var origPanelParentSplitter = null;
if(origPanelParentIndex == origPanelParentParent.items.length - 1){ // check if origPanelParent is last child
origPanelParentSplitter = origPanelParentParent.items.items[origPanelParentIndex - 1];
}else{
origPanelParentSplitter = origPanelParentParent.items.items[origPanelParentIndex + 1];
}
if(origPanelParentSplitter.xtype == 'splitter'){
origPanelParentParent.remove(origPanelParentSplitter);
}
origPanelParentParent.remove(origPanelParent.id);
}
if(origPanelParent.id == placeholderParent.id){
// resize moved panel because it disappears after moving
//Ext.get(origPanelData.id).setSize(placeholderDimensions.size);
Ext.get(origPanelData.id).down('.x-panel-header').setSize(origPanelDimensions.header.size);
Ext.get(origPanelData.id).down('.x-panel-header-text-container').setSize(origPanelDimensions.headerText.size);
Ext.get(origPanelData.id).down('.x-box-inner').setSize(origPanelDimensions.boxInner.size);
Ext.get(origPanelData.id).down('.x-panel-body').setSize(origPanelDimensions.body.size);
Ext.get(origPanelData.id).down('.x-panel-body').setPositioning(origPanelDimensions.body.position);
}else{
// resize moved panel because it disappears after moving
Ext.get(origPanelData.id).setSize({
width: '100%',
height: placeholderDimensions.size.height
});
Ext.get(origPanelData.id).down('.x-panel-header').setSize({
width: '100%',//placeholderDimensions.size.width,
height: origPanelDimensions.header.size.height
});
Ext.get(origPanelData.id).down('.x-panel-header-text-container').setSize({
width: '100%', //placeholderDimensions.size.width - 11,
height: origPanelDimensions.headerText.size.height
});
Ext.get(origPanelData.id).down('.x-box-inner').setSize({
width: '100%',//placeholderDimensions.size.width - 1,
height: origPanelDimensions.boxInner.size.height
});
Ext.get(origPanelData.id).down('.x-panel-body').setSize({
width: '100%',//placeholderDimensions.size.width,
height: placeholderDimensions.size.height - 25,
});
Ext.get(origPanelData.id).down('.x-panel-body').setPositioning(origPanelDimensions.body.position);
}
_this.panelAdded = false;
}else{
Ext.get(dd.id).down('.x-panel-header').setSize(origPanelDimensions.header.size);
Ext.get(dd.id).down('.x-panel-header-text-container').setSize(origPanelDimensions.headerText.size);
Ext.get(dd.id).down('.x-box-inner').setSize(origPanelDimensions.boxInner.size);
Ext.get(dd.id).down('.x-panel-body').setSize(origPanelDimensions.body.size);
Ext.get(dd.id).down('.x-panel-body').setPositioning(origPanelDimensions.body.position);
}
};
dd.onDragOut = function(event, id){
if(!_this.insidePlaceholder){
if(_this.panelAdded){
_this.placeholderParent.remove(_this.placeholderPanel);
if(_this.addedSplitter){
_this.placeholderParent.remove(_this.addedSplitter);
}
_this.placeholderPanel = null;
_this.placeholderIndex = null;
_this.addedSplitter = null;
_this.addedSplitterIndex = null;
_this.placeholderDimensions = null;
_this.placeholderParent = null;
_this.placeholderParentParent = null;
_this.panelAddedTargetParent = null;
_this.panelAdded = false;
}
}
};
dd.onInvalidDrop = function(event){
};
});
}
}
});
}
});
There's also a bug there that after you drop a panel, it disappears (or at least just turn into a small square). I fixed it by resizing the panel after it is dropped.