I have multiple dropzones for uploading files on a webpage
How to highlight all dropzone elements as soon as a file is dragged into the browser, so the user knows where to drop the file? And when a file is dragged over one of the dropzones I need to add an additional class to indicate the user can release the file
update
kurideja pointed me in the right direction to Dragster
https://github.com/bensmithett/dragster
Now it almost works :)
If you drag over one dropzone and drag back out without releasing the file all dropzones are hidden
http://jsfiddle.net/L7v2f96z/9/
html
<div class="dropzone"></div>
<div class="dropzone"></div>
javascript
// Add/remove class when file is dragged over the dropzone. Hover effect
$('.dropzone').dragster({
enter : function(){
$(this).show().addClass('hover');
},
leave : function(){
$(this).hide().removeClass('hover');
}
});
// Show/hide dropzones until a file is dragged into the browser window. Hide dropzones after file is dropped or dragging is stopped
var w = $(window).dragster({
enter : function(){
$('.dropzone').show();
},
leave : function(){
$('.dropzone').hide();
}
})
// Prevent defaults (file is openened in the browser) if user drops file outside a dropzone
.on('dragover', function(e){
e.preventDefault();
})
.on('drop', function(e){
e.preventDefault();
w.trigger('dragleave');
});
css
.dropzone {
width:200px;
height:200px;
background:#fff;
display:none;
border:2px dashed rgba(0,0,0,0.5);
box-shadow:0 2px 5px rgba(0,0,0,0.1), inset 0 0 40px rgba(0,0,0,0.1);
border-radius:2px;
margin:10px;
}
.dropzone.hover {
background:#e3e3e3;
}
Main problem was: after leaving the dropzone area, dragster triggered leave twice, both on .dropzone and window. Simply adding e.stopPropagation() solves the problem. There are also few more fixes (removed show() and hide() inside dropzone dragster). Your code on Fiddle and also below:
// Add/remove class when file is dragged over the dropzone. Hover effect
$('.dropzone').dragster({
enter: function() {
$(this).addClass('hover');
},
leave: function(e) {
e.stopPropagation(); //-- Critical point
$(this).removeClass('hover');
}
});
// Show/hide dropzones until a file is dragged into the browser window. Hide dropzones after file is dropped or dragging is stopped
var w = $(window).dragster({
enter: function() {
$('.dropzone').show();
},
leave: function() {
$('.dropzone').hide();
}
})
// Prevent defaults (file is openened in the browser) if user drop file outside a dropzone
.on('dragover', function(e) {
e.preventDefault();
})
.on('drop', function (e) {
e.preventDefault();
w.trigger('dragleave');
});
You can use e.originalEvent.pageXand e.originalEvent.pageY on dragover and check if its in a range of the box. For this example I have copied the dropzone and I know the width and height of the div so I could hardcode the condition. You will have to come up with a way to store the position(top and left) of the dropzone areas and use that for comparison.
var drag_timer;
$(document).on('dragover', function (e) {
var dt = e.originalEvent.dataTransfer;
if (dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))) {
if (e.originalEvent.pageX <= 200 && e.originalEvent.pageY <= 200) {
$('.dropzone').removeClass('highlight');
$('.dropzone:eq(0)').addClass('highlight');
} else if (e.originalEvent.pageX <= 400 && e.originalEvent.pageY <= 400) {
$('.dropzone').removeClass('highlight');
$('.dropzone:eq(1)').addClass('highlight');
} else {
$('.dropzone').removeClass('highlight');
}
$('.dropzone').show();
window.clearTimeout(drag_timer);
}
})
.on('dragleave', function (e) {
drag_timer = window.setTimeout(function () {
$('.dropzone').hide();
}, 50);
});
Demo Fiddle
You can use the target member of the event to get the proper element:
var drag_timer;
$(document).on('dragover', function(e){
var dt = e.originalEvent.dataTransfer;
if(dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))){
$('.dropzone').show();
window.clearTimeout(drag_timer);
}
})
.on('dragleave', function(e){
drag_timer = window.setTimeout(function(){
$('.dropzone').hide();
}, 50);
});
$('.dropzone')
.on('dragenter', function(e){
$(e.originalEvent.target).addClass('highlight');
})
.on('dragleave', function(e){
$(e.originalEvent.target).removeClass('highlight');
});
Fiddle: http://jsfiddle.net/mzcqxfq3/
Some drag events are fired on EACH element, so basically there is not a one continuous drag, but a sequence of drags over all elements below the mouse.
Just use this plugin: http://javascript.hew.io/bensmithett/dragster
In my case I wanted to change the style of the class the moment I put
a new file and when the dropzone was filled, I did the following:
.dz-drag-hover , .dz-started {
border: 2px solid #0CB598;
}
My solution would be very similar to your aproach.
When a file is draged into the window, add a css-class to the element which contains all drop-zones (body if neccessary). Then you can style your drop-zones on drag accordingly:
$(document).on('dragover', function(e){
var dt = e.originalEvent.dataTransfer;
if(dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))){
$('body').addClass('dragging'); // Adding a class to the body
}
})
.on('dragleave', function(e){
$('body').removeClass('dragging')
});
The css would be:
/* style the drop-zone */
.dropzone {
height:200px;
width:200px;
display:none;
border:2px dashed black;
}
/* show the dropzone when file is dragged into window */
body.dragging .dropzone{
display:block;
}
/* highlight box when hovered but only when file is dragged */
body.dragging .dropzone:hover{
background:gray;
}
If this isn't what you wanted pleas tell me in a comment ;)
EDIT
Of course you have to remove the class when the file is droped
$(document).on('drop', function(event) {
$('body').removeClass('dragging');
}
IE11 bug caused by dt.types.indexOf, e.originalEvent.dataTransfer.types is a DOMStringList object in ie.
So you shoud use dt.types.contains instead ofdt.types.indexOf.
The following works:
var drag_timer;
$(document).on('dragover', function(e) {
var dt = e.originalEvent.dataTransfer;
if (dt.types != null &&
(dt.types.indexOf ? dt.types.indexOf('Files') != -1 :
(dt.types.contains('Files') ||
dt.types.contains('application/x-moz-file')))) {
$('.dropzone').show();
window.clearTimeout(drag_timer);
}
})
.on('dragleave', function(e) {
drag_timer = window.setTimeout(function() {
$('.dropzone').hide();
}, 25);
});
.dropzone {
height: 100px;
width: 100px;
background: red;
display: none;
}
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<div class="dropzone"></div>
Related
I am using wordpress and my content looks like this
<div class="image-wrap"><a class="ajax-load-next" href="http://linktopage.com/2/"><img src="blah1.jpg" alt=""/></a></div><!--nextpage-->
<div class="image-wrap"><a class="ajax-load-next" href="http://linktopage.com/3/"><img src="blahab.jpg" alt=""/></a></div><!--nextpage-->
<div class="image-wrap"><a class="ajax-load-next" href="http://linktopage.com/4/"><img src="blahco.jpg" alt=""/></a></div><!--nextpage-->
<div class="image-wrap"><a class="ajax-load-next" href="http://linktopage.com/5/"><img src="blahneat.jpg" alt=""/></a></div>
I have a custom javascript that loads the next image when the user clicks on the image. Now I want to add left & right keyboard arrow navigation to this script and I don't know how I can I implement to it since I'm not familiar with javascript.
$('body').on('click', '.image-wrap', function(e) { // listen for 'click' on our '.image-wrap' element
e.preventDefault(); // Prevents default behavior on the a element
$.ajax({
url: $(this).find( 'a' ).attr( 'href' ), // the url we are fetching by ajax
success: function (response) {
newImg = $(response).find('.image-wrap').html(), // get the new href link and image from the response, contained in div.image-wrap
$( 'div.image-wrap' ).html( newImg ); // set the new html for our inner div
}
}).fail(function (data) {
if ( window.console && window.console.log ) {
console.log( data ); // log failure to console
}
});
});
EDIT:
By pressing the right arrow key I want it to click the ajax link that is inside image-wrap div which should load the next image. If pressing the left arrow key it should go back to the previous image. Any idea how to do this?
You can use mousetrap.
function GoToLocation(url)
{
window.location = url;
}
Mousetrap.bind("right", function() {
document.getElementById('next-image').click();
});
<script src="https://craig.global.ssl.fastly.net/js/rainbow-custom.min.js?39e99"></script>
<script src="https://craig.global.ssl.fastly.net/js/mousetrap/mousetrap.js?bc893"></script>
<div class="image-wrap"><a id="next-image" class="ajax-load-next" href="http://linktopage.com/2/"><img src="blah1.jpg" alt=""/></a></div><!--nextpage-->
<div class="image-wrap"><a id="next-image" class="ajax-load-next" href="http://linktopage.com/3/"><img src="blahab.jpg" alt=""/></a></div><!--nextpage-->
<div class="image-wrap"><a id="next-image" class="ajax-load-next" href="http://linktopage.com/4/"><img src="blahco.jpg" alt=""/></a></div><!--nextpage-->
<div class="image-wrap"><a id="next-image" class="ajax-load-next" href="http://linktopage.com/5/"><img src="blahneat.jpg" alt=""/></a></div>
if you are use attachment.php or image.php based gallery. you can also use this : Wordpress Attachment Page Navigate with Keyboard
You need to bind a handler to the document keyup event, and test the key code for the event. A handy reference to key codes: https://css-tricks.com/snippets/javascript/javascript-keycodes/
Below is an example. When you run it, click in the output panel to give it focus before testing the keys.
var selectedIndex = 0;
var elements = $('.navigable').toArray();
var maxElements = elements.length;
function nextSelection() {
selectedIndex++;
if(selectedIndex >= maxElements) {
selectedIndex = 0;
}
selectElement();
}
function prevSelection() {
selectedIndex--;
if(selectedIndex < 0) {
selectedIndex = maxElements - 1;
}
selectElement();
}
function selectElement() {
$('.navigable').removeClass('selected');
$(elements[selectedIndex]).addClass('selected');
}
handleKeyUp = function(ev) {
if(ev.keyCode == 37) { // left arrow key
prevSelection();
}
if(ev.keyCode == 39) { // right arrow key
nextSelection();
}
if(ev.keyCode == 27) { // escape key
$(document).off('keyup', handleKeyUp);
}
}
$(document).on('keyup', handleKeyUp);
selectElement();
div {
padding: 30px;
margin: 10px;
border: 1px solid #aaa;
background: #fee;
display: inline-block;
}
div.selected {
background: #faa;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="navigable">1</div>
<div class="navigable">2</div>
<div class="navigable">3</div>
<br>
<br>
<p> Click in this panel to give it focus. Use arrow keys to navigate between divs. Press `ESC` to disable `keyup` handler.</p>
I have created two function on Enter Key press
to hide show dive on Enter key press
to auto resize textarea Height on Enter when it reached to end.
Here is the fiddle : http://jsfiddle.net/rz3f3gng/2/
$('.one').hide();
$(function() {
//hide show dive on enter press and on other keys hide div
$('#mainContent').on('keypress', function(e) {
if (e.which == 13) {
e.preventDefault();
$('.one').show();
} else {
$('.one').hide();
}
});
function TextareaAuto(o) {
o.style.height = "200px";
o.style.height = (2 + o.scrollHeight) + "px";
}
});
.one {
width: 100px;
height: 30px;
background: red;
}
textarea {
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="one">
</div>
<textarea id="mainContent" onkeydown="TextareaAuto(this)" style="overflow:hidden">
</textarea>
Only One function seems to work at time, either Hide show div or auto size textarea.
You should never mix inline event handlers with jQuery handlers. Just use two jQuery handlers or call the function from the existing handler:
e.g.
$('#mainContent').on('keypress', function(e){
if (e.which == 13) {
e.preventDefault();
$('.one').show();
}
else{
$('.one').hide();
}
TextareaAuto(this);
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/rz3f3gng/3/
Update
As you still want the Enter to work (see comment below), just get rid of your e.preventDefault()
e.g.
$('#mainContent').on('keypress', function(e){
if (e.which == 13) {
$('.one').show();
}
else{
$('.one').hide();
}
TextareaAuto(this);
});
http://jsfiddle.net/TrueBlueAussie/rz3f3gng/4/
Which now means it can be reduced using toggle() to
$('#mainContent').on('keypress', function(e){
$('.one').toggle(e.which == 13);
TextareaAuto(this);
});
http://jsfiddle.net/TrueBlueAussie/rz3f3gng/5/
I know there are lots of ways to detect the click outside of an element. Mostly all of them use event.stopPropagation. Since event.stopPropagation will break other stuff, I was wondering if there is another way to achieve the same effect. I created a simple test for this:
HTML:
<div class="click">Click me</div>
Javascript:
$(function() {
var $click = $('.click'),
$html = $('html');
$click.on( 'click', function( e ) {
$click.addClass('is-clicked').text('Click outside');
// Wait for click outside
$html.on( 'click', clickOutside );
// Is there any other way except using .stopPropagation / return false
event.stopPropagation();
});
function clickOutside( e ) {
if ( $click.has( e.target ).length === 0 ) {
$click.removeClass('is-clicked').text('Click me');
// Remove event listener
$html.off( 'click', clickOutside );
}
}
});
http://jsfiddle.net/8p4jhvqn/
This works, but only because i stop the bubbling with event.stopPropagation();. How can i get rid of event.stopPropagation(); in this case?
It can be done in a simpler way, can't it be? Why complicate things when something as simple as below could work.
$(document).click(function(e){
var elm = $('.click');
if(elm[0] == e.target){
elm.addClass("is-clicked").text("click outside");
} else { elm.removeClass("is-clicked").text("click inside"); }
});
DEMO
You could do something like this to achieve the same effect
$(document).on("click", function(e){
var target = $(e.target);
if(target.hasClass("click")){
$click.addClass('is-clicked').text('Click outside');
}else{
$click.removeClass('is-clicked').text('Click me');
}
});
HTML code:
<div id="box" style="width:100px; height:100px; border:1px solid #000000; background-color:#00ff00;"></div>
JavaScript code:
function Init()
{
$(document).click(function(event){
if(event.target.id == "box")
{
$(event.target).css("backgroundColor", "#ff0000");
}
else
{
$("#box").css("backgroundColor", "#00ff00");
}
})
}
$(document).ready(Init);
If the element in question has child elements, then those may show up as e.target, and you can't simply compare it to your element.
In that case, capture the event in both the event and in the document, and detect events which only occurred on the document, for example by recording and comparing e.target:
var lastTarget = undefined;
$("#interesting-div").click(function(e) {
// remember target
lastTarget = e.target;
});
$(document).click(function(e) {
if (e.target != lastTarget) {
// if target is different, then this event didn't come from our
// interesting div.
// do something interesting here:
console.log("We got a click outside");
}
});
var lastTarget = undefined;
$("#interesting-div").click(function(e) {
// remember target
lastTarget = e.target;
});
$(document).click(function(e) {
if (e.target != lastTarget) {
// if target is different, then this event didn't come from our
// interesting div.
// do something interesting here:
console.log("We got a click outside");
}
});
#interesting-div {
background: #ff0;
border: 1px solid black;
padding: .5em;
}
#annoying-childelement {
background: #fa0;
border: 1px solid black;
margin: 1em;
padding: .5em;
width: 20em;
}
#large-div {
background: #ccc;
padding: 2em 2em 20em 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="large-div">
<div id="interesting-div">
This is our interesting element
<div id="annoying-childelement">
child element
</div>
</div>
</div>
</div>
Couldn't find a solution that actually worked, but I want that on a click, a div shows.
Now this works when I load the page, but then after that first click, I have to click twice every time for the div to show.
Any ideas?
$(document).ready(function () {
setMenu();
});
function setMenu()
{
var headerExtIsOpen = false;
$('#headerExt').hide();
$('#header').click(function () {
if (!headerExtIsOpen) {
$('#headerExt').show();
headerExtIsOpen = true;
} else {
$('#headerExt').hide();
headerExtIsOpen = false;
}
});
}
There is no need to remember the state, just use toggle()
$(function () {
setMenu();
});
function setMenu()
{
$('#headerExt').hide();
$('#header').on("click", function (e) {
e.preventDefault();
$('#headerExt').toggle();
});
}
You said you want to toggle other things.
Best thing would be to toggle a class to change the color
$('#header').on("click", function (e) {
e.preventDefault();
$(this).toggleClass("open");
$('#headerExt').toggle();
});
another way is to check the state
$('#header').on("click", function (e) {
e.preventDefault();
var child = $('#headerExt').toggle();
var isOpen = child.is(":visibile");
$(this).css("background-color" : isOpen ? "red" : "blue" );
});
if the layout is something like
<div class="portlet">
<h2>Header</h2>
<div>
<p>Content</p>
</div>
</div>
You can have CSS like this
.portlet h2 { background-color: yellow; }
.portlet > div { display: none; }
.portlet.open h2 { background-color: green; }
.portlet.open > div { display: block; }
And the JavaScript
$(".portlet h2 a").on("click", function() {
$(this).closest(".portlet").toggleClass("open");
});
And there is layouts where it would be possible to have zero JavaScript involved.
Turns out I had some script hidden in my .js file that closes the menu again when the user clicks elsewhere, that I forgot about.
function resetMenu(e) {
var container = $('#headerExt');
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
{
$('#header').css("background-color", "inherit");
container.hide();
headerExtIsOpen = false;
}
}
I forgot to set the headerExtIsOpen back to false again after closing it in this function (code above shows the fix). Now it works fine :)
I have various elements on the page that can be dragged onto various drop zones. However for the textarea I can't find a way to show to the user that a draggable image suitable for a different zone, may not be dropped in the textarea.
I tried all kinds of combinations handling the ondragenter and ondragover events but it has been impossible to show the "no drop" icon when the image is dragged over the textarea.
There are lots of tutorials and tips on how to made a drop zone accept everything. I want to know how to make a dropzone and a textarea in particular reject a drag item. Turning of drag behavior for the item is not an option because there are other zones that should accept that image.
This JS fiddle shows that by default an image can be dragged into a textarea resulting in the URL being shown. I would love some help showing me how to stop that.
function dragstart(event) {//stuff}
function dragenter(event) {event.preventDefault();}
function dragover(event) {event.preventDefault();}
function dragdrop(event) {event.preventDefault();}
http://jsfiddle.net/mWKd3/16/
You aren't binding/attaching your events, for the attributes ondragstart, ondragenter, ondragover, and ondragdrop are not defined.
Here is a new fiddle that displays it http://jsfiddle.net/mWKd3/18/
In-Short - the Javascript (I'm using jQuery to attach the events)
$("img").bind("dragstart",function(e){
});
$("textarea").bind("dragenter",function(e){
e.preventDefault();
});
$("textarea").bind("dragover",function(e){
e.preventDefault();
});
$("textarea").bind("dragdrop",function(e){
e.preventDefault();
});
The following was an alternative method of doing drag-n-drop.
Referencing http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/ and extending your jsfiddle
HTML*
<div style='height:2em;display:block;'></div>
<img id='imgarea' src="http://www.planetinaction.com/images/gexplorer_logo48.png" draggable="true">
<textarea id='tarea' class="textzone"></textarea>
<div id='debugger' style='top:0em;left:5em;right:0em;height:2em;width:auto;position:absolute;display:block;'>Debug Window</div>
CSS*
.targetzone {
width: 200px;
height: 200px;
background-color: yellow;
}
.textzone {
width: 200px;
height: 200px;
background-color: white;
}
Javascript*
(function($) {
$.fn.dragstart = function(opt) {
opt = $.extend({handle:"",cursor:"move"}, opt);
if(opt.handle === "") {
var $el = this;
} else {
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
if(opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
}
var z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
$(this).data("start_pos_x",$drag.offset().left);
$(this).data("start_pos_y",$drag.offset().top);
$(this).data("start_z_idx",z_idx);
$drag.css('z-index', 1000).parents().on("mousemove", function(e) {
$('.draggable').offset({
top:e.pageY + pos_y - drg_h,
left:e.pageX + pos_x - drg_w
});
}).on("mouseup", function(e) {
$(this).removeClass('draggable').css('z-index', z_idx);
$("#debugger").append(document.elementFromPoint(e.pageX,e.pageY).id + " was selected!");
})
e.preventDefault(); // disable selection
}).on("mouseup", function() {
if(opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle').parent().removeClass('draggable');
}
$(this).offset({
top: $(this).data("start_pos_y"),
left: $(this).data("start_pos_x")
});
});
}
})(jQuery);
$("img").dragstart();