I am trying to create this behavior and not sure whether Gridstack supports it or not. I have 3 Gridstack grids: Grid1, Grid2, and Grid3. Grid1 is a standalone grid and Grid3 is nested inside Grid2. I need to be able to drag widgets from Grid1 both into Grid2 (outer grid) and into Grid3 (nested grid). Following samples I was able to drag widgets between 2 top level grids and create a nested grid, but not combining these 2 together. If this is supported - any pointers are appreciated.
NB: Expand the snippet to full screen
$(document).ready(function() {
$('.grid-stack').gridstack();
});
.grid-stack {
background: lightgoldenrodyellow;
}
.grid-stack-item-content {
color: #2c3e50;
text-align: center;
background-color: #18bc9c;
}
.grid-stack .grid-stack {
/*margin: 0 -10px;*/
background: rgba(255, 255, 255, 0.3);
}
.grid-stack .grid-stack .grid-stack-item-content {
background: lightpink;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
<script type="text/javascript" src='//cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.js'></script>
<script type="text/javascript" src='//cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.jQueryUI.min.js'></script>
<div class="container-fluid">
<h1> Multilevel Nested grids demo</h1>
<div class="grid-stack" id="container-stack">
<div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="4">
<div class="grid-stack-item-content">
<span>Grid One</span>
<div class="grid-stack" id="grid-one">
<div class="grid-stack-item widget" data-gs-x="0" data-gs-y="0" data-gs-width="3" data-gs-height="1">
<div class="grid-stack-item-content">1</div>
</div>
<div class="grid-stack-item widget" data-gs-x="3" data-gs-y="0" data-gs-width="3" data-gs-height="1">
<div class="grid-stack-item-content">2</div>
</div>
</div>
</div>
</div>
<div class="grid-stack-item" data-gs-x="4" data-gs-y="0" data-gs-width="8" data-gs-height="4">
<div class="grid-stack-item-content">
<span>Grid Two</span>
<div class="grid-stack" id="grid-two">
<div class="grid-stack-item widget" data-gs-x="0" data-gs-y="0" data-gs-width="3" data-gs-height="1">
<div class="grid-stack-item-content">3</div>
</div>
<div class="grid-stack-item widget" data-gs-x="3" data-gs-y="0" data-gs-width="3" data-gs-height="1">
<div class="grid-stack-item-content">4</div>
</div>
<div class="grid-stack-item" data-gs-x="6" data-gs-y="0" data-gs-width="6" data-gs-height="3">
<div class="grid-stack-item-content">
<span>Grid Three</span>
<div class="grid-stack" id="grid-three">
<div class="grid-stack-item widget" data-gs-x="0" data-gs-y="0" data-gs-width="6" data-gs-height="1">
<div class="grid-stack-item-content">5</div>
</div>
<div class="grid-stack-item widget" data-gs-x="6" data-gs-y="0" data-gs-width="6" data-gs-height="1">
<div class="grid-stack-item-content">6</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Following samples I was able to drag widgets between 2 top level grids and create a nested grid, but not combining these 2 together. If this is supported
Sad but true, that's not possible. At least, not with gridstack.
The key behind this dragging mechanism is accomplished by the acceptWidgets option. But this can't handle multilevel .grid-stack element. Hence, error appears.
You can try to modify the script added in the snippet to something like this:
$("#container-stack").gridstack({
acceptWidgets: '.grid-stack-item'
})
But sadly, this will cause error once you start dragging any widget. But it works with single level nesting, which is not definitely what you are looking for.
The documentation also does not indicate anything at all regarding the nested level dragging.
But the reason I am assuming this isn't possible is this issue, also this one.
I guess this is (almost) exactly what you wanted. but there is no response from any officials. Also, it's three years old. Another flaw that indicates this project is dying is when you try to access some of their files such as the script, you get a security warning, which prevented me to add this snippet for a while.
Therefore, if I were you I would go for jqueryUI and custom code this.
Update
Here is a snippet of something similar to what you expected I guess, let me know if this is right, then I will improve this once again, like adding resizing, snap to sibling widgets and a few more things:
Once again, check the snippet in fullscreen mode.
$("#gridThree").draggable({
snap: '#gridTwo',
snapMode: 'inner',
zIndex: 5,
containment: 'parent'
});
$(".widgetInOne, .widgetInTwo, .widgetInThree").draggable({
snap: '#gridOne, #gridTwo, #gridThree',
snapMode: 'inner',
zIndex: false,
stack: 'div',
cursor: 'grab',
// grid: [ 100, 100 ]
});
$("#gridOne, #gridTwo, #gridThree").droppable({
accept: '.widgetInOne, .widgetInTwo, .widgetInThree',
drop: function(event, ui) {
if ($(event.target).find($(event.toElement)).length == 0) {
$(event.toElement).css({
'left': '',
top: ''
});
$(event.target).append($(event.toElement));
}
}
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#gridOne {
background: #cecece;
width: 40%;
height: 400px;
display: inline-block;
margin-right: 4%;
vertical-align: top;
}
.widgetInOne,
.widgetInTwo,
.widgetInThree {
width: 100px;
height: 100px;
padding: 0.5em;
}
#gridTwo {
background: #bfe9f3;
width: 50%;
height: 400px;
display: inline-block;
margin-left: 4%;
vertical-align: top;
position: relative;
}
#gridThree {
background: #ffdda9;
width: 300px;
height: 300px;
display: inline-block;
vertical-align: top;
position: absolute;
right: 100px;
top: 0;
}
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="https://jqueryui.com/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="gridOne">
<div class="ui-widget-content widgetInOne">
<p>One</p>
</div>
</div>
<div id="gridTwo">
<div class="ui-widget-content widgetInTwo">
<p>Two</p>
</div>
<div id="gridThree">
<div class="ui-widget-content widgetInThree">
<p>Three</p>
</div>
</div>
</div>
A Few Notable things here:
When you drag a widget into a grid, the widget element actually moves in that grid (in the DOM structure), so any parent dependent css selector might not work here. only apply css with the widget class.
For now the widgets only snaps to the grid inner edges (not to the outer side of other widgets), to find more check: here I couldn't find any other option but to use // grid: [ 100, 100 ] for this one.
Resizable option is not added here yet, hope you can tweak it as you need
This is code from an old drag/drop fiddle I composed (an age ago!), with areas that are both draggable and droppable. The items that can be pulled across to either of the droppable areas can be dragged again from one area to another and dragged up and down. While the items are not sized the same as are in your example, it goes to show that the same user experience can be achieved by using simply jquery/jquery-ui without sticking to gridstack. You may save yourself some laborious hours by working outside the grid! ;)
Hope this helps
fiddle
$("#launchPad").height($(window).height() - 20);
var dropSpace = $(window).width() - $("#launchPad").width();
$("#dropZone").width(dropSpace - 70);
$("#dropZone").height($("#launchPad").height());
$(".card").draggable({
appendTo: "#launchPad",
cursor: "move",
helper: 'clone',
revert: "invalid",
});
$("#launchPad").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$("#launchPad").append($(ui.draggable));
}
});
$(".stackDrop1").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$(this).append($(ui.draggable));
}
});
$(".stackDrop2").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$(this).append($(ui.draggable));
}
});
body {
margin: 0;
}
#launchPad {
width: 200px;
float: left;
border: 1px solid #eaeaea;
background-color: #f5f5f5;
}
#dropZone {
float: right;
border: 1px solid #eaeaea;
background-color: #ffffcc;
}
.card {
width: 150px;
padding: 5px 10px;
margin: 5px;
border: 1px solid #ccc;
background-color: #eaeaea;
}
.stack {
width: 180px;
border: 1px solid #ccc;
background-color: #f5f5f5;
margin: 20px;
}
.stackHdr {
background-color: #eaeaea;
border: 1px solid #fff;
padding: 5px
}
.stackDrop1,
.stackDrop2 {
min-height: 100px;
padding: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<body>
<div id="launchPad">
<div class="card draggable">
apple
</div>
<div class="card draggable">
orange
</div>
<div class="card draggable">
banana
</div>
<div class="card draggable">
car
</div>
<div class="card draggable">
bus
</div>
</div>
<div id="dropZone">
<div class="stack">
<div class="stackHdr">
Drop here
</div>
<div class="stackDrop1 droppable">
</div>
</div>
<div class="stack">
<div class="stackHdr">
Or here
</div>
<div class="stackDrop2 droppable">
</div>
</div>
</div>
I create fork which solves the problem of nested grids.
Related
I try to make an editor with a sidebar. to drag components from the sidebar to the editor area.
But, I had some problems. the most critical one is.
to sort dropped component at a specific position into the editor area for example or in other words I need to drag and drop component 1 and component 2 and then component 3 between 1 and 2.
I used for that jquery sortable function.
Error:
I get no sort for the dropped component, moreover, if I try to sort
the dropped components later, I get components cloned inside the
editor area rather than get it sorted
here is my attempt
$( function() {
$("#side").resizable().draggable();
$("#editor")
.sortable().disableSelection().droppable({
accept: ".component",
drop: function(event, ui)
{ $(this).append(ui.draggable.clone()); }
});
$(".component")
.mousedown
(function(){ $(this).css('cursor','grabbing'); })
.draggable
({ helper: "clone" });
});
#editor, #side, .component{padding: 10px;}
#editor {
position: fixed;
top:0;
left:0;
right:0;
bottom:0;
background:#9999;
z-index: -1;
text-align: right;
cursor: default;
}
#side{
position: fixed;
top:0;
left:0;
width:300px;
height: 100vh;
background:red;
color:yellow;
cursor: move;
}
.component{
background-color:blue;
width: 80px;
height: 50px;
margin:20px;
display: inline-block;
}
.component:hover{
cursor:grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="side">
<h3 id="title">I'm resizable and draggable</h3>
<div class="component">
I'm droppable 1
</div>
<div class="component">
I'm droppable 2
</div>
<div class="component">
I'm droppable 3
</div>
<div class="component">
I'm droppable 4
</div>
</div>
<div id="editor" contenteditable="true">
<h3 id="title">I'm editable</h3>
</div>
Consider using connectToSortable with your Draggable. See the following example.
$(function() {
$("#side").resizable().draggable();
$("#editor")
.sortable({
items: "div.component"
}).disableSelection();
$(".component")
.mousedown(function() {
$(this).css('cursor', 'grabbing');
})
.draggable({
helper: "clone",
connectToSortable: "#editor"
});
});
#editor,
#side,
.component {
padding: 10px;
}
#editor {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #9999;
z-index: -1;
text-align: right;
cursor: default;
}
#side {
position: fixed;
top: 0;
left: 0;
width: 300px;
height: 100vh;
background: red;
color: yellow;
cursor: move;
}
.component {
background-color: blue;
width: 80px;
height: 50px;
margin: 20px;
display: inline-block;
}
.component:hover {
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="side">
<h3 id="title">I'm resizable and draggable</h3>
<div class="component">
I'm droppable 1
</div>
<div class="component">
I'm droppable 2
</div>
<div class="component">
I'm droppable 3
</div>
<div class="component">
I'm droppable 4
</div>
</div>
<div id="editor" contenteditable="true">
<h3 id="title">I'm editable</h3>
</div>
The cloned items are then dropped directly into the Sortable.
sortable on part works fine - single are sorted horizontally.
Why parent is not sortable - to sort part vertically ?
$('.parent').sortable({
items: ".part",
containment: "parent",
tolerance: "pointer",
axis: "y",
});
$('.part').sortable({
containment: "parent",
tolerance: "pointer",
axis: "x",
});
.parent{
background:silver;
position:fixed;
width:90%;
left:5%;
height:50px;
overflow-y:scroll;
}
.part{
background:lightgreen;
margin:5px;
display:grid;
grid-template-columns:50% 50%;
}
.single{
background:gold;
cursor:cell;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class='parent'>
<div class='part'>
<div class='single'>lorem1</div>
<div class='single'>ipsum1</div>
</div>
<div class='part'>
<div class='single'>lorem2</div>
<div class='single'>ipsum2</div>
</div>
</div>
The primary issue is that there is no place to click on $(".part") without clicking on $(".single"). The target of the sort event is then the part and not the parent.
I would advise either a handle, or some amount of padding.
$(function() {
$('.parent').sortable({
items: "> .part",
containment: "parent",
tolerance: "pointer",
axis: "y",
});
$('.part').sortable({
containment: "parent",
items: "> .single",
tolerance: "pointer",
axis: "x",
});
});
.parent {
background: silver;
position: fixed;
width: 90%;
left: 5%;
height: 50px;
overflow-y: scroll;
}
.part {
background: lightgreen;
margin: 5px;
padding-left: 16px;
display: grid;
grid-template-columns: 50% 50%;
}
.single {
background: gold;
cursor: cell;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class='parent'>
<div class='part'>
<div class='single'>lorem1</div>
<div class='single'>ipsum1</div>
</div>
<div class='part'>
<div class='single'>lorem2</div>
<div class='single'>ipsum2</div>
</div>
</div>
By adding some padding, 16px worth on the left, I now have a defined space I can grab a Part without grabbing a single, and I can sort it as expected. items may not be needed, but it does clarify things when reviewing the code.
Hope that helps.
I have a basic drag and drop trello-like kanban board. You can drag tasks between different grey boxes. It uses HTML drag and drop API found here https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API.
var dropTarget = document.querySelector(".drop-target");
var draggables = document.querySelectorAll(".drag-task");
// Tells the other side what data is being passed (e.g. the ID is targeted)
draggables.forEach(item => {
item.addEventListener("dragstart", function(ev){
ev.dataTransfer.setData("srcId", ev.target.id);
});
})
// The end destination, prevent browsers default drag and drop (disabling breaks feature)
// because it's disabled by browsers by default
dropTarget.addEventListener('dragover', function(ev) {
ev.preventDefault();
});
// End destination where item is dropped into
dropTarget.addEventListener('drop', function(ev) {
ev.preventDefault();
let target = ev.target;
let droppable = target.classList.contains('drag-box');
let srcId = ev.dataTransfer.getData("srcId");
if (droppable) {
ev.target.appendChild(document.getElementById(srcId));
}
});
/***********DRAGGABLE BACKGROUND ****************/
.drag-box {
background-color: lightgray;
float: right;
width: 120px;
min-height: 50px;
padding-bottom: 30px;
height: auto;
margin: 30px;
}
.drag-task {
background-color: white;
margin: 15px;
}
.drop-active {
border: 1px dashed red;
}
<div class="drop-target">
<div class="drag-box">
<div class="drag-card">
<div draggable="true" id="task1" class="drag-task">Test Card 1</div>
</div>
<div class="drag-card">
<div draggable="true" id="task2" class="drag-task">Test Card 2</div>
</div>
<div class="drag-card">
<div draggable="true" id="task3" class="drag-task">Test Card 3</div>
</div>
</div>
<div class="drag-box">
</div>
<div class="drag-box">
</div>
</div>
What I want to do to achieve is an effect similar to this gif found here. This creates another <div> element on the same level as drag-card class on a draghover effect, and repositions itself accordingly.
I know I have to use dragover and dragleave event listeners but that's as far as I got. I added this code at the end of the file. I have never used drag event listeners so this is new to me.
var makeHoverElement= true;
dropTarget.addEventListener("dragover", function(ev){
if(makeHoverElement){
let newNode =document.createElement('div');
newNode.className ='drop-active'
ev.target.parentElement.prepend(newNode);
makeHoverElement = false;
}
});
dropTarget.addEventListener("dragleave", function(ev){
// really I have no idea how to make this effect
});
Results so far have not turned out as I expected. Dragover is applying to element where the task item originated from
The problem is in ev.target.parentElement.prepend(newNode);
Your ev.target is still a child of the node you are dragging it from. That's why the dotted border div gets added to the 'old' box. I suggest that in your 'dragover' function you explicitly find the element the mouse is over and add your newNode to it. For example, you can select it by document.querySelector(":hover" ) or try to handle 'mouseover' events there.
As for the 'dragleave' effect, I suggest you clone your ev.target with Node.cloneNode() method and append the clone to the ev.target.parentElement using Node.insertBefore().
MDN on .insertBefore()
Using jquery and jquery UI, I did something quite like this a while ago. I didn't create a "make new card" function, I began with a "launchpad" and created two droppable areas that cards could be appended to and switched between - similar to what you have. Using "intersect" as I remember was a tipping point to getting it to work as I wanted - being able to move elements up and down the list (so they don't necessarily move back to where they originated). Perhaps it could be a starting point for you?
Here's the fiddle (the jquery is old.. recommend updating to newer versions)
Hope this helps.
EDIT: I made a couple of small tweaks to your code to add an outline and change the cursor on move. According to a comment on another question, adding a border is the most efficient way to create the visual 'outline' effect. There is a longer way to create the 'sortable' effect which is demoed in this codepen I found, and explained simply, the function is based around calculating hover position and if the dragged element is half-way over an item in the list, the effect displays and the item can be dropped in between list items.
Hope this is clear enough!
// Tells the other side what data is being passed (e.g. the ID is targeted)
var dropTarget = document.querySelector(".drop-target");
var draggables = document.querySelectorAll(".drag-task");
// Tells the other side what data is being passed (e.g. the ID is targeted)
draggables.forEach(item => {
item.addEventListener("dragstart", function(ev) {
ev.dataTransfer.setData("srcId", ev.target.id);
});
})
// The end destination, prevent browsers default drag and drop (disabling breaks feature)
// because it's disabled by browsers by default
dropTarget.addEventListener('dragover', function(ev) {
ev.preventDefault();
});
// End destination where item is dropped into
dropTarget.addEventListener('drop', function(ev) {
ev.preventDefault();
let target = ev.target;
let droppable = target.classList.contains('drag-box');
let srcId = ev.dataTransfer.getData("srcId");
if (droppable) {
ev.target.appendChild(document.getElementById(srcId));
}
});
.drag-box {
background-color: lightgray;
float: left;
width: 120px;
min-height: 80px; /*lengthened the height slightly*/
padding-bottom: 30px;
height: auto;
margin: 30px;
cursor: move; /*added the 'cross' cursor*/
}
.drag-task {
background-color: white;
margin: 10px;
padding: 5px; /*added padding to make tiles bigger*/
border:1px dashed #000000; /*set an outline*/
}
.drop-active {
border: 1px dashed red;
cursor: pointer; /*change the pointer back to the default cursor while moving between lists*/
}
<div class="drop-target">
<div class="drag-box">
<div class="drag-card">
<div draggable="true" id="task1" class="drag-task">Test Card 1</div>
</div>
<div class="drag-card">
<div draggable="true" id="task2" class="drag-task">Test Card 2</div>
</div>
<div class="drag-card">
<div draggable="true" id="task3" class="drag-task">Test Card 3</div>
</div>
</div>
<!-- added tiles to the 2nd list (and deleted 3rd box)-->
<div class="drag-box">
<div class="drag-card">
<div draggable="true" id="orange" class="drag-task">Orange</div>
</div>
<div class="drag-card">
<div draggable="true" id="apple" class="drag-task">Apple</div>
</div>
<div class="drag-card">
<div draggable="true" id="pear" class="drag-task">Pear</div>
</div>
</div>
$("#launchPad").height($(window).height() - 20);
var dropSpace = $(window).width() - $("#launchPad").width();
$("#dropZone").width(dropSpace - 70);
$("#dropZone").height($("#launchPad").height());
$(".card").draggable({
appendTo: "#launchPad",
cursor: "move",
helper: 'clone',
revert: "invalid",
});
$("#launchPad").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$("#launchPad").append($(ui.draggable));
}
});
$(".stackDrop").droppable({
tolerance: "intersect",
accept: ".card",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
$(this).append($(ui.draggable));
}
});
body {
margin: 0;
background-color: #ffffcc;
}
#launchPad {
width:170px;
float:left;
border: 1px solid #eaeaea;
background-color: #f5f5f5;
}
#dropZone {
float:right;
border: 1px solid #eaeaea;
background-color: #ffffcc;
}
.card {
width: 130px;
padding: 5px 10px;
margin:5px;
border:1px solid #ccc;
background-color: #eaeaea;
}
.stack {
display:inline-block;
vertical-align:top;
width: 180px;
border: 1px solid #ccc;
background-color: #f5f5f5;
margin: 20px;
}
.stackHdr {
background-color: #eaeaea;
border: 1px solid #fff;
padding: 5px
}
.stackDrop {
min-height:100px;
padding: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<div id="launchPad">
<div class="card draggable" >
apple
</div>
<div class="card draggable">
orange
</div>
<div class="card draggable">
banana
</div>
<div class="card draggable">
car
</div>
<div class="card draggable">
bus
</div>
</div>
<div id="dropZone">
<div class="stack">
<div class="stackHdr">
Drop here
</div>
<div class="stackDrop droppable">
</div>
</div>
<div class="stack">
<div class="stackHdr">
Or here
</div>
<div class="stackDrop droppable">
</div>
</div>
</div>
I have four droppable divs on the page. In addition, I have a number of draggables that can be dropped into each droppable.
If I drop enough draggables into a droppable then it overflows. What I want to do is enable overflow-y: scroll; on that droppable once I it is required.
The problem is that I if I have the 'overflow-y: scroll;' enabled then the draggables appear below the droppable divs (eg. they disappear). Alternatively, if I don't have `'overflow-y:' set then it obviously overflows.
Underneith the code below is a snippet you can run to look at this (note: you'll probably need this in full screen to see the issue).
Any help would be greatly appreciated :)
$(document).ready(function() {
setDraggables();
setDroppables();
});
// Manage drag and drop of added items
$(document).on('drag', 'div.uiTask', function(e) {
});
function setDraggables() {
$('.uiTask').draggable();
}
function setDroppables() {
$("#urgentImportantTopLeft").droppable({
drop: function(event, ui) {
$(this).append('<div class="uiTask">This is a task</div>');
setDraggables();
ui.draggable.remove();
}
});
$("#urgentImportantTopRight").droppable({
drop: function(event, ui) {
$(this).append('<div class="uiTask">This is a task</div>');
setDraggables();
ui.draggable.remove();
}
});
$("#urgentImportantBottomLeft").droppable({
drop: function(event, ui) {
$(this).append('<div class="uiTask">This is a task </div>');
setDraggables();
ui.draggable.remove();
}
});
$("#urgentImportantBottomRight").droppable({
drop: function(event, ui) {
$(this).append('<div class="uiTask">This is a task</div>');
setDraggables();
ui.draggable.remove();
}
});
}
#urgentImportant {
position: absolute;
height: 100%;
width: 100%;
}
#urgentImportantTopLeft,
#urgentImportantTopRight,
#urgentImportantBottomLeft,
#urgentImportantBottomRight {
z-index: 0;
height: 50%;
border: 1px solid white;
}
.tasks {} .uiTask {
display: inline-block;
width: 100%;
padding: 0.5em;
margin: 0.25em 0.25em;
background-color: grey;
border-radius: 5px;
cursor: grab;
z-index: 1000;
}
<head>
<link rel="stylesheet" href="http://www.w3schools.com/lib/w3.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
</head>
<div id="urgentImportant">
<div id="urgentImportantTopLeft" class="w3-container w3-half w3-blue">Urgent / Important
<div class="tasks"></div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
<div class="uiTask">This is a task</div>
</div>
<div id="urgentImportantTopRight" class="w3-container w3-half w3-blue">Not urgent / Important
<br>
<br>
<div class="uiTask">This is a task</div>
</div>
<div id="urgentImportantBottomLeft" class="w3-container w3-half w3-blue">Urgent / Not important
<br>
<br>
<div class="uiTask">This is a task</div>
</div>
<div id="urgentImportantBottomRight" class="w3-container w3-half w3-blue">Not urgent / Not important
<br>
<br>
<div class="uiTask">This is a task</div>
</div>
</div>
You have to use some jquery draggable methods to handle this,i have updated your code below.
//replace your setDraggables func with this.
function setDraggables() {
$('.uiTask').draggable({
helper: 'clone',
revert: 'invalid'
});
}
//change your css as this
#urgentImportantTopLeft,
#urgentImportantTopRight,
#urgentImportantBottomLeft,
#urgentImportantBottomRight {
z-index: 0;
height: 50%;
border: 1px solid white;
overflow:scroll;
}
.tasks {
overflow: overlay;
}
.uiTask {
display: block;
width: 20%;
padding: 0.5em;
margin: 0.25em 0.25em;
background-color: grey;
border-radius: 5px;
cursor: grab;
z-index: 1000;
}
Please refer this fiddle here to understand the problem I'm trying to explain. I want such a layout wherein divs will utilize all the available space. There are 8 divs here which are resizable. When I minimize divs A and B, an empty space is seen below these divs. I want divs D and E to occupy that empty space.
How can I achieve this? There are some jQuery plugins available like gridstack out there but their resizing feature is somewhat different. Without using any available jQuery plugin, is it possible to achieve mentioned effect? If you have any useful resources please share. Thanks in advance.
Edit
One solution could be to have 3 columns in .container but this solution might not work if div is resized horizontally.
Change your div structure to the following I think that will help you.
$(document).ready(function() {
$('.tile').resizable({
handles: 'e, s, se',
containment: '.container'
});
});
.tile
{
height: 180px;
width: 100%;
float: left;
background-color: rgb(232, 232, 232);
border: 1px solid red;
margin: 0% 0% 3% 0%;
min-height: 20px;
max-height: 360px;
max-width: 540px;
min-width: 180px;
text-align: centre
}
.verticalspace{
width:180px;
float:left;
margin: 0% 0% 0% 1%;
}
.container{
overflow: hidden
}
<div class="container">
<div class= "verticalspace">
<div class="tile">A</div>
<div class="tile">E</div>
</div>
<div class= "verticalspace">
<div class="tile">B</div>
<div class="tile">F</div>
</div>
<div class= "verticalspace">
<div class="tile">C</div>
<div class="tile">G</div>
</div>
<div class= "verticalspace">
<div class="tile">D</div>
<div class="tile">H</div>
</div>
</div>
this kind of structure will stay close even if somediv above it is collapsed also
You could try a 3 col solution (And use javascript to properly order the items in each column):
.col {
background: whitesmoke;
width: 165px;
float: left;
}
.item {
height: 150px;
width: 150px;
margin: auto;
background: grey;
margin-top: 15px;
}
.custom {
height: 265px;
}
.custom2 {
height: 30px;
}
<div class="container">
<div class="col">
<div class="item"></div>
<div class="item custom"></div>
<div class="item"></div>
</div>
<div class="col">
<div class="item"></div>
<div class="item custom2"></div>
<div class="item"></div>
</div>
<div class="col">
<div class="item custom2"></div>
<div class="item"></div>
<div class="item custom"></div>
</div>
</div>