|
/* By Bo Ericsson, https://www.linkedin.com/in/boeric00/ */ |
|
|
|
/* eslint-disable func-names, wrap-iife, no-plusplus, no-param-reassign, no-bitwise */ |
|
|
|
// Id generator (a demo of iife, generator function, and closure) |
|
// Outer iife to define the getId function, which returns an ever increasing integer |
|
// with each call |
|
const getId = (() => { |
|
// Inner iife to run the generator function which returns 'id', a generator object |
|
const id = (function* () { |
|
let i = 0; |
|
while (true) { |
|
yield i++; |
|
} |
|
})(); |
|
|
|
// The 'id' generator is locked inside the outer iife's closure |
|
return () => id.next().value; |
|
})(); |
|
|
|
// Returns an array of specified size with values incrementing from 0 |
|
function range(length) { |
|
const array = []; |
|
for (let i = 0; i < length; i++) { |
|
array.push(i); |
|
} |
|
return array; |
|
} |
|
|
|
// Zone colors (used to pick colors for the object generated in each zone) |
|
const zoneColors = ['blue', 'green', 'orange', 'darkred']; |
|
|
|
// Obtain references to the four zones |
|
const zones = document.querySelectorAll('.zone'); |
|
|
|
// Drag handlers |
|
let source; // Contains a reference to the item being dragged |
|
|
|
// Triggers when an item starts being dragged |
|
function ondragstart(evt) { |
|
// Add the 'dragging' class from the item being moved |
|
this.classList.add('dragging'); |
|
// Save a reference to the item being dragged |
|
source = this; |
|
evt.dataTransfer.effectAllowed = 'move'; |
|
} |
|
|
|
function ondragover(evt) { |
|
evt.preventDefault(); |
|
} |
|
|
|
function ondragenter(evt) { |
|
if (evt.target.classList.contains('zone')) { |
|
// Add the 'droppable' class of the zone element |
|
evt.target.classList.add('droppable'); |
|
} |
|
evt.preventDefault(); |
|
} |
|
|
|
function ondragleave(evt) { |
|
if (evt.target.classList.contains('zone')) { |
|
// Remove the 'droppable' class of the zone element |
|
evt.target.classList.remove('droppable'); |
|
} |
|
} |
|
|
|
function ondrop(evt) { |
|
// Remove the 'dragging' class from the item being moved |
|
source.classList.remove('dragging'); |
|
|
|
if (evt.target.classList.contains('zone')) { |
|
// Remove the 'droppable' class of the zone element |
|
evt.target.classList.remove('droppable'); |
|
// Move the item |
|
evt.target.appendChild(source); |
|
} |
|
evt.preventDefault(); |
|
} |
|
|
|
// Create items |
|
zones.forEach((zone, zoneIdx) => { |
|
// Add handlers for the zone's drag events |
|
zone.ondragenter = ondragenter; |
|
zone.ondragover = ondragover; |
|
zone.ondragleave = ondragleave; |
|
zone.ondrop = ondrop; |
|
|
|
// Determine items to create in this zone (min 1, max 7) |
|
const items = ~~(Math.random() * 7) + 1; |
|
|
|
range(items).forEach((idx) => { |
|
// Create the element |
|
const elem = document.createElement('div'); |
|
// Generate the text for the element |
|
const text = `${zoneIdx}-${idx}`; |
|
elem.innerHTML = text; |
|
// Determine type (circle or square randomly) |
|
const type = Math.random() > 0.5 ? 'circle' : 'square'; |
|
elem.className = `item ${type} color-${zoneColors[zoneIdx]}`; |
|
// Set the element id (not necessary but demos, when inspected, |
|
// that items actually move, not just the innerHTML) |
|
elem.id = getId(); |
|
// Enable dragging |
|
elem.draggable = true; |
|
// Handler to kickstart the dragging process |
|
elem.ondragstart = ondragstart; |
|
|
|
// Append the item to the zone |
|
zone.appendChild(elem); |
|
}); |
|
}); |