I have a drag and drop list of parent and child categories. I want to set the data attributes to the numerical order when I hit the test button. The parent data attribute currently works. But I'm having trouble getting the child data attribute to work correctly.
So for each parent, the child category should be number 1,2,3... and then the count should reset for the next parent. Right now the child doesn't reset for the new parent. How can I get the child to reference its parent so I can get the counter to reset?
Not sure if this is the best way to accomplish this. The end goal is to grab those data attributes and use that number to update the orderId in the database.
$(".categories").sortable({
connectWith: ".categories",
placeholder: "placeholder",
start: function(event, ui) {
if (ui.helper.hasClass('child-category')) {
ui.placeholder.removeClass('placeholder');
ui.placeholder.addClass('placeholder-sub');
} else {
ui.placeholder.removeClass('placeholder-sub');
ui.placeholder.addClass('placeholder');
}
},
sort: function(event, ui) {
var pos;
if (ui.helper.hasClass('child-category')) {
pos = ui.position.left + 20;
$('#cursor').text(ui.position.left + 20);
} else if (ui.helper.hasClass('parent-category')) {
pos = ui.position.left;
$('#cursor').text(ui.position.left);
}
if (pos >= 32 && !ui.helper.hasClass('child-category')) {
ui.placeholder.removeClass('placeholder');
ui.placeholder.addClass('placeholder-sub');
ui.helper.addClass('child-category');
ui.helper.removeClass('parent-category');
} else if (pos < 25 && ui.helper.hasClass('child-category')) {
ui.placeholder.removeClass('placeholder-sub');
ui.placeholder.addClass('placeholder');
ui.helper.removeClass('child-category');
ui.helper.addClass('parent-category');
}
}
});
$(".category").attr("data-order-parent", "");
$(".category").attr("data-order-child", "");
var i = 1;
$(".parent-category").each(function() {
$(this).attr("data-order-parent", i);
var j = 1;
$(".child-category").each(function() {
$(this).attr("data-order-child", j);
j++;
});
i++;
});
.categories {
list-style: none outside none;
}
.category {
background: #fff;
border: 1px solid #ddd;
cursor: move;
height: 50px;
line-height: 50px;
padding: 0 10px;
width: 480px;
}
.category:hover {
background-color: #F5F5F5;
}
.child-category {
margin-left: 40px;
width: 440px;
}
.placeholder {
background: #fff;
border: 1px dashed #ccc;
height: 50px;
width: 480px;
}
.placeholder-sub {
background: #fff;
border: 1px dashed #ccc;
height: 50px;
width: 440px;
margin-left: 40px;
}
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<button id="TEST" type="button">TEST</button>
<ul class='categories'>
<li class="category parent-category" data-order-parent="" data-order-child="">
categoryName-1
</li>
<li class="category parent-category" data-order-parent="" data-order-child="">
categoryName-2
</li>
<li class="category parent-category" data-order-parent="" data-order-child="">
categoryName-3
</li>
<li class="category parent-category" data-order-parent="" data-order-child="">
categoryName-4
</li>
</ul>
You should just iterate over your categories only once: children always follow after the last parent, so it is not so difficult to keep track.
Add this to the sortable object argument:
stop: function(event, ui) {
$(".category").attr("data-order-parent", "");
$(".category").attr("data-order-child", "");
var i = 1, j = 1;
$(".category").each(function() { // Iterate all categories (not only parents)
if ($(this).is(".parent-category")) { // Is it parent or child?
$(this).attr("data-order-parent", i++);
j = 1; // Reset child counter
} else {
$(this).attr("data-order-child", j++);
}
});
}
Related
JSFiddle: https://jsfiddle.net/1fLmtyoj/15/
I'm following this example to see if an element is overflowing, but something isn't working, this is for a DIV: Check with jquery if div has overflowing elements and
https://stackoverflow.com/a/7668692/1005607
I have an <LI> tag containing <SPAN>s. From the above answer, it's necessary to check (1) Overflow active, (2) Semi-visible parts. I combined them into the following function.
function isOverflowing(element) {
// 1. Main Part for overflow check
if (element.offsetHeight < element.scrollHeight ||
element.offsetWidth < element.scrollWidth) {
return true;
}
// 2. Partially invisible items
var invisibleItems = [];
for(var i=0; i<element.childElementCount; i++){
if (element.children[i].offsetTop + element.children[i].offsetHeight >
element.offsetTop + element.offsetHeight ||
element.children[i].offsetLeft + element.children[i].offsetWidth >
element.offsetLeft + element.offsetWidth ){
invisibleItems.push(element.children[i]);
}
}
if (invisibleItems.length) {
return true;
}
// Otherwise, neither Part 1 nor 2, return FALSE
return false;
}
In the JSFiddle, the expected output is that #1 and #3 are not overflowing, but #2 and #4 are overflowing. But all 4 are shown as not overflowing.
If you were to display element via the console, you would see that element does not have the attribute childElementCount -- but the first member of the element array does. Thus, refer to element[0] for all the attributes, and it behaves as expected. I think this is due to the selector you've used.
function isOverflowing(element) {
// 1. Main Part for overflow check
if (element.offsetHeight < element.scrollHeight ||
element.offsetWidth < element.scrollWidth) {
return true;
}
// 2. Partially invisible items
var invisibleItems = [];
for(var i=0; i<element[0].childElementCount; i++){
if (element[0].children[i].offsetTop + element[0].children[i].offsetHeight >
element[0].offsetTop + element[0].offsetHeight ||
element[0].children[i].offsetLeft + element[0].children[i].offsetWidth >
element[0].offsetLeft + element[0].offsetWidth ){
invisibleItems.push(element[0].children[i]);
}
}
if (invisibleItems.length) {
return true;
}
// Otherwise, neither Part 1 nor 2, return FALSE
return false;
}
$('#result').html('#1? ' + isOverflowing($('li:eq(0)')) +
'#2? ' + isOverflowing($('li:eq(1)')) +
'#3? ' + isOverflowing($('li:eq(2)')) +
'#4? ' + isOverflowing($('li:eq(3)'))
);
.type1 {
border: 1px solid black;
width: 130px;
height: 30px;
margin-bottom: 5px;
}
.type2 {
border: 1px dotted red;
width: 50px;
height: 25px;
margin-bottom: 45px;
}
.type3 {
border: 1px dashed blue;
width: 200px;
height: 40px;
margin-bottom: 5px;
}
.type4 {
border: 1px dashed green;
width: 100px;
height: 10px;
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="type1"><span>Some text in LI 1</span></li>
<li class="type2"><span>Some more text in LI 2</span></li>
<li class="type3"><span>A long string of text in LI3</span></li>
<li class="type4"><span>A much longer string of text in LI4</span></li>
</ul>
<br/>
<br/>
<br/>
<br/>
<p id="result"></p>
As you say, however, this solution isn't generic enough -- it doesn't allow for nested DOM nodes. To fix this, we would want a recursive function. Try this, possibly. It's working, I think, but it really made my brain hurt to think recursively. ;)
function isOverflowing(element) {
/*******
* This is going to be a recursive function -- first,
* it'll check if there are children elements and,
* if not, simply return true. In the event there
* are child elements, it should recurse over each
* to see if any child overflows, whether partially
* invis or not.
******/
var elOverflows;
var el = element[0];
// On the first iteration, we initialize these. On every
// recursive iteration, we simply preserve them
var mainHeight = el.offsetTop + el.offsetHeight,
mainOffsetHeight = el.offsetHeight,
mainWidth = el.offsetLeft + el.offsetWidth,
mainOffsetWidth = el.offsetWidth;
// 1. Main Part for overflow check
if (mainOffsetHeight < el.scrollHeight ||
mainOffsetWidth < el.scrollWidth) {
elOverflows = true;
return elOverflows;
}
/***
* 2. If the current element doesn't contain any
* children, and the above check didn't return,
* then we don't have any overflow.
***/
if (el.childElementCount == 0) {
elOverflows = false;
return elOverflows;
} else {
// Here, we have child elements. We want to iterate
// over each of them and re-call isOverflowing() on
// each one. This is the recursion, allowing us to
// have any number of nested child elements.
$(el.children).each(function() {
elOverflows = isOverflowing($(this));
});
return elOverflows;
}
}
$("#container li").each(function() {
$("#result").append("<p>#" + $(this).index() + ": " + isOverflowing($(this)));
})
.type1 {
border: 1px solid black;
width: 130px;
height: 30px;
margin-bottom: 5px;
}
.type2 {
border: 1px dotted red;
width: 50px;
height: 25px;
margin-bottom: 45px;
}
.type3 {
border: 1px dashed blue;
width: 200px;
height: 40px;
margin-bottom: 5px;
}
.type4 {
border: 1px dashed green;
width: 100px;
height: 10px;
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id='container'>
<li class="type1"><span>Some text in LI 1</span></li>
<li class="type2"><span>Some more text in LI 2</span></li>
<li class="type3"><span>A long string <span>containing A much longer string </span> in its center bit.</span>
</li>
<li class="type4"><span>A much longer string of text in LI4</span></li>
</ul>
<br/>
<br/>
<br/>
<br/>
<p id="result"></p>
I've made isOverflowing recursive, and for each child node of the current node, I simply re-call it again, until there are no more child nodes. passing the return value out to the initial call allows us to see if any of the child nodes exceed the bounds of the initial node.
Hope this helps!
So I do have a loop of droppable areas where user is able to drop items. Size of the loop can be different. It depends on user's input. You can check fiddle here
Here is my droppable area:
$(".projLeader ol").droppable({
tolerance: 'pointer',
hoverClass: 'highlight',
drop: function(ev, ui)
{
var zz = ui.draggable.text()
var xyz = itm.includes(zz);
if (xyz === false)
{
var item = ui.draggable;
if (!ui.draggable.closest('.placeholder').length) item = item.clone().draggable();// if item was dragged from the source list - clone it
//this.innerHTML = ''; // clean the placeholder
item.addClass('dropClass').appendTo(this);
// append item to placeholder
//add to array
itm.push(zz);
var n = $(this).closest("div.proc").find(".dropClass").length;
$(this).closest("div.proc").find("h6").text("Items Dropped: " + n + ".");
}
else
{
alert('Name is Already Exist');
}
}
});
The problem is I got warning message for each field. For example if I drop item in box1 and then want to drop same item in box2 I got warning message. How can I fix it? Thanks for any help
I spent some time understanding your code and here's the solution. I added some code to detect if an existing box already exists.Hope it helps :)!
var itm = [];
$( "#savebutton" ).click(function() { LISTOBJ.saveList(); });
$("#myAccordion").accordion({heightStyle:"content", active: false, collapsible:true});
$("#myAccordion li").draggable({
appendTo: "body",
helper: "clone",
start: function(ev, ui){ ui.helper.width($(this).width()); }
});
$(".projLeader ol").droppable({
tolerance: 'pointer',
hoverClass: 'highlight',
drop: function(ev, ui)
{
var zz = ui.draggable.text()
var xyz = itm.includes(zz);
if (xyz === false)
{
var item = ui.draggable;
var map = {}, i , size;
var flag = false;
if (!ui.draggable.closest('.placeholder').length){
item = item.clone().draggable();// if item was dragged from the source list - clone it
//this.innerHTML = ''; // clean the placeholder
item.addClass('dropClass').appendTo(this);
// append item to placeholder
//add to array
var n = $(this).closest("div.proc").find(".dropClass").length;
$(this).closest("div.proc").find("h6").text("Items Dropped: " + n + ".");
var listOfElements = $(this).closest("div.proc").find("li").text();
var newarr = listOfElements.split('x');
newarr.shift();
var actualArrayLength = newarr.length;
for (i = 0, size = newarr.length; i < size; i++){
if (map[newarr[i]]){
xyz = true;
alert("Name is Already Exist");
$(this).closest("div.proc").find("h6").text("Items Dropped: " + (n - 1) + ".");
$(this).closest("div.proc").find("li:last-child").remove();
return false;
}
else{
map[newarr[i]] = true;
newarr[newarr.length - 1];
}
}
}
}
}
});
$(".projLeader").on('click', '.closer', function(){
var item = $(this).closest('.item');
itm.splice(item);
item.fadeTo(200, 0, function(){ item.remove(); })
});
var LISTOBJ = {
saveList: function() {
var listCSV = "";
$( ".projLeader li" ).each(function() {
if (listCSV === "") {
listCSV = $(this).text();
} else {
listCSV += ", " + $(this).text();
}
$("#output").text(listCSV);
$(".hiddenListInput").val(listCSV);
});
}
}
body {
font-family: verdana;
font-size: 12px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
margin-bottom: 10px;
}
ol{list-style-type: none;}
.item { height:20px; width: 180px; margin:5px; padding:5px; border:1px solid gray; background-color: #cd8; position: relative; }
.item .closer { position: absolute; right: 5px; top: 2px; font: bold 14px arial; color: #666; padding: 1px 3px; line-height: 1; cursor: pointer; display: none;}
.item .closer:hover { color: #000; }
.placeholder { height: 30px; width: 195px; margin: 5px; background: #eee; border: 1px dashed #999; }
.placeholder .item { margin: 0; }
ol .item .closer { display: block; }
.highlight { border: 1px solid red; background: #fff; }
.highlight .item { opacity: 0.3; }
.ui-draggable-dragging { z-index: 99; opacity: 1 !important; }
.dropClass {
background-color: lightblue;
padding-left: 10px;
width: 180px;
border: 1px solid black;
border-radius: 8px;
margin-bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<h1 class="ui-widget-header">Products</h1>
<div id="myAccordion">
<h3>T-Shirts</h3>
<div>
<ul>
<li class="item"><span class="closer">x</span>Lolcat Shirt</li>
<li class="item"><span class="closer">x</span>Cheezeburger Shirt</li>
<li class="item"><span class="closer">x</span>Buckit Shirt</li>
</ul>
</div>
<h3>Bags</h3>
<div>
<ul>
<li class="item"><span class="closer">x</span>Zebra Striped</li>
<li class="item"><span class="closer">x</span>Black Leather</li>
<li class="item"><span class="closer">x</span>Alligator Leather</li>
</ul>
</div>
<h3>Gadgets</h3>
<div>
<ul>
<li class="item"><span class="closer">x</span>iPhone</li>
<li class="item"><span class="closer">x</span>iPod</li>
<li class="item"><span class="closer">x</span>iPad</li>
</ul>
</div>
</div>
<div class='proc'><pre>
<h6> </h6><br /></pre>
<div class="projLeader">
<label>Box1:</label>
<div class="ui-widget-content">
<ol id = "ID1">
<li class="placeholder" name="projLeader"></li>
<input type="hidden" name="projLeader" class="hiddenListInput1" />
</ol>
</div>
</div>
</div>
<div class='proc'><pre>
<h6> </h6><br /></pre>
<div class="projLeader">
<label>Box2:</label>
<div class="ui-widget-content">
<ol id = "ID2" >
<li class="placeholder" name="projLeader"></li>
<input type="hidden" name="projLeader" class="hiddenListInput2" />
</ol>
</div>
</div>
</div>
<br/>
<input type="submit" id="savebutton" class="button" value="Save" onclick="userSubmitted = true;" />
<div id="output"></div>
I'm trying to have a bgcolor change for an element on mouseover, mouseout, and onclick. The problem is Javascript overwrites my onclick with mouseout, so I can't have both. So is there any way to have mouseover reset after mouseout?
function init() {
document.getElementById('default').onmouseover = function() {
tabHoverOn('default', 'grey')
};
document.getElementById('default').onmouseout = function() {
tabHoverOff('default', 'yellow')
};
document.getElementById('section2').onmouseover = function() {
tabHoverOn('section2', 'grey')
};
document.getElementById('section2').onmouseout = function() {
tabHoverOff('section2', 'yellow')
};
document.getElementById('section3').onmouseover = function() {
tabHoverOn('section3', 'grey')
};
document.getElementById('section3').onmouseout = function() {
tabHoverOff('section3', 'yellow')
};
}
function tabHoverOn(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
function tabHoverOff(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
var current = document.getElementById('default');
function tab1Highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab1highlight";
current = id;
}
function tab2highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab2highlight";
current = id;
}
function tab3highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab3highlight";
current = id;
}
window.onload = init();
body {
width: 900px;
margin: 10px auto;
}
nav {
display: block;
width: 80%;
margin: 0 auto;
}
nav > ul {
list-style: none;
}
nav > ul > li {
display: inline-block;
margin: 0 3px;
width: 150px;
}
nav > ul > li > a {
width: 100%;
background-color: #ffff66;
border: 1px solid #9b9b9b;
border-radius: 12px 8px 0 0;
padding: 8px 15px;
text-decoration: none;
font-weight: bold;
font-family: arial, sans-serif;
}
main {
display: block;
width: 80%;
margin: 0 auto;
border: 1px solid #9b9b9b;
padding: 10px;
}
main > h1 {
font-size: 1.5em;
}
.tab1highlight {
background-color: #339966;
color: white;
}
.tab2highlight {
background-color: #ff6666;
color: white;
}
.tab3highlight {
background-color: #6600ff;
color: white;
}
main img {
border: 5px solid #eeefff;
width: 80%;
margin-top: 20px;
}
<body>
<nav>
<ul>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
</nav>
<main>
<h1>Exercise: Navigation Tab #5</h1>
<ul>
<li>
Combine the navigation tab exercises #1, #3, and #4 in one file, including <br>
<ul>
<li>temporarily change the background color of a tab when the cursor is hovering on it.</li>
<li>set the foreground and background color of the tab being clicked.</li>
<li>change the background color of the main element based on the selected tab.</li>
</ul>
<p>
To test, click on a tab and then move your mouse around. For example, the third tab is clicked, the tab background color is switched to blue. Then hover the mouse over the third tab, the background color of the tab should be switch to light green and then back to blue after the mouse moves out.
</p>
<img src="menu_tab5.jpg">
</li>
</ul>
</main>
It's generally a good idea to keep CSS out of JavaScript completely if you can help it. A better strategy for solving the hover problem is to use the CSS pseudo selector :hover rather than coding the color changes in JavaScript. If you give all your tabs the same class, you only have to write the CSS once:
.tab {
background-color: yellow;
}
.tab:hover {
background-color: grey;
}
Once you've done that, you can also relegate the click styling to CSS by creating an event handler that adds and removes a special class each time a tab is clicked.
In the CSS file:
.tab.clicked {
background-color: blue;
}
And then in JavaScript, something like:
var tabs = document.getElementsByClassName('tab');
for (i = 0; i < tabs.length; i ++) {
tabs[i].onclick = function (ev) {
for (i = 0; i < tabs.length; i ++) {
tabs[i].classList.remove('clicked');
}
ev.currentTarget.classList.add('clicked');
};
}
I've created a JSFiddle to illustrate.
Try updating a Boolean variable.
var Ele = document.getElementById('default');
var clicked = false;
Ele.onclick = function(){
clicked = true;
// add additional functionality here
}
Ele.onmouseover = function(){
clicked = false;
// add additional functionality here
}
Ele.onmouseout = function(){
if(!clicked){
// add additional functionality here
}
}
I'm attempting to build an accordion menu using querySelectorAll() but unsure what the best method would be to check if the clicked list item's children (.toggleContent and .toggleIcon) belong to it's clicked parent toggle_li[i].
Correct me if I am wrong, but I assume that controlling this within the onclick function will be more flexible than impacting the toggleDataAttr function?
I'm still new to querySelector so any guidance is appreciated.
codepen: http://codepen.io/seejaeger/pen/qdqxGy
// data attribute toggle
var toggleDataAttr = function (toggleElem, opt1, opt2, dataAttr) {
//
// ? belongs to clicked element (parent toggle_li[i])?
//
var toggleElem = document.querySelector(toggleElem);
toggleElem.setAttribute(dataAttr,
toggleElem.getAttribute(dataAttr) === opt1 ? opt2 : opt1);
};
// declare toggle onclick element
var toggle_li = document.querySelectorAll('li');
// iterate query and listen for clicks
for (var i = 0; i < toggle_li.length; i++) {
toggle_li[i].onclick = function() {
//
// ? belongs to clicked element (parent toggle_li[i])?
//
toggleDataAttr('.toggleContent', 'closed', 'open', 'data-state');
toggleDataAttr('.toggleIcon', 'plus', 'minus', 'data-icon');
};
}
Here is what I think you should do:
Update your toggleDataAttr function to receive one more parameter parentElem.
Use this new parentElem for querySelector instead of document inside toggleDataAttr.
And then in your loop, pass this as parameter to be used as parentElem.
Snippet:
var toggleDataAttr = function(parentElem, toggleElem, opt1, opt2, dataAttr) {
var toggleElem = parentElem.querySelector(toggleElem);
toggleElem.setAttribute(dataAttr, toggleElem.getAttribute(dataAttr) === opt1 ? opt2 : opt1);
};
var toggle_li = document.querySelectorAll('li');
for (var i = 0; i < toggle_li.length; i++) {
toggle_li[i].onclick = function() {
toggleDataAttr(this, '.toggleContent', 'closed', 'open', 'data-state');
toggleDataAttr(this, '.toggleIcon', 'plus', 'minus', 'data-icon');
};
}
body {
background: #034;
opacity: 0.9;
font-family: sans-serif;
font-size: 24px;
font-weight: 300;
letter-spacing: 2px;
}
ul {
list-style: none;
padding: 0 24px;
width: 30%;
overflow: hidden;
color: #333;
}
li {
background: #eee;
padding: 0px;
border-bottom: 2px solid #aaa;
}
i {
font-style: normal;
}
.li-label {
padding: 18px;
}
.toggleContent {
padding: 18px 14px;
border-top: 2px solid #bac;
background: #334;
color: #eee;
}
.toggleContent[data-state=closed] {
display: none;
}
.toggleContent[data-state=open] {
display: block;
}
.toggleIcon[data-icon=plus]:after {
content: '+';
float: right;
}
.toggleIcon[data-icon=minus]:after {
content: '-';
float: right;
}
<ul>
<li>
<div class="li-label">
list item one <i class="toggleIcon" data-icon="plus"></i>
</div>
<div class="toggleContent" data-state="closed">toggle content one</div>
</li>
<li>
<div class="li-label">
list item two <i class="toggleIcon" data-icon="plus"></i>
</div>
<div class="toggleContent" data-state="closed">toggle content two</div>
</li>
<li>
<div class="li-label">
list item three <i class="toggleIcon" data-icon="plus"></i>
</div>
<div class="toggleContent" data-state="closed">toggle content three</div>
</li>
</ul>
Hope it helps.
Hello everyone,
I'm building a drop&drag inventory panel for my webgame, but I was unable to make it work with stackable elements. I have simplified the whole inventory so that it's less confusing.
FIrst off, let me explain how do I expect it to work:
Every .item element can be dropped on any free .inv_slot.
If I try to drop an .item element on another .item that does not contain class .stackable, it will simply activate the draggable's revert() function.
if I try to drop the .item element on an .item that does have the .stackable class,
it will only remove the clone/helper. (Later on I will addd an function that only increases the items stack size.)
Now what's wrong with the below example :
in case an .item accidentally dropped on border or between two .inv_slotslots, the Revert animation is not activated. It does work however, while dropping the .item element outside the #panel.
Also if I accidentally dropped an .item between two .inv_slot elements, it will behave as if the .item was dropped on a .stackable item. So it will remove the clone instead of reverting back to it's prev. position. (Most likely an issue with the selector in drop: method)
If I drop a .stackable item over another .stackable item, it does not refresh the cursor. It seems to be stuck in the drag mode which activates the "pointer" cursor.
Now here's the (partialy working) example:
$(document).ready(function() {
//var prev_el = '';
var item_isStackable = "";
$( ".item").draggable({
scroll: true,
revert: function(isValidEl)
{
if(isValidEl)
{
return false;
}else{
return true;
}
},
helper: "clone",
cursor: "pointer",
stack: false,
zIndex: 27,
drag: function(event, ui)
{
item_isStackable = $(this).hasClass("stackable");
},
});
$( ".inv_slot" ).droppable({
accept: ".item",
drop: function( event, ui ) {
var item = $(this).find(".item");
if(item.length == 0) /// See if there any items already in the currently selected inventory slot //
{
console.log("Inserting");
ui.draggable.detach().appendTo($(this)); // if none, insert the item into athe free slot ///
}
else if(item_isStackable == true && item.hasClass("stackable")){
console.log("Increasing ");
ui.draggable.detach(); /// If yes, just destroy the clone ///
}else{
console.log("reverting back");
// in case it's not .inv_slot , revert the item back to it's previous position //
ui.draggable.animate(ui.draggable.data().origPosition,"slow");
}
}
});
});
#panel
{
width: 340px;
height: 44px;
border: 1px solid #000;
padding: 4px;
}
.inv_slot
{
z-index: 22;
position: relative;
width: 40px;
height: 40px;
border: 1px solid red;
float: left;
}
.inv_slot .slot_pos{
z-index: 24;
position: absolute;
margin-left: 50%;
left: -4px; top: 2px;
}
.item
{
position: relative;
z-index: 25;
margin: 4px;
width: 30px;
height: 30px;
border: 1px solid blue;
}
.item.stackable
{
border: 1px solid green;
}
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.js"></script>
<div id="panel">
<div class="inv_slot">
<div class="item stackable" ></div>
<span class="slot_pos">0</span>
</div>
<div class="inv_slot">
<div class="item"> </div>
<span class="slot_pos">1</span>
</div>
<div class="inv_slot">
<div class="item stackable"> </div>
<span class="slot_pos">2</span>
</div>
<div class="inv_slot"><span class="slot_pos">3</span> </div>
<div class="inv_slot"><span class="slot_pos">4</span> </div>
<div class="inv_slot"><span class="slot_pos">5</span> </div>
<div class="inv_slot"><span class="slot_pos">6</span> </div>
<div class="inv_slot"><span class="slot_pos">7</span> </div>
</div>
I have spent couple of hours without any progress , so I'd really appreciate if someone could help me out with this one.
Thanks in advance,
Alex.
What's happening is that when you drag a box onto a border next to it, it deletes itself because it tries to stack itself. You need to change the second part of your if statement:
else if(item_isStackable == true && item.hasClass("stackable") && ui.draggable.filter(function() { var d = this; return item.filter(function() { return d == this; }).length > 0; }).length === 0)
To fix the cursor pointer problem:
.item
{
position: relative;
z-index: 25;
margin: 4px;
width: 30px;
height: 30px;
border: 1px solid blue;
cursor: default !important; /* Add this property. */
}
Fiddle.