I'm working on a kind of puzzle game with HTML5 drag and drop api. I build a grid of 3 rows with 4 col per row giving me twelve squares. All but one of the squares contains some numbers from 1 to 11. The empty square is meant to be the dropzone i.e where any square can be dragged into.
When an element is dragged the dataTransfer.setData is set to the id of the element being dragged while ondrop event gets the data using dataTransfer.getData() result of which is used to query the dom for the element being dragged, then cloned after which the dropzone is now replaced with the cloned node. The source from which the dragged element is coming is also replaced with a dropzone.
var squares = document.querySelectorAll(".item");
var dropzone = document.querySelector(".col-lg-3.dropzone");
function startDrag(e){
e.dataTransfer.setData("text", e.target.id);
console.log(e.target)
}
function overDrag(e){
e.preventDefault();
e.target.classList.toggle("dropzone-active");
}
function leaveDrag(e){
e.preventDefault();
e.target.classList.toggle("dropzone-active");
}
function dropItem(e){
e.preventDefault();
var data = e.dataTransfer.getData("text");
var draggedElem = document.getElementById(data)
var clone = draggedElem.cloneNode(true);
var emptyzone = dropzone.cloneNode(false);
emptyzone.className = "col-lg-3 dropzone";
draggedElem.parentNode.replaceChild(emptyzone,draggedElem);
clone.id = data;
e.target.parentNode.replaceChild(clone, e.target);
}
for(var i=0; i<squares.length; i++){
squares[i].addEventListener("dragstart", startDrag, false);
}
dropzone.addEventListener("dragover", overDrag, false);
dropzone.addEventListener("dragleave", leaveDrag, false);
dropzone.addEventListener("drop", dropItem, false);
#gameZone{
width:800px;
height:500px;
background-color: rgba(0,0,0,.5);
margin: 0 auto;
padding:15px;
position:relative;
}
.item,
.dropzone{
background-color:red;
margin-right:10px;
margin-bottom:15px;
width:100px;
height:100px;
font-size: 2em;
color:#fff;
text-align:center;
}
.drag-active{
position:absolute;
z-index: 10;
}
.dropzone-active{
border:dashed 3px white;
}
.dropzone{
background-color:rgba(255,255,255,.6);
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<section id="gameZone">
<div class="row">
<div class="col-lg-3 item" id="one" draggable="true">1</div>
<div class="col-lg-3 item" id="three" draggable="true">3</div>
<div class="col-lg-3 item" id="two" draggable="true">2</div>
<div class="col-lg-3 item" id="four" draggable="true">4</div>
</div>
<div class="row">
<div class="col-lg-3 dropzone"></div>
<div class="col-lg-3 item" id="five" draggable="true">5</div>
<div class="col-lg-3 item" id="six" draggable="true">6</div>
<div class="col-lg-3 item" id="nine" draggable="true">9</div>
</div>
<div class="row">
<div class="col-lg-3 item" id="seven" draggable="true">7</div>
<div class="col-lg-3 item" id="eight" draggable="true">8</div>
<div class="col-lg-3 item"id="eleven" draggable="true">11</div>
<div class="col-lg-3 item" id="ten" draggable="true">10</div>
</div>
</section>
The problem now is that the first drag and drop action is successful, however, trying to drag a new element in the new dropzone doesn't work, it just doesn't recognize the ondragenter, ondragleave, ondragover and the drop events anymore.
You can create a function to set dropzone variable, attach dragover, dragleave, drop events to current dropzone element. Within drop event listener call function passing data to attach dragstart event to element currently having id data.
var squares = document.querySelectorAll(".item");
var dropzone;
//= document.querySelector(".col-lg-3.dropzone");
function startDrag(e) {
e.dataTransfer.setData("text", e.target.id);
}
function overDrag(e) {
e.preventDefault();
e.target.classList.toggle("dropzone-active");
}
function leaveDrag(e) {
e.preventDefault();
e.target.classList.toggle("dropzone-active");
}
function dropItem(e) {
e.preventDefault();
var data = e.dataTransfer.getData("text");
var draggedElem = document.getElementById(data)
var clone = draggedElem.cloneNode(true);
var emptyzone = dropzone.cloneNode(false);
emptyzone.className = "col-lg-3 dropzone";
draggedElem.parentNode.replaceChild(emptyzone, draggedElem);
clone.id = data;
e.target.parentNode.replaceChild(clone, e.target);
setResetDND(data);
}
for (var i = 0; i < squares.length; i++) {
squares[i].addEventListener("dragstart", startDrag, false);
}
function setResetDND(id) {
dropzone = document.querySelector(".col-lg-3.dropzone");
dropzone.addEventListener("dragover", overDrag, false);
dropzone.addEventListener("dragleave", leaveDrag, false);
dropzone.addEventListener("drop", dropItem, false);
if (id) {
document.getElementById(id)
.addEventListener("dragstart", startDrag)
}
}
setResetDND();
#gameZone {
width: 800px;
height: 500px;
background-color: rgba(0, 0, 0, .5);
margin: 0 auto;
padding: 15px;
position: relative;
}
.item,
.dropzone {
background-color: red;
margin-right: 10px;
margin-bottom: 15px;
width: 100px;
height: 100px;
font-size: 2em;
color: #fff;
text-align: center;
}
.drag-active {
position: absolute;
z-index: 10;
}
.dropzone-active {
border: dashed 3px white;
}
.dropzone {
background-color: rgba(255, 255, 255, .6);
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<section id="gameZone">
<div class="row">
<div class="col-lg-3 item" id="one" draggable="true">1</div>
<div class="col-lg-3 item" id="three" draggable="true">3</div>
<div class="col-lg-3 item" id="two" draggable="true">2</div>
<div class="col-lg-3 item" id="four" draggable="true">4</div>
</div>
<div class="row">
<div class="col-lg-3 dropzone"></div>
<div class="col-lg-3 item" id="five" draggable="true">5</div>
<div class="col-lg-3 item" id="six" draggable="true">6</div>
<div class="col-lg-3 item" id="nine" draggable="true">9</div>
</div>
<div class="row">
<div class="col-lg-3 item" id="seven" draggable="true">7</div>
<div class="col-lg-3 item" id="eight" draggable="true">8</div>
<div class="col-lg-3 item" id="eleven" draggable="true">11</div>
<div class="col-lg-3 item" id="ten" draggable="true">10</div>
</div>
</section>
Related
do you know how to keep selected a div in a different column, right every time I click on a div it remove the previous selected. I would like to keep the user choice selected on each different column : [https://codepen.io/dodgpine/pen/bGaqWVG][1]
const subTitleBuild = document.querySelectorAll(".sub-title-build");
const subTitleOs = document.querySelectorAll(".sub-title-os");
const subTitlePackage = document.querySelectorAll(".sub-title-package");
const subTitleLanguage = document.querySelectorAll(".sub-title-language");
const subTitleCuda = document.querySelectorAll(".sub-title-cuda");
const selections = [
subTitleBuild,
subTitleOs,
subTitlePackage,
subTitleLanguage,
subTitleCuda,
];
selections.forEach((selection) => {
selection.forEach((title) => {
title.addEventListener("click", () => {
removeSelectedClasses();
title.classList.add("selected");
});
});
});
function removeSelectedClasses() {
selections.forEach((selection) => {
selection.forEach((title) => {
console.log(title);
title.classList.remove("selected");
});
});
}
I've made two changes to your javascript, which I think achieve what you want (if I have understood correctly, you want a click to apply the class selected without affecting previously selected options, and, presumably, be able to remove earlier selections with another click on them).
Firstly, I commented out (removed) title.classList.remove("selected"); from your removeSelectedClasses() function, as this is what was clearing earlier selections.
Secondly, I modified, title.classList.add("selected"); in your event listeners to instead toggle the selected class on and off using: title.classList.toggle("selected");. This enables a single click to apply the selected class, while a second click on the same box removes it.
The snippet below works to show the effect.
I note you probably need column selections to be limited to a single choice, so you will have to fiddle with how the changes I suggested are applied. But the principle should help you do that.
const subTitleBuild = document.querySelectorAll(".sub-title-build");
const subTitleOs = document.querySelectorAll(".sub-title-os");
const subTitlePackage = document.querySelectorAll(".sub-title-package");
const subTitleLanguage = document.querySelectorAll(".sub-title-language");
const subTitleCuda = document.querySelectorAll(".sub-title-cuda");
const selections = [
subTitleBuild,
subTitleOs,
subTitlePackage,
subTitleLanguage,
subTitleCuda,
];
selections.forEach((selection) => {
selection.forEach((title) => {
title.addEventListener("click", () => {
removeSelectedClasses();
title.classList.toggle("selected");
});
});
});
function removeSelectedClasses() {
selections.forEach((selection) => {
selection.forEach((title) => {
console.log(title);
//title.classList.remove("selected");
});
});
}
.container-master {
width: 1200px;
margin: auto;
}
.container {
display: flex;
justify-content: space-between;
}
.column {
width: 170px;
}
.container-btn {
padding: 20px;
border: 2px solid black;
text-align: center;
margin-top: 10px;
}
.title {
margin-bottom: 30px;
background-color: #3e4652;
color: #ffffff;
}
.sub-title,
.sub-title-build {
cursor: pointer;
}
.row-cmd {
width: 1200px;
margin: 50px auto;
}
.container-btn-cmd {
padding: 20px;
border: 2px solid black;
text-align: center;
margin-top: 10px;
}
.command-container {
padding: 20px;
border: 2px solid black;
text-align: center;
margin-top: 10px;
}
.selected {
background-color: orangered;
color: #ffffff;
}
<div class="container-master">
<div class="container">
<div class="column ptbuild">
<div class="container-btn title">
<div class="btn">PyTorch Build</div>
</div>
<div class="container-btn sub-title-build" id="stable">
<div class="btn">Stable (1.11.0)</div>
</div>
<div class="container-btn sub-title-build" id="preview">
<div class="btn">Preview (Nightly)</div>
</div>
<div class="container-btn sub-title-build" id="lts">
<div class="btn">LTS (1.8.2)</div>
</div>
</div>
<div class="column os">
<div class="container-btn title">
<div class="btn">Your OS</div>
</div>
<div class="container-btn sub-title-os" id="linux">
<div class="btn">Linux</div>
</div>
<div class="container-btn sub-title-os" id="macos">
<div class="btn">Mac</div>
</div>
<div class="container-btn sub-title-os" id="windows">
<div class="btn">Windows</div>
</div>
</div>
<div class="column package">
<div class="container-btn title">
<div class="btn">Package</div>
</div>
<div class="container-btn sub-title-package" id="conda">
<div class="btn">Conda</div>
</div>
<div class="container-btn sub-title-package" id="pip">
<div class="btn">Pip</div>
</div>
<div class="container-btn sub-title-package" id="libtorch">
<div class="btn">LibTorch</div>
</div>
<div class="container-btn sub-title-package" id="source">
<div class="btn">Source</div>
</div>
</div>
<div class="column language">
<div class="container-btn title">
<div class="btn">Language</div>
</div>
<div class="container-btn sub-title-language" id="python">
<div class="btn">Python</div>
</div>
<div class="container-btn sub-title-language" id="cplusplus">
<div class="btn">C++ / Java</div>
</div>
</div>
<div class="column cuda">
<div class="container-btn title">
<div class="btn">Compute Platform</div>
</div>
<div
class="container-btn sub-title-cuda"
id="cuda10.2"
style="text-decoration: line-through"
>
<div class="btn">CUDA 10.2</div>
</div>
<div
class="container-btn sub-title-cuda"
id="cuda11.x"
style="text-decoration: line-through"
>
<div class="btn">CUDA 11.3</div>
</div>
<div
class="container-btn sub-title-cuda"
id="rocm4.x"
style="text-decoration: line-through"
>
<div class="btn">ROCM 4.2 (beta)</div>
</div>
<div class="container-btn sub-title-cuda" id="accnone">
<div class="btn">CPU</div>
</div>
</div>
</div>
<div class="row-cmd">
<div class="container-btn-cmd title">
<div class="option-text">Run this Command:</div>
</div>
<div class="command-container">
<div class="cmd-text" id="command">
<pre># MacOS Binaries dont support CUDA, install from source if CUDA is needed<br>conda install pytorch torchvision torchaudio -c pytorch</pre>
</div>
</div>
</div>
</div>
I am trying to find a more efficient way to write my code. I have a lesson where students can move sliders to view equivalent fractions. The code can be found on this codepen. I was hoping to use just one function so when any one of the three sliders are changed, the fraction will change also. I have tried,
const ranges = document.querySelectorAll(".range");
console.log("#"+ranges[0].id)
$("#"+ranges[0].id, "#"+ranges[1].id, "#"+ranges[2].id).change(function () {
console.log (ranges)
console.log (ranges[0].value)
console.log (ranges[0].id + "Bubbles")
setBubble(ranges[0].value * 1, ranges[0].id + "Bubble");
equivalentFraction (ranges[0].value, ranges[1].value, ranges[2].value);
});
setBubble(range, rangeBubble);
equivalentFraction (ranges[0].value, ranges[1].value, ranges[2].value);
However, the values in the bubbles do not show and the values in the fractions do not update. I am not sure what I am doing incorrectly and would appreciate your help.
Consider the following.
$(function() {
function setBubble(rangeEl, bubbleEl) {
var val = parseInt(rangeEl.value);
var min = rangeEl.min ? parseInt(rangeEl.min) : 0;
var max = rangeEl.max ? parseInt(rangeEl.max) : 100;
var result = ((val - min) * 100) / (max - min);
$(bubbleEl).html(rangeEl.value).css("left", "calc(" + result + "% + " + ((8 - result) * 0.15) + "px)");
}
function writeEquation(inpObj, targetObj) {
targetObj.html("");
var equation = $("<span>", {
class: "frac"
}).appendTo(targetObj);
$("<sup>").html(inpObj.numerator + " × " + inpObj.factor).appendTo(equation);
$("<span>").html("/").appendTo(equation);
$("<sub>").html(inpObj.denominator + " × " + inpObj.factor).appendTo(equation);
$("<span>", {
class: "eq"
}).html("=").appendTo(targetObj);
var result = $("<span>", {
class: "frac"
}).appendTo(targetObj);
$("<sup>").html(inpObj.numerator * inpObj.factor).appendTo(result);
$("<span>").html("/").appendTo(result);
$("<sub>").html(inpObj.denominator * inpObj.factor).appendTo(result);
}
function getValues() {
return {
numerator: parseInt($("#numeratorEquivalentSlider").val()),
denominator: parseInt($("#denominatorEquivalentSlider").val()),
factor: parseInt($("#equivalentSlider").val())
};
}
$("div[class*='EquivalentFractionSlider']").each(function(index, elem) {
setBubble($(".range", elem).get(0), $(".bubble", elem).get(0));
});
$(".range").on("input", function() {
setBubble($(this).get(0), $(this).parent().find(".bubble").get(0));
}).change(function() {
var inp = getValues();
if (inp.denominator == 0) {
$("#equivalentErrorStatement").html("Sorry, Denominator cannot be 0.").addClass("errorComment");
return false;
}
if (inp.factor == 0) {
$("#equivalentErrorStatement").html("Sorry, Factor cannot be 0. This would cause Denominitor to be 0.").addClass("errorComment");
return false;
}
writeEquation(inp, $("#equivalentFractionStatement"));
});
});
.bubble {
background: red;
color: white;
padding: 4px 12px;
margin: 0 auto 3rem;
position: absolute;
border-radius: 4px;
transform: translate(-50%, 70%)
}
.bubble::after {
content: "";
position: absolute;
width: 2px;
height: 2px;
background: red;
top: -1px;
left: 50%;
}
.emphasisBox {
border-radius: 25px;
border: 5px solid hsl(245, 98%, 19%);
background-color: hsl(210, 86%, 86%);
border-width: 5px;
box-shadow: 5px 10px hsl(205, 48%, 69%);
padding: 3rem;
}
/* the following rules are used to write fractions */
span.frac {
display: inline-block;
text-align: center;
}
span.frac>sup {
display: block;
border-bottom: 1px solid;
font: inherit;
}
span.frac>span {
display: none;
}
span.frac>sub {
display: block;
font: inherit;
}
span.eq {
vertical-align: 16px;
padding: .25em;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="row justify-content-center mt-3">
<div class="col-8 col-md-5">
<div class="row justify-content-center">
<div class="col-10 col-md-6">Numerator</div>
<div class="col-10 col-md-4">
<div class="numeratorEquivalentFractionSlider">
<input id="numeratorEquivalentSlider" type="range" class="range" min="-20" value="10" max="20">
<output id="numeratorEquivalentBubble" class="bubble"></output>
</div>
</div>
</div>
</div>
<div class="col-8 col-md-5">
<div class="row justify-content-center">
<div class="col-10 col-md-7">Denominator</div>
<div class="col-10 col-md-4">
<div class="denominatorEquivalentFractionSlider">
<input id="denominatorEquivalentSlider" type="range" class="range" min="-20" value="2" max="20">
<output id="denominatorEquivalentBubble" class="bubble"></output>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center mt-3">
<div class="col-8 col-md-5">
<div class="row justify-content-center">
<div class="col-10 col-md-4">Factor</div>
<div class="col-10 col-md-4">
<div class="EquivalentFractionSlider">
<input id="equivalentSlider" type="range" class="range" min="-20" value="5" max="20">
<output id="equivalentBubble" class="bubble"></output>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center align-items-center">
<!-- blank row to create space between card and banner -->
<section class="col"> </section>
</div>
<div class="row justify-content-center text-center">
<div id="equivalentErrorStatement" class="col-10 col-6"></div>
</div>
<div class="row justify-content-center my-3 text-center">
<div id="equivalentFractionStatement" class="col-8 col-md-4 emphasisBox"></div>
</div>
</div>
I have presented a jQuery answer, as I try not to mix. You cna see here, I have setup a few more functions:
setBubble()
getValues()
writeEquation()
setBubble() accepts a Range Element and a target Bubble element. I suspect you will have the one bubble element, yet if you ever have more in the future, this is then can be carried over. It will gather the value from the range and set it in the bubble and then position the bubble on the screen.
getValues() will collect the values from each of the sliders and place them into a single Object that has numerator, denominator and factor elements. It does not do any error checking, it just gets the values.
writeEquation() accepts an Object that should contain numerator, denominator and factor and writes the equation to the specific target jQuery Object. It does not perform any error checking.
You will also see that once the User has selected a value, we perform checks to see if these would cause an issue issue. If the values would cause an issue, a Error is shown and the function is exited (return false;). Otherwise the values are used and written out as the equation.
I have got a drag and drop functionality working with dragula so that it creates elements to drop the element into as a child. The idea is that you can make any element become a container to hold child items.
The problem I am having is that I don't want the drop locations to be visible until I have hovered my draggable element over. When dragging an element around the page, it renders all the parent containers - but i only really want that to appear when hovering over a spot where it can be created. Not so much of a problem with a small amount of items but when you got 100+ items its causes the page to grow and is quite jarring.
Below is what I have got so far. Any help is greatly appreciated!
var drake;
function setupDragula() {
var containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));
var item = Array.prototype.slice.call(document.querySelectorAll(".js-structure-item"));
var opts = {
allowNestedContainers: true
};
opts = {
accepts: function(el, target, source, sibling) {
// prevent dragged containers from trying to drop inside itself
return !contains(el, target);
}
};
drake = dragula(
containers,
opts
).on('drag', function(el) {
prepareEmptyDropZones();
el.classList.remove('ex-moved');
}).on('drop', function(el, container, source) {
el.classList.add('ex-moved');
removeEmptyDropZones();
}).on('cancel', function(el, container, source) {
removeEmptyDropZones();
}).on('over', function(el, container) {
container.classList.add('editing');
el.classList.add('el-over');
}).on('out', function(el, container) {
container.classList.remove('editing');
el.classList.remove('el-over');
});
}
function contains(a, b) {
return a.contains ?
a != b && a.contains(b) :
!!(a.compareDocumentPosition(b) & 16);
}
function prepareEmptyDropZones() {
var item = querySelectorAllArray(".js-structure-item");
item.forEach(function(el) {
var firstParent = el.querySelector('.js-structure-parent');
if (firstParent === null) {
//el.classList.add('empty');
var emptyParent = document.createElement('div');
emptyParent.className = "js-structure-parent";
//emptyParent.classList.add('empty-drop-zone');
el.appendChild(emptyParent);
} else {
el.classList.remove('empty');
}
});
resetContainers();
}
function removeEmptyDropZones() {
var dropZones = querySelectorAllArray(".js-structure-parent");
dropZones.forEach(function(dropZone) {
if (dropZone.children.length == 0) {
dropZone.remove();
}
});
}
function resetContainers() {
drake.containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));
}
function querySelectorAllArray(selector) {
return Array.prototype.slice.call(document.querySelectorAll(selector))
}
document.addEventListener("DOMContentLoaded", function(event) {
setupDragula();
});
.js-structure-item {
cursor: move;
}
.js-structure-item .container {
margin-bottom: 10px;
}
/*parent*/
.js-structure-parent {
padding: 0px 0px 0px 30px;
/*border: 1px solid red;
position: relative;*/
}
.js-structure-parent:empty,
.empty-drop-zone {
min-height: 20px;
border: 1px dashed #ccc;
}
.el-over {
background-color: green;
}
.js-structure-item.empty {
color: #666;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
File Folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
File 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 4
</div>
</div>
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image Folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
Image file 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 4
</div>
</div>
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
Document file 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 4
</div>
</div>
</div>
</div>
</div>
var drake;
function setupDragula() {
var containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));
var item = Array.prototype.slice.call(document.querySelectorAll(".js-structure-item"));
var opts = {
allowNestedContainers: true
};
opts = {
accepts: function(el, target, source, sibling) {
// prevent dragged containers from trying to drop inside itself
return !contains(el, target);
}
};
drake = dragula(
containers,
opts
).on('drag', function(el) {
prepareEmptyDropZones();
el.classList.remove('ex-moved');
}).on('drop', function(el, container, source) {
el.classList.add('ex-moved');
removeEmptyDropZones();
}).on('cancel', function(el, container, source) {
removeEmptyDropZones();
}).on('over', function(el, container) {
container.classList.add('editing');
el.classList.add('el-over');
}).on('out', function(el, container) {
container.classList.remove('editing');
el.classList.remove('el-over');
});
}
function contains(a, b) {
return a.contains ?
a != b && a.contains(b) :
!!(a.compareDocumentPosition(b) & 16);
}
function prepareEmptyDropZones() {
var item = querySelectorAllArray(".js-structure-item");
item.forEach(function(el) {
var firstParent = el.querySelector('.js-structure-parent');
if (firstParent === null) {
//el.classList.add('empty');
var emptyParent = document.createElement('div');
emptyParent.className = "js-structure-parent";
//emptyParent.classList.add('empty-drop-zone');
el.appendChild(emptyParent);
} else {
el.classList.remove('empty');
}
});
resetContainers();
}
function removeEmptyDropZones() {
var dropZones = querySelectorAllArray(".js-structure-parent");
dropZones.forEach(function(dropZone) {
if (dropZone.children.length == 0) {
dropZone.remove();
}
});
}
function resetContainers() {
drake.containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));
}
function querySelectorAllArray(selector) {
return Array.prototype.slice.call(document.querySelectorAll(selector))
}
document.addEventListener("DOMContentLoaded", function(event) {
setupDragula();
});
.js-structure-item {
cursor: move;
}
.js-structure-item .container {
margin-bottom: 10px;
}
/*parent*/
.js-structure-parent {
padding: 0px 0px 0px 30px;
/*border: 1px solid red;
position: relative;*/
}
.el-over {
background-color: green;
}
.js-structure-item.empty {
color: #666;
}
.gu-mirror {
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 0.8;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.js-structure-parent:empty,
.empty-drop-zone {
min-height: 6px;
}
.gu-transit {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
File Folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
File 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 4
</div>
</div>
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image Folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
Image file 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 4
</div>
</div>
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
Document file 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 4
</div>
</div>
</div>
</div>
</div>
Try this :::
var drake;
function setupDragula() {
var containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));
var item = Array.prototype.slice.call(document.querySelectorAll(".js-structure-item"));
var opts = {
allowNestedContainers: true
};
opts = {
accepts: function(el, target, source, sibling) {
// prevent dragged containers from trying to drop inside itself
return !contains(el, target);
}
};
drake = dragula(
containers,
opts
).on('drag', function(el) {
prepareEmptyDropZones();
el.classList.remove('ex-moved');
}).on('drop', function(el, container, source) {
el.classList.add('ex-moved');
removeEmptyDropZones();
}).on('cancel', function(el, container, source) {
removeEmptyDropZones();
}).on('over', function(el, container) {
container.classList.add('editing');
el.classList.add('el-over');
}).on('out', function(el, container) {
container.classList.remove('editing');
el.classList.remove('el-over');
});
}
function contains(a, b) {
return a.contains ?
a != b && a.contains(b) :
!!(a.compareDocumentPosition(b) & 16);
}
function prepareEmptyDropZones() {
var item = querySelectorAllArray(".js-structure-item");
item.forEach(function(el) {
var firstParent = el.querySelector('.js-structure-parent');
if (firstParent === null) {
//el.classList.add('empty');
var emptyParent = document.createElement('div');
emptyParent.className = "js-structure-parent";
//emptyParent.classList.add('empty-drop-zone');
el.appendChild(emptyParent);
} else {
el.classList.remove('empty');
}
});
resetContainers();
}
function removeEmptyDropZones() {
var dropZones = querySelectorAllArray(".js-structure-parent");
dropZones.forEach(function(dropZone) {
if (dropZone.children.length == 0) {
dropZone.remove();
}
});
}
function resetContainers() {
drake.containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));
}
function querySelectorAllArray(selector) {
return Array.prototype.slice.call(document.querySelectorAll(selector))
}
document.addEventListener("DOMContentLoaded", function(event) {
setupDragula();
});
.js-structure-item {
cursor: move;
}
.js-structure-item .container {
margin-bottom: 10px;
}
/*parent*/
.js-structure-parent {
padding: 0px 0px 0px 30px;
/*border: 1px solid red;
position: relative;*/
}
.el-over {
background-color: green;
}
.js-structure-item.empty {
color: #666;
}
.gu-mirror {
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 0.8;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
File Folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
File 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
File 4
</div>
</div>
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image Folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
Image file 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
Image file 4
</div>
</div>
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document folder
</div>
<div class="js-structure-parent">
<div class="js-structure-item">
<div class="container">
Document file 1
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 2
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 3
</div>
</div>
<div class="js-structure-item">
<div class="container">
Document file 4
</div>
</div>
</div>
</div>
</div>
I have a page that generates some draggable elements.
However I noticed that on firefox I cannot get them to drag while on chrome I can.To create a new element i press the create item button.Here is my code
/*
* #param event A jquery event that occurs when an object is being dragged
*/
function dragStartHandler(event){
//e refers to a jQuery object
//that does not have dataTransfer property
//so we have to refer to the original javascript event
var originalEvent = event.originalEvent;
var currentElement = originalEvent.target;
console.log("Hack it");
console.log($(currentElement).data());
//We want to store the data-task-id of the object that is being dragged
originalEvent.dataTransfer.setData("text",$(currentElement).data("task-id"));
originalEvent.dataTransfer.effectAllowed = "move";
}
$(document).ready(function(){
//When a new task/item is creatted it is assigned a unique data attribute which is the task index
var taskIndex = 0;
$(".text-info").addClass("text-center");
$(".createTask").addClass("btn-block").on("click",function(){
//Find the category whict this button belongs to
var currentCategory = $(this).parent(".box");
var categoryId = currentCategory.data("category");
//Create a new task
var task = $("<div class='list-group-item droppable' draggable='true' data-task-id="+taskIndex+"></div>");
//Assign a data-task-id attribute and set its text
task.text("Data id = "+taskIndex);
taskIndex++;
task.appendTo($(this).prev(".dropTarget"));
});
$(".droppable").on("dragstart",dragStartHandler);
$(".dropTarget").on("dragenter",function(event){
event.preventDefault();
event.stopPropagation();
$(this).addClass("highlighted-box");
}).on("dragover",false)
.on("drop",function(event){
event.preventDefault();
event.stopPropagation();
var originalEvent = event.originalEvent;
//Retrieve the data-task-id we stored in the event
var taskId = originalEvent.dataTransfer.getData("text");
console.log(taskId);
//The object that will be moved is determined by the id we stored on the event parameter
var objectToMove =$("body").find(`[data-task-id='${taskId}']`);
console.log(objectToMove);
var category = $(this).parent(".box").data("category");
objectToMove.data("category-group",category);
//Remove the square object from its previous position
//and append it to the current dropTarget
$(objectToMove).appendTo(this);
return false;
});
});
.highlighted-box {
box-shadow: 0 0 4px 4px #EBE311;
}
.dropTarget {
height: 10em;
width: 10em;
/* border:2px solid; */
margin: auto;
}
.dropTarget .droppable{
margin: auto;
position: relative;
top: 20%;
}
.droppable {
background-color: dodgerblue;
/* height: 6em;
border-radius: 5px; */
/* box-shadow: 0 0 5px 5px #3D0404; */
/* width: 6em; */
}
#square2{
background-color: red;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<body>
<div class="jumbotron intro text-center">
<h1>Drag and drop demo</h1>
</div>
<div class="row">
<div class="col-md-3 box" data-category="0">
<h1 class="text-info">Ideas</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
<div class="col-md-3 box" data-category="1">
<h1 class="text-info">Wornking on</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
<div class="col-md-3 box" data-category="2">
<h1 class="text-info">Completed</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
<div class="col-md-3 box" data-category="3">
<h1 class="text-info">Accepted</h1>
<div class="dropTarget list-group">
</div>
<div class="btn btn-info createTask">
Create item
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-6">
<div id="square" draggable="true" data-index = "0" class="droppable list-group-item"></div>
</div>
<div class="col-md-6">
<div id="square2" class="droppable list-group-item" draggable="true" data-index="1"></div>
</div>
</div>
</div>
</body>
The problem with my code was the event delegation.
To fix it I did the following:
$("body").on("dragstart",".droppable",dragStartHandler);
Here you can find more more here
I have a page that when loaded displays this:
The HTML for this is as follows (the below is built within a foreach statement in the view as I'm using MVC 5)
<div class="boxTop"></div>
<div id="panel1" class="box">
<div class="row col-xs-12 margin0" style="margin-left:-8%">
<div class="col-md-6 col-xs-6">
<img data-name="blackcherry" alt="cherries.png" data-id="1" src="/Content/Images/FlavourLab/cherries.png">
</div>
<div class="col-md-6 col-xs-6">
<img data-name="coconut" alt="coconut" data-id="2" src="/Content/Images/FlavourLab/coconut.png">
</div>
</div>
<div class="clearfix"></div>
<div class="marginBottom10 visible-xs-block"></div>
<div class="row col-xs-12 margin0" style="margin-left:-8%">
<div class="col-md-6 col-xs-6">
<img data-name="mango" alt="mango" data-id="3" src="/Content/Images/FlavourLab/mango.png">
</div>
<div class="col-md-6 col-xs-6">
<img data-name="strawberries" alt="strawberries" data-id="4" src="/Content/Images/FlavourLab/strawberries.png">
</div>
</div>
<div class="clearfix"></div>
<div class="marginBottom10 visible-xs-block"></div>
</div>
<div class="boxBtm"></div>
What I'm trying to do is when one of those images are clicked I need to place the following css circle on top of it to show its been selected the CSS for the circle is like this
#circle1 {
background: none repeat scroll 0 0 green;
height: 80px;
width: 80px;
opacity: 0.4;
}
.circle {
border-radius: 50%;
display: inline-block;
margin-right: 20px;
}
Which gets rendered like this:
<div class="circle" id="circle"></div>
My current jQuery is like this:
$("#panel1 row img").click(function () {
var id = $(this).attr("data-id").val();
alert(id);
});
2 Things:
The jQuery does not fire, I'm unsure why. Can someone explain this?
How would I add the above CSS Circle to the clicked image?
This #panel1 row img is a wrong selector, change it to #panel1 .row img - note class name selector .row
Change your click handler to do this $(this).toggleClass("circle");
.circle class shall look like:
.circle {
border-radius: 50%;
border: 2px solid red;
overflow: visible;
}
Try something like this (the "row" class missed the dot in the selector)
$("#panel1 .row img").click(function () {
$(this).addClass('circle');
});