I am working on an upload script at the moment, and of course it has drag and drop capabilities.
However I am trying to get this to work when I drag a file over my element it adds the class drag-over however because my element has children it is constantly firing because it enters and leaves the element.
What I want to know is how can I expand the *dragenter* / *dragover* to include the main elements children also?
Here is a trimmed down version of my code (please note I have disabled the file input):
$(document).ready(function(){
$(window).on('dragenter', function(){
$(this).preventDefault();
});
$('#drag-and-drop-zone').on('dragenter', function(){
$(this).addClass('drag-over');
});
$('#drag-and-drop-zone').on('dragleave', function(){
$(this).removeClass('drag-over');
});
});
.uploader
{
width: 100%;
background-color: #f9f9f9;
color: #92AAB0;
text-align: center;
vertical-align: middle;
padding: 30px 0px;
margin-bottom: 10px;
border-radius: 5px;
font-size: 200%;
box-shadow: inset 0px 0px 20px #c9afb2;
cursor: default;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.uploader div.or {
font-size: 50%;
font-weight: bold;
color: #C0C0C0;
padding: 10px;
}
.uploader div.browser label {
background-color: #ffffff;
border: 2px solid #f44;
padding: 5px 15px;
color: #f44;
padding: 6px 0px;
font-size: 40%;
font-weight: bold;
cursor: pointer;
border-radius: 2px;
position: relative;
overflow: hidden;
display: block;
width: 300px;
margin: 20px auto 0px auto;
transition: all 0.3s linear 0s;
}
.uploader div.browser span {
cursor: pointer;
}
.uploader div.browser input {
position: absolute;
top: 0;
right: 0;
margin: 0;
border: solid transparent;
border-width: 0 0 100px 200px;
opacity: .0;
filter: alpha(opacity= 0);
direction: ltr;
cursor: pointer;
}
.uploader div.browser label:hover {
background-color: #f44;
color: #fff;
border: 2px solid #fff;
}
.drag-over{
border: 2px solid #00aef0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="uploader" id="drag-and-drop-zone">
<div>Drag & Drop Images Here</div>
<div class="or">-or-</div>
<div class="browser">
<label>
<span>Select Image</span>
<input type="file" title="Click to add Images" accept="image/*" name="files" disabled="true">
</label>
</div>
</div>
Solved it!!
It is a simple case of instead on on('dragenter') I needed to use bind('dragover')
$(document).ready(function(){
$(window).on('dragenter', function(){
$(this).preventDefault();
});
$('#drag-and-drop-zone').bind('dragover', function(){
$(this).addClass('drag-over');
});
$('#drag-and-drop-zone').bind('dragleave', function(){
$(this).removeClass('drag-over');
});
});
.uploader
{
width: 100%;
background-color: #f9f9f9;
color: #92AAB0;
text-align: center;
vertical-align: middle;
padding: 30px 0px;
margin-bottom: 10px;
border-radius: 5px;
font-size: 200%;
box-shadow: inset 0px 0px 20px #c9afb2;
cursor: default;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.uploader div.or {
font-size: 50%;
font-weight: bold;
color: #C0C0C0;
padding: 10px;
}
.uploader div.browser label {
background-color: #ffffff;
border: 2px solid #f44;
padding: 5px 15px;
color: #f44;
padding: 6px 0px;
font-size: 40%;
font-weight: bold;
cursor: pointer;
border-radius: 2px;
position: relative;
overflow: hidden;
display: block;
width: 300px;
margin: 20px auto 0px auto;
transition: all 0.3s linear 0s;
}
.uploader div.browser span {
cursor: pointer;
}
.uploader div.browser input {
position: absolute;
top: 0;
right: 0;
margin: 0;
border: solid transparent;
border-width: 0 0 100px 200px;
opacity: .0;
filter: alpha(opacity= 0);
direction: ltr;
cursor: pointer;
}
.uploader div.browser label:hover {
background-color: #f44;
color: #fff;
border: 2px solid #fff;
}
.drag-over{
border: 2px solid #00aef0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="uploader" id="drag-and-drop-zone">
<div>Drag & Drop Images Here</div>
<div class="or">-or-</div>
<div class="browser">
<label>
<span>Select Image</span>
<input type="file" title="Click to add Images" accept="image/*" name="files" disabled="true">
</label>
</div>
</div>
Apparently this problem is more recurrent than I thought since I found at least 5 questions associated with the same topic.
Unlike "mouseover", the events "dragover" and "dragleave" do not consider the child elements as a whole, so each time the mouse passes over any of the children, "dragleave" will be triggered.
Thinking about the upload of files, I created a widget that allows:
Drag and drop desktop files using $ _FILES
Drag and drop to browser images/elements or url using $ _POST and cURL
Attach a device file using button using $ _FILES
Use input to write/paste url images/elements using $ _POST and cURL
The problem: As everything, both form inputs and images, are within DIVs children, "dragleave" was triggered even if it did not leave the dashed line. Using the attribute "pointer-events: none" is not an alternative since methods 3 and 4 need to trigger "onchange" events.
The solution? An overlapping DIV that covers all the drop-container when the mouse enters, and the only one with child elements with "pointer-events: none".
The structure:
div #drop-container: main div, keep all togheter
div #drop-area: "dragenter" listener and inmediate trigger #drop-pupup
div #drop-pupup: at same leval as #drop-area, "dragenter", "dragleave" and "drop" listener
Then, when the mouse enters by dragging an element to #drop-area, inmediatly shows #drop-pupup ahead and successively the events are on this div and not the initial receiver.
Here is the JS/jQuery code. I took the liberty to leave the PoC so do not lose all the time I lost.
jQuery(document).on('dragover', '#drop-area', function(event) {
event.preventDefault();
event.stopPropagation();
jQuery('#drop-popup').css('display','block');
});
jQuery(document).on('dragover dragleave drop', '#drop-popup', function(event) {
event.preventDefault();
event.stopPropagation();
console.log(event.type);
// layout and drop events
if ( event.type == 'dragover') {
jQuery('#drop-popup').css('display','block');
}
else {
jQuery('#drop-popup').css('display','none');
if ( event.type == 'drop' ) {
// do what you want to do
// for files: use event.originalEvent.dataTransfer.files
// for web dragged elements: use event.originalEvent.dataTransfer.getData('Text') and CURL to capture
}
}
});
body {
background: #ffffff;
margin: 0px;
font-family: sans-serif;
}
#drop-container {
margin: 100px 10%; /* for online testing purposes only */
width: 80%; /* for jsfiddle purposes only */
display: block;
float: left;
overflow: hidden;
box-sizing: content-box;
position: relative; /* needed to use absolute on #drop-popup */
border-radius: 5px;
text-align: center;
cursor: default;
border: 2px dashed #000000;
}
#drop-area {
display: block;
float: left;
padding: 10px;
width: 100%;
}
#drop-popup {
display: none;
box-sizing: content-box;
position: absolute;
width: 100%;
top: 0;
left: 0;
background: linear-gradient(to BOTTOM, rgba(245, 245, 245, 1) , rgba(245, 245, 245, 0));
height: 512px;
padding: 20px;
z-index: 20;
}
#drop-popup > p {
pointer-events: none;
}
<html>
<head>
<title>Drag and Drop</title>
</head>
<body>
<div id="drop-container">
<div id="drop-area">
<p>Child paragraph content inside drop area saying "drop a file or an image in the dashed area"</p>
<div>This is a child div No. 1</div>
<div>This is a child div No. 2</div>
</div>
<div id="drop-popup">
<p>This DIV will cover all childs on main DIV dropover event and current P tag is the only one with CSS "pointer-events: none;"</p>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript"></script>
</body>
<html>
About jQuery "on", use it with the div id inside on, so you can start event triggers starting "uploading box" hidden.
Finally, I preferred to use "dragover" over "dragenter" because it has a small delay (milliseconds) that favors performance
(https://developer.mozilla.org/en-US/docs/Web/API/Document/dragover_event).
You can simply hide elements from the mouse interaction with styling:
e.g. add this to the child elements:
pointer-events: none;
Unfortunately support is not great in IE for this: http://caniuse.com/#feat=pointer-events
I found 2 other working solutions.
It works only if you do not have other controller elements (edit, delete) inside the area, because this solution blocks them too:
#drop * {pointer-events: none;}
There is a better solution.
The idea is that you increase a counter every time you enter/hover into/on a new child element and decrease the counter when you leave one of them.
$(document).ready(function(){
var dropzoneCounter = 0;
$('#drag-and-drop-zone').on('dragenter', function(){
dropzoneCounter++;
$(this).addClass('drag-over');
});
$('#drag-and-drop-zone').bind('dragleave', function(){
dropzoneCounter--;
if (dropzoneCounter === 0) {
$(this).removeClass('drag-over');
}
});
$('#drag-and-drop-zone').bind('drop', function(){
dropzoneCounter = 0;
$(this).removeClass('drag-over');
});
});
Related
I have a html with some css:
<label class="label-checkbox">
<input type="checkbox" data-bind="click: clickedMultipleServicesButton, checked: checkedMultipleServicesButton, css: {checked: true}">
<span style="font-size:14px !important">Test Button</span>
</label>
<style>
label.label-checkbox {
cursor: pointer;
}
label.label-checkbox input {
position: absolute;
top: 0;
left: 0;
visibility: hidden;
pointer-events: none;
}
label.label-checkbox span {
padding: 8px 11px;
border: 1px solid #ccc;
display: inline-block;
color: #ffffff;
border-radius: 6px;
margin: 7px;
background: #253965;
user-select: none;
}
label.label-checkbox input:checked + span {
box-shadow: inset 1px 2px 5px #777;
transform: translateY(1px);
background: #ffd800;
}
</style>
It works when I remove data-bindings. On click it colors the blue button a yellow one and opposite.
But however, when I add data-binding: click it doesnt work anymore.
I assume that I need to dynamically attach css classes on click event?
Desired behavior:
I want to have data-bind="click: someFunction" but when I click, to have css behavior, and to have function that will catch when is the button checked, and when it is not.
Yes I'm not sure how to manipulate pseudo-classes in the knockout but you can dynamically add and remove CSS class:
<label class="label-checkbox" >
<input type="checkbox" data-bind="click: clickedMultipleServicesButton, css: checkedMultipleServicesButton() && 'checked'"/>
<span style="font-size:14px !important">Test Button</span>
</label>
<style>
label.label-checkbox {
cursor: pointer;
}
label.label-checkbox input {
position: absolute;
top: 0;
left: 0;
visibility: hidden;
pointer-events: none;
}
label.label-checkbox span {
padding: 8px 11px;
border: 1px solid #ccc;
display: inline-block;
color: #ffffff;
border-radius: 6px;
margin: 7px;
background: #253965;
user-select: none;
}
label.label-checkbox input.checked + span {
box-shadow: inset 1px 2px 5px #777;
transform: translateY(1px);
background: #ffd800;
}
</style>
note that I turned your input:checked into input.checked.
Code in the view model:
self.checkedMultipleServicesButton = ko.observable(false);
self.clickedMultipleServicesButton = function (e) {
self.checkedMultipleServicesButton(!self.checkedMultipleServicesButton());
}
I'm a beginner to website building, and I wanted to create an animation every time a button is pressed. So I tried doing it on CSS first, but realized it could not be done with that alone, so I incorporated JS into my code which is still not working. The idea is, when I press the button, "Filter", the menu that is in the element, ".filter" comes down, so I tried adding an animation to shift the margin down, which does not work. How can I make this work?
function btnFilter() {
document.getElementByClass(".filter").style.WebkitAnimation = "filter-animation";
document.getElementByClass(".filter").style.animation = "filter-animation";
}
.filter {
display: none;
position: relative;
border-radius: 8px;
border-bottom: 1px solid #ffffff;
border-left: 1px solid #ffffff;
border-right: 1px solid #ffffff;
margin-top: -57px;
}
#-webkit-keyframes filter-animation {
from {
margin-top: -57px;
display: none;
}
to {
margin-top: 30px;
display: flex;
}
}
#keyframes filter-animation {
from {
margin-top: -57px;
display: none;
}
to {
margin-top: 30px;
display: flex;
}
}
<button onclick="btnFilter()">Filter</button>
<div class="filter">
<p>filter</p>
<form class="drpdwn-1">
<p>Price range:</p>
<select value="Price Range">
<option>$0 - $50</option>
<option>$50 - $100</option>
<option>> $100</option>
</select>
</form>
</div>
jQuery(JS)may help you
https://jsfiddle.net/moongod101/h8t6347b/
My way to do it is just use the jQuery function addClass,easy and simple
function btnFilter() {
document.getElementsByClassName(".filter").style.WebkitAnimation = "filter-animation";
document.getElementsByClassName(".filter").style.animation = "filter-animation";
}
use getElementsByClassName('.className')...
You can use just CSS but you need to toggle a css class for animating the button every time.
Here is an example:
var el = document.querySelector(".button");
el.addEventListener('click', function() {
if(!el.classList.contains("animate")) {
el.classList.add("animate");
} else {
el.classList.remove("animate");
}
});
.button {
font-weight: bold;
font-size: 1.2em;
color: white;
background-color: #777;
padding: 0.7em 2em;
border: 0;
margin: 1em auto 0;
border-radius: 3px;
box-shadow: 0 3px 0 #444;
display: block;
cursor: pointer;
appearance: none;
transition: transform 1.5s ease;
}
.animate {
transform: translateY(50px);
}
<button class="button">Click me</button>
As you can see below in IE the slider is working, but I can't find what is the "ms-fill-lower" pseudo-code in chrome/firefox. Also I haven't figured out how can I print out the number continously above the thumb (I was thinking about creating a new childnode in JS and then using the position of the slider + the current value of the thumb and with this info I could create a new position for the brand new childnode. Is there an easier way maybe?)
<!DOCTYPE:html>
<html>
<head>
<style>
input {
position: fixed;
top: 40;
right: 40;
}
input[type=range] {
-webkit-appearance: none;
margin: 30px 0px;
width: 80%;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-ms-thumb {
box-shadow: 0px 0px 0px #ffccff, 0px 0px 0px #ffccff;
height: 30px;
width: 48px;
background-image: url('https://scontent-vie1-1.xx.fbcdn.net/hphotos-xpa1/v/t34.0-12/12204684_1096899726988871_1886399559_n.jpg?oh=b8481694391b1a5ebe58733f0638a08f&oe=563669C2');
cursor: pointer;
-webkit-appearance: none;
margin-top: 0px;
}
input[type=range]::-ms-track {
width: 100%;
height: 30px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #ff0000;
border: 0.2px solid #ff0000;
}
input[type=range]::-ms-fill-upper {
background: #ffccff;
}
input[type=range]:focus::-ms-fill-lower {
background: #ff0000;
}
input[type=range]:focus::-ms-fill-upper {
background: #ffccff;
}
</style>
</head>
<body>
<input type="range"></input>
</body>
</html>
Pseudo elements for chrome ::-webkit-slider-thumb and ::-webkit-slider-runnable-track
for firefox ::-moz-range-thumb and ::-moz-range-track
to print the number continuously
<input type="range" max="22" min="12" value="18" step="2" oninput="dataUpdate()" id="myInput" />
<p id="mydata"></p>
<script>
function dataUpdate(){
var x = document.getElementById("myInput").value;
document.getElementById("mydata").innerHTML=x;
}
</script>
where value is current position of the range on load, step is the difference between each value, oninput event will trigger when you'll move the range's thumb and the output will be displayed in the <p> tag
to check pseudo elements in chrome you can read this http://webcomponents.org/articles/introduction-to-shadow-dom/
I want to display tooltip on click of textbox.
What i did is:
CSS:
.tooltip {
background-color:#000;
border:1px solid #fff;
padding:10px 15px;
width:200px;
display:none;
color:#fff;
float:right;
text-align:left;
font-size:12px;
position:absolute;
z-index: 1;
}
.input1 {
background: none repeat scroll 0 0 #F8F8F8;
border: 1px solid #DDDDDD;
border-radius: 4px 4px 4px 4px;
box-shadow: 0 0 2px #DFDFDF inset;
clear: left;
min-height: 45px;
position: relative;
}
.textfield {
background: none repeat scroll 0 0 transparent;
border: medium none;
font-family: inherit;
font-size: inherit;
font-size-adjust: inherit;
font-stretch: inherit;
font-style: inherit;
font-variant: inherit;
font-weight: inherit;
height: 100%;
line-height: 1em;
margin: 0;
padding: 15px;
width: 100%;
}
.label {
float: left;
line-height: 15px;
margin: 0;
padding: 15px 0;
text-align: right;
width: 26%;
}
JS:
$(function () {
$("#help_form :input").tooltip({
position: "center right",
offset: [-2, 10],
effect: "fade",
opacity: 0.7
});
});
HTML:
<div id="help">
<form id="help_form" class="help_form" action="/me/problem" method="post">
<div class="input1">
<label class="label" for="issuetitle">Title</label>
<input class="textfield" type="text" name="issuetitle" title="must be 100 characters long" />
</div>
</form>
</div>
Actually by setting width of textfield = 30%. We can able to see tooltip. But because of some restriction i don't want want to do it. Is there any other way to do it by using it tooltip comes over textbox.
Thanks in advance.
you can also use jquery for tooltip, like this,
$(function() {
$( document ).tooltip();
});
</script>
And if you want to know more about it then refer this link,
http://jqueryui.com/tooltip/
First you need to have a correct html : put a <style>after your head.
Then you need to load the tooltip plugin you want to call with .tooltip().
Then check for your console and javascript errors.
But maybe you have stripped down your code to post here.
If it's the case, try with a display: block on your .tooltip declaration and check if you can see it.
The problem I'm having is not being able to select the divs inside the 'menuItem' class divs. I've tried using the jQuery selector to select by both class and even ID, but every time I try to do anything with it, such as an animation, nothing happens. Is there some jQuery law I don't know about that prevents me from doing so?
$('.menu')
.hover( function() {
$(this).toggleClass('highlighted');
})
.click(function() {
$(this).parent().children('.menuItem').children('#wtf').slideDown();
});
Also tried these for the click(), but none of them work..
$('#wtf').slideDown();
$('.test').slideDown();
$(this).parent().find('.menuItem').each( function() { $(this).slideDown(); } );
$(this).parent().children('.menuItem').children().slideDown();
<div class='box'>
<div>
<div class='menu'>Resources</div>
<div class='menuItem'>
<div ID='wtf' class='test'>Library</div>
<div>Internet</div>
<div>Your mom</div>
</div>
</div>
<div>
<div class='menu'>Products</div>
</div>
<div>
<div class='menu'>Contact</div>
</div>
</div>
body { font-size: 16px; }
.box {
background: blue;
border: 1px;
padding: 4 6 4 6;
position: absolute;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 2px solid;
}
.box div {
float: left;
text-align:center;
}
.menu {
background: lightblue;
width: 105px;
text-align: center;
padding: 4 10;
margin: 1 5;
font-weight: bold;
font-family:'Verdana', 'Times', serif;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 2px solid gray;
}
.highlighted {
background: lime;
color: navy;
}
.menuItem {
clear: left;
position: absolute;
margin-top: 30px;
}
.menuItem div {
display: none;
background: lightblue;
opacity: .7;
filter: alpha(opacity=.7);
width: 105px;
text-align: center;
padding: 4 10;
margin: 1 5;
font-size: 10px;
font-family: 'Verdana', 'Times', serif;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 2px solid white;
clear: left;
}
Have you tried?
$(this+' > .menuItem div')
I applied a background color to your style and your jQuery selector wasn't selecting properly. I tried this and it changed the background color, but I don't have CSS in place for the visual of the slideDown() to work - you'll have to write your CSS up correctly.
$(this).siblings().find("#wtf").css("background-color","#cccccc").slideDown();