Highlight drop areas in HTML drag and drop - javascript

I'm building Yet Another Drag'n'Drop File Uploader. What I'd like to do is highlight the drop area on the page when a drag is started, so the user knows where to move the file to. The interface doesn't make it explicit straight away, which is desired in this case...
Highlighting the dropzone when the user is already over it is fine, but it's the time when the user is dragging but not yet in a droppable area that I'd like to be notified of.
I'm not able to use the dragstart event, since that fires on the HTML Element which is being dragged, and in this case, it's a file from the user's desktop or something. I also tried the following:
$(document.body).on('dragenter', changeTheCSSClass)
.on('dragleave', changeItBackAgain);
However, the enter and leave events fire for every single nested element that the cursor is over, so I get tons of events and the class switches back and forth continuously. Definitely not what I want there.
Any ideas?

As no one posted anything I am posting this, neither stable nor 100% working, but sometimes working.
changeback = 2;
changedback = true;
$(document)
.off('dragenter dragleave')
.on('dragenter', function (e) {
setTimeout(function () {
window.clearTimeout(changeback);
changeback = 0;
console.log('dragenter', e.target);
if (changedback) document.getElementById('nav-askquestion').style.color = '#bc0000';
changedback = false;
}, 10);
})
.on('dragleave', function (e) {
console.log('dragleave', e.target);
if (changeback == 0) {
changeback = window.setTimeout(function () {
console.log('changed back');
document.getElementById('nav-askquestion').style.color = '#FFFFFF';
changedback = true;
}, 15);
}
});
Applied to this page itself. Also you will need to cancel inhouse drags by setting some flag on dragstart.
the names dragenter and dragleave should be actually dragover and dragout it seems :)
How is it going at your end?

You could use angularJS:
<div align="center" class="alert alert-success ng-pristine ng-untouched ng-valid ng-empty"
ngf-select="onPrepareFile($file)" ngf-drop="onPrepareFile($file)" ng-model="vm.file"
name="inputFileStorage"
ngf-pattern="'image/*,application/pdf'"
ngf-accept="'image/*,application/pdf'"
ngf-max-size="10MB">
<a ng-show="!file"><strong>Select or Drop File Here</strong></a>
<a ng-show="file" class="ng-hide"><strong class="ng-binding"> has been Loaded</strong></a>
</div>
In the example I am limiting to a PDF with 10MB max size.
I use TS to code, sorry for the generated code, but can't find original TS...
this.onPrepareFile = function (file) {
if (file) {
var reader = new FileReader();
reader.onloadend = function () {
// yOUR FILE INFO IS IN: reader.result
};
reader.readAsDataURL(file);
}
};

Related

Undo .removeAtribute function

I'm looking for a solution to restore a removed attribute. I'm not an experienced programmer, so I'm not sure where to start when sharing my code, so I'll try to give some context below.
I have an image of a map that has several hidden overlays. These overlays are activated by a series of adjacent buttons.
Each of these buttons has a mouseover and mouseout event, which temporarily reveals the overlay. They also have an onclick event that permanently displays the overlay. I've used a .removeAtribute function to remove the mouseout event so that my overlay is permanent.
All other layers are still visible with the mouseover and mouseout events (so that you can make comparisons).
When I onclick another overlay button, it clears the previous one, however, now the mouseout event for the previously selected button is still inactive, so hovering over it causes the overlay to appear permanently.
How can I restore the mouseout event after I've removed it?
I have tried to use .setAttribute("onmouseout"), but I've had no luck in making that work.
Hopefully, this all makes some sense; I'll post some of my code below, which might help give further context.
function btn01On() {
document.getElementById("btn01").removeAttribute("onmouseout");
}
function btnClear() {
document.getElementById("btn01").setAttribute("onmouseout");
}
<button id="btn01" class="map-button map-button1"
onclick="MM_showHideLayers('InfoCurrentExc','','show','OverlayCurrentExc','','show');btn01On();" onmouseover="MM_showHideLayers('OverlayCurrentExc','','show')" onmouseout="MM_showHideLayers('OverlayCurrentExc','','show')">
Current Excavation
</button>
Usually setting up event handlers using onevent attribute, (although oldest method for event handling) is not the recommended way, See https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers#dom_event_handler_list.
I recommend using EventTarget.addEventListener and EventTarget.removeEventListener for your case. Try the code below
const mouseoutHandler = function() {
MM_showHideLayers('OverlayCurrentExc', '', 'show');
};
const mouseOverHandler = function() {
MM_showHideLayers('OverlayCurrentExc', '', 'show');
};
const button01 = document.getElementById("btn01");
button01.addEventListener("mouseover", mouseOverHandler);
function btn01On() {
if (!mouseoutListener)
button01.addEventListener("mouseout", mouseoutHandler);
}
function btnClear() {
if (mouseoutListener) {
button01.removeEventListener("mouseout", mouseoutListener);
mouseoutListener = null;
}
}
const clickHandler = function() {
MM_showHideLayers('InfoCurrentExc', '', 'show', 'OverlayCurrentExc', '', 'show');
btn01On();
}
button01.addEventListener("click", clickHandler);
I was lucky enough to find someone who had a fix for this problem. I'll share the code below for anyone who might land here with a similar request.
I don't fully understand how this code works so if someone has a good explanation feel free to share it.
// Remove mouse outs
function btn01On() {
document.getElementById("btn01").removeAttribute("onmouseout");
}
// keep mouse outs
const buttonIds = ["btn01"];
const mouseOuts = {};
buttonIds.forEach((id) => {
const el = document.getElementById(id);
if (el) {
mouseOuts[id] = el.getAttribute('onmouseout');
}
});
const restoreMouseOutEvent = () => {
buttonIds.forEach((id) => {
const el = document.getElementById(id);
if (el && mouseOuts[id]) {
el.setAttribute('onmouseout', mouseOuts[id]);
}
});
}

Multiple image upload feature with jquery - Preview Images won't disappear on click

I have a feature on a form that allows multiple uploads of images.
When you select the images you want to upload, it shows a small thumbnail of them. However, I thought it would be simple to make it so these images disappear when clicked on, but it's not working.
See below code. The preview image click function doesn't seem to be acknowledged and there's no console errors to help me out. When clicked, nothing happens.
$(function() {
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<img class="preview-img">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
};
$('#upload').on('change', function() {
imagesPreview(this, 'div.gallery');
});
$(".preview-img").click(function(){
$(this).hide();
});
});
The reader.onload function is exectued asynchronously. So the preview image click handler is registered before the images are available in the DOM. You can verify this by registering the click handler manually via the JavaScript console after all images were rendered.
You should use following code to set up the click event handler:
$(document).on("click", ".preview-img", function() {
$(this).hide();
});
This will still work after the DOM changed, since the handler is registered on the document instead of img-elements which do not exist yet.
Change this line :
$(".preview-img").click(function(){
$(this).hide();
});
To this :
$("body").on('click','.preview-img',function(){
$(this).hide();
});
This event listener will detect dynamically added elements

Jquery Droppable not working for file upload drag and drop, throws Error: Expected DOM element or View

I have been working on a https://github.com/wekan/ fork where I try to implement additional drag and drop functionality.
Out of the box wekan already came with labels/member drag and drop where the hover overlay is done via droppable hoverClass:
const selector = $cards.find(itemsSelector);
selector.droppable({
hoverClass: 'draggable-hover-card',
accept: '.js-member,.js-label',
'drop'(evt, ui) {
evt.preventDefault();
evt.stopPropagation();
const cardId = Blaze.getData(this)._id;
const card = Cards.findOne(cardId); //get current card I am hovering
//stuff
},
});
I added attachment drag and drop functionality, which won't work exactly like above code and produces the problem that I cannot add the hoverClass cleanly.
When I implement it as shown below the logic of doing addClass is sound but I get an error:
Exception from Tracker afterFlush function:
debug.js:41 Error: Expected DOM element or View
at Object.Blaze.getData (view.js:757)
at list.js:116
at Object.Tracker._runFlush (tracker.js:511)
at onGlobalMessage (setimmediate.js:102)
My code where I want to get an overlay/hover functionality for a single card that I hover over with a file:
const cardId = Blaze.getData(this)._id;
const card = Cards.findOne(cardId); //get current card I am hovering
selector.on({'': (evt) => { //.droppable as above does not work
evt.preventDefault(); //prevent default browser behavior
evt.stopPropagation();
},
dragover(e) { // pulled out of selector.on() to add/removeClass
e.preventDefault();
e.stopPropagation();
card.addClass('is-selected'); //add overlay on hover
},
dragenter(e) {
e.preventDefault();
e.stopPropagation();
},
dragleave(e) {
e.preventDefault();
e.stopPropagation();
card.removeClass('is-selected');
},
drop(evt, ui) {
card.removeClass('is-selected');
if(!ui){ // prevent complications with other drop events
evt.preventDefault();
evt.stopImmediatePropagation(); // prevent x -times actions
evt.target.files = evt.dataTransfer.files; // working file upload
_.each(evt.dataTransfer.files, (f) => {
const file = new FS.File(f);
file.boardId = card.boardId;
file.cardId = card._id;
Attachments.insert(file);
});}
},
});
When I move
const cardId = Blaze.getData(this)._id;
const card = Cards.findOne(cardId);
back into the drop event like in the first code block and try/test e.g. selector.addClass('') instead, the overlay works, but not correctly(selector basically returns the whole card list instead of a single card).
I am a novice currently in training and I just can't understand what error I am making.
Template.currentData() instead of Blaze.getData() does not work.
When I try selector.droppable() my dropped file isn't accepted and all the other events won't fire either.
After trying different varieties I am pretty sure that Blaze.getData() is the problem here. I don't know how to replace its function though.
The problem was a syntax and logic error on my side. While I knew that this in Blaze.getData() would point to the div I wanted, this.addClass() would throw an error. So I thought I'd need the whole Blaze-Block which then lead to the problem above.
Right Syntax:
$(this).addClass('');

Document.on.dragover gets broken by unrelated code

My javascript file is here. Basically my website is sort of a command prompt style website where I enter commands to do certain functions like file uploading. I also have a "drag & drop" upload function, which looks like this:
$(document).on('dragover', 'body', function(e) {
e.preventDefault();
$("#fileupload").addClass('ishovered');
$(".dragtext").show();
});
$(document).on('dragleave', 'body', function(e) {
$("#fileupload").removeClass('ishovered');
$(".dragtext").hide();
});
$(document).on('drop', 'body', function(e) {
$("#fileupload").removeClass('ishovered');
$(".dragtext").hide();
});
Now this works fine on the website load. But after I run this seemingly unrelated code:
[...]
} else if (value.match("^clear") || value.match("^cls")) {
if ($(".isup").attr("value") == "tr") {
$("#container").append("<span class='code'>" + value + "</span><span class='cmd-cont'>error: please answer yes/no first</span>");
updateScroll();
} else {
$("#container").html(""); /* This is what usually runs, and for some reason breaks the drag & drop upload */
}
}
[...]
function updateScroll() {
var element = document.getElementById("container");
element.scrollTop = element.scrollHeight;
}
For some reason running this code breaks the drag & drop upload, as in the website doesn't respond to files being hovered over after that code has been executed.
Live demo (you can recreate by trying to pull and file in to the website after load, then typing "cls" or "clear" and then try to drag a file in again)
$("#container").html(""); destroys the #fileupload form (because it's a child of #container)

How do I detect clicks when using YUI drag drop?

I'm using YUI to add drag drop support to a div. It also responds to clicks. Unfortunately, the click behavior takes effect even after a drag drop operation. Here's a code snippet:
// Create a DOM object for the group tag.
div = document.createElement('div');
div.className = 'group';
div.onclick = function() { beginEditName(); }
container.appendChild(div);
// Enable drag/drop for the group tag.
dragdrop = new YAHOO.util.DD(div);
dragdrop.scroll = false;
dragdrop.on('dragEvent', function(ev) { onDrag(ev); });
dragdrop.on('endDragEvent', function(ev) { onEndDrag(ev); });
dragdrop.setXConstraint(0,0);
Click is supposed to edit text, while drag drop is supposed to move the tag. However, the onclick event is firing so that text editing begins after the tag is moved.
I could code around the problem, but is there a more direct YUI way of differentiating a simple click from a drag drop?
Michael,
http://ericmiraglia.com/yui/demos/ddclick.php
View the source, and let me know (ericmiraglia at yahoo dot com) if you have any further questions on this.
Modification. I will copy the code here, this way if this guy take off the code from his server people will be able to check the source.
var beingDragged = false;
var dd = new YAHOO.util.DD("drag");
dd.subscribe("mouseDownEvent", function(e){
beingDragged = false;
});
dd.subscribe("startDragEvent", function(e) {
beingDragged = true;
});
dd.subscribe("mouseUpEvent", function(e) {
if(beingDragged) {
alert("dragged")
} else {
alert("clicked");
}
})

Categories

Resources