Drag and drop file to specific target - javascript

I have a set of elements of media files listed like this.
I want to upload a a media file from windows explorer to a specific target of this list(for eg- It should be possible to add file above 'Title A' or below 'Title A'... ). How to achieve this?I know how to upload a file and it is achievable for me if it's to add to the end of the list. What I don't get is how to get that specific position which I need to upload.
(If it's a DOM element, I could have used jQuery draggable droppble, but again it's not possible here! :(. )
I am using ember and I have created component and added it after each element
abc: $('<div class="bla"></div>'),
didInsertElement() {
this._super(...arguments);
var self = this;
$('.xyz').bind("dragenter", function (evt) {
event.preventDefault();
event.stopPropagation();
var targetElement = $(evt.target).prev();
var holder = self.get('abc');
targetElement.after(holder);
});
$('.xyz').bind("dragleave", function (evt) {
event.preventDefault();
$('.bla').detach();
});
$('.xyz').bind("drop", function (evt) {
event.preventDefault();
$('.bla').detach();
});
},
With this I could successfully add a div below the target element. But with 'dragleave' it's executing every time and hence it's detaching everytime and also if I don't want to drop it or drop outside the window, it's not detaching at all.(something like dragend?)
.bla{
position: relative;
clear: both;
cursor: default;
margin-top: 2px;
min-height: 32px;
line-height: 32px;
overflow: hidden;
background-color: white;
border: 1px solid #999;
}
Any help?!
Thank you.

Related

JavaScript class - Override class function when specified?

I have a JavaScript class with some functions in it. One of those functions is an drop event which handles dragging and dropping files into a area. As soon the client dropped a file, a function named onDrop should be executed.
This onDrop function is located inside the class and should only be executed when the user drops a file. However, I need an possiblty to override the default class function onDrop with an own specified function from the class instance constructor. But, when there is no own specified function, use the default onDrop class function.
One of the two problems I have right now is that the default class function onDrop is executed immediately after creating a new instance of the class (which is wrong because this function should only be executed when the user draggend and dropped a file).
The second problem I have is when an user dropped a file, the onDrop function is never executed because an error in the console, which tells that the function onDrop is undefined.
Obviously I'm doing something wrong here but at this time I don't know exactly what. Maybe someone can tell me more about this problem?
Let me explain this situation with the following code (and at the very bottom a codepen example)
class myClass
{
constructor(area, events)
{
this.events = Object.assign
({
ondrop: this.onDrop()
}, events);
area.addEventListener('dragover', ev =>
{
ev.preventDefault();
});
area.addEventListener('drop', ev =>
{
ev.preventDefault();
this.events.ondrop(ev);
});
}
onDrop(ev)
{
alert('This is the onDrop function from the class itself');
}
}
var area = document.getElementById('file-upload');
var events = {
// remove the comment tags to overwrite the default onDrop function from the class
//ondrop: function() {alert('This is the onDrop function from the instance')}
};
var instance = new myClass(area, events);
body {
font-family : sans-serif;
}
#file-drag {
border : 2px dashed #555;
border-radius : 7px;
color : #555;
cursor : pointer;
display : block;
font-weight : bold;
margin : 1em 0;
padding : 3em;
text-align : center;
transition : background 0.3s, color 0.3s;
}
#file-drag:hover {
background : #ddd;
}
#file-drag:hover,
#file-drag.hover {
border-color : #3070A5;
border-style : solid;
box-shadow : inset 0 3px 4px #888;
color : #3070A5;
}
#file-upload-form {
margin : auto;
width : 40%;
}
<div id="file-upload">
<label for="file-upload" id="file-drag">
Drag a file into this box
</label>
</div>
Full Codes in Codepen

Capture mouse wheel event as native HTML attribute

I'm about to start working with the mousewheel event but the only thing I can find online uses addEventListener(). I am wanting to detect is with native HTML and CSS. In other words I'm looking for something like:
<span id='fooBar' onmousewheel='alert("fooBar")'></span>
I am creating spans dynamically and injecting them into the DOM and it would work a lot better if I didn't have to run javascript to do so. Every other event I can seem to get working natively but not mousewheel. Is this possible?
The reason you are only finding references to addEventListener() is because that is the standard and correct way to do it (it appears that onmousewheel isn't even supported in Firefox).
While this can be made to work (in browsers that support it) using the code you show in your question (except that your span is empty so you can't initiate the event with it since the element won't have any rendered size) and I have an example of that below, the use of inline HTML event handling attributes hearkens back to the time before we had standards and should not be used. Here's a link to another answer of mine that explains why.
<span id='fooBar' onmousewheel='alert("fooBar")'>Use the mousewheel while mouse is over this</span>
Inline vs. Delegation
In the demo the A side uses the standard addEventListener and registers the wheel event which is the replacement for the deprecated mousewheel event. Using the addEventListener is not only the standard but it's the most efficient if event delegation is used.
The use of onwheel as an attribute event has limited support due to the fact that using any attribute event is non-standard and discouraged. Despite this, I have included side B which uses the deprecated non-standard onmousewheel event for an attribute inline event handler. Because it's an awkwardly coded <span>, I used insertAdjacentHTML on a string that used all three quotes (i.e.', ", `). The use of a string literal was used on the a 2nd level of nested quotes, it's very messy.
Refer to this post on how the Event Object properties are utilized in event delegation.
Details are commented in the demo
Demo
// Reference the buttons
const btnA = document.getElementById('addA');
const btnB = document.getElementById('addB');
// Reference the parent nodes
const secA = document.querySelector('section:first-of-type');
const secB = document.querySelector('section:last-of-type');
// Register the click event on buttons
btnA.addEventListener('click', addNodeA, false);
btnB.addEventListener('click', addNodeB, false);
/* Register the wheel event on section A
|| which is the parent node of the wheeled
|| nodes. Event delegation involves one
|| event handler for multiple event targets.
|| This is far more efficient than multiple
|| inline event handlers.
*/
secA.addEventListener('wheel', markNode, false);
let cnt = 0;
/* Add node A to section A
|| ex. <span id="A1" class="A">A1</span>
*/
function addNodeA(e) {
cnt++;
var nodeA = document.createElement('span');
nodeA.id = 'A' + cnt;
nodeA.textContent = nodeA.id;
nodeA.className = 'A';
secA.appendChild(nodeA);
return false;
}
/* Add node B to section B
|| ex. <span id="B3" class="B" onmousewheel="this.style.outline = `5px dashed red`">B3</span>
*/
function addNodeB(e) {
cnt++;
/* This string is wrapped in single quotes,
|| double quotes for the attributes values,
|| and backticks for the property value of
|| an attribute value. Very messy, confusing,
|| and inefficient.
*/
var nodeB = '<span id="B' + cnt + '" class="B" onmousewheel="this.style.outline = `5px dashed red`">B' + cnt + '</span>';
// insertAdjacentHTML is innerHTML on steroids
secB.insertAdjacentHTML('beforeend', nodeB);
return false;
}
function markNode(e) {
/* If the wheeled node (i.e. e.target) is not the
|| registered node (i.e. e.currentTarget), then...
*/
if (e.target !== e.currentTarget) {
var node = e.target;
if (node.className === 'A') {
node.style.outline = '5px dashed blue';
} else {
return false;
}
}
}
html,
body {
width: 100%;
width: 100%
}
fieldset {
height: 10%;
}
main {
border: 3px solid lime;
height: 90%;
min-height: 250px;
display: flex;
}
section {
width: 50%;
min-height: 250px;
outline: 3px dashed gold;
padding: 10px 25px;
}
span {
height: 50px;
width: 50px;
padding: 2px;
text-align: center;
font-size: 12px;
margin: 5px;
display: inline-block;
}
.A {
background: rgba(0, 100, 200, .3);
}
.B {
background: rgba(200, 100, 0, .3);
}
#addB {
margin-left: 35%
}
<fieldset>
<legend>addNode</legend>
<button id='addA'>nodeA</button>
<button id='addB'>nodeB</button>
</fieldset>
<main>
<section></section>
<section></section>
</main>
You can dynamically create elements with listeners pretty easily. You just need to understand the DOM and how to attach event listeners.
The example below creates 10 spans and attaches a listener to each of them. Just hover over a span and scroll the mouse-wheel. The ID of the span will be logged to the console.
// Create 10 spans with a scroll listener.
var count = 10;
for (var i = 0; i < count; i++) {
var span = document.createElement('SPAN');
span.id = 'foo-bar-' + i;
span.innerHTML = 'Foo #' + i;
addEventListener(span, 'mousewheel', performEvent);
document.body.appendChild(span);
}
// Event function.
function performEvent(e) {
console.log(e.target.id);
}
// IE 8+ via http://youmightnotneedjquery.com/
function addEventListener(el, eventName, handler) {
if (el.addEventListener) {
el.addEventListener(eventName, handler);
} else {
el.attachEvent('on' + eventName, function(){
handler.call(el);
});
}
}
.as-console-wrapper { max-height: 5em !important; }
span[id^="foo-bar-"] {
border: thin solid black;
margin: 0.25em;
}
Try the following:
::-webkit-scrollbar {
width: 0px; /* remove scrollbar space */
background: transparent; /* optional: just make scrollbar invisible */
}
<!DOCTYPE HTML>
<html>
<body style="overflow: auto;
max-height: 100vh;" onscroll="alert('hi')">
<div style="height:2000px;width:100%"></div>
</body>
</html>
The reason you find "addEventListener" examples only is because you need to handle this cross-browser:
var supportedWheelEvent = "onwheel" in HTMLDivElement.prototype ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll";
Also, it's best to do this on one element only! Use delegated event listener to handle this for all of the elements that you need.
HTML Example:
<div id="delegator">
<div class="handleWheel">handle wheel event here</div>
<div> no wheel event handled here </div>
<div class="handleWheel">handle wheel event here</div>
<div> no wheel event handled here </div>
</div>
JS:
var supportedWheelEvent = "onwheel" in HTMLDivElement.prototype ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll";
function handler(e){
if(e.target.classList.contains('handleWheel')){
// handle the event here
}
}
var d = document.getElementById('delegator');
d.addEventListener(supportedWheelEvent, handler);
Working codepen sample:
https://codepen.io/Mchaov/pen/zwaMmM

Style select box option:disabled when it's checked

In the image below, I want Exp. Year (the disabled option) to be grey on page load like a placeholder, and when an option is clicked (2016), I want it to turn to black. It is possible to do this without js?
JSFiddle
What is currently does:
What I want it to do: (Exp. Month is grey on page load, then 2016 is black on select)
.select-box {
border: 1px solid $ghBlack;
height: 36px;
background: transparent;
margin: 10px 0 14px 0;
color: #000;
}
option:disabled {
color: #a9a9a9;
}
option:not(:checked) {
color: #a9a9a9;
}
One way to do this is as follows:
// binding an anonymous function as the change-event handler:
$('select').change(function () {
// adjusting the 'color' property of the select element:
$(this).css('color', function () {
// caching the 'this' variable for efficiency (give repeated use):
var self = this,
// finding the options of the select element:
opts = self.options;
// getting the currently-selected option, and then checking if
// it's the default-selected option (returns a Boolean); if it is
// we set the colour to '#aaa', if not we set the colour to '#000':
return opts[self.selectedIndex].defaultSelected ? '#aaa' : '#000';
});
// triggering the change-event so that this runs on page-load:
}).change();
JS Fiddle demo.
Reference:
change().
css().
When you explained more what you try to do, then the answer is no, you can't do it without javascript, because the color of the main option is just one....its defined by this css selector
.select-box {
color: grey;
}
You can only change colors of the options (when the select is opened) - fiddle: http://jsfiddle.net/san6q621/

Temporarily disable all onclick events and bind them back

How to disable all onclick events on a page, bind my custom function, and after the execution enable all the previous events?
I'm building a bookmarklet, which should work on any already loaded page and I'm using jQuery to handle my custom logic (the page is jquerified after it is loaded). Note, that I don't have any control which events and when are being bound.
Currently the best stable solution i found is to unbind the events, bind by custom function preventing the default action and then, reload the page. This works, however I want to avoid the reload. A partial workaround would be to reload the page and scroll to the previous position (how to achieve this effect?). Some possible solution would use iframes, but I'd prefer to avoid this.
it's easier to lay a div-element over all... something like
CSS
.noclick {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9999; /* or maybe higher */
background-color: transparent;
}
jQuery
jQuery(document).ready(function() {
jQuery('body').append('<div class="noclick" />');
});
A nice way I've seen it done, and done it myself is to use a modal 'mask' overlay.
The grayed out transparent mask that covers the entire page, except for the element you're interacting with, eg. modal popup window.
One more way is to use the jQuery BlockUI plugin.
You can reassign the onclick to another property and than override it.
Example with one element
var btn = document.getElementById("button");
btn._onclick = btn.onclick;
btn.onclick = function(){ return false; };
and when you want to transfer it back to the original event
var btn = document.getElementById("button");
if (btn._onclick) {
btn.onclick = btn._onclick;
btn._onclick = null;
}
It depends on whether your onclick event is dependent on the element being clicked (i.e. whether it needs to know which element was clicked):
If it's independent, then you can just add an event handler to the body element or other parent (because the parent event gets called first, then the child, which is what you want):
$('body').click(function() { /* your code here */});
It it is dependent on the the element, then you can access the previous onclick event code that has been registered in the 'click' property of element which is being clicked, so something like this (probably being a little more specific with the selectors):
$('body *').each(function() {
var previousClick = this.click;
this.click = null; // remove previous
$(this).click(function() { /* your code here */});
$(this).click(function() { previousClick();}); // run the code that was already there.
})
Some modification algorhythm's answer.
The idea is to "cover" the link by a transparent element. You can use a pseudo element (e.g. :after).
To prevent "tab key" set tabindex:
<a href="..." tabindex="-1">
Mark link with a class "disabled" on click:
$('a').on('click', function(){ $(this).addClass('disabled') })
Add css:
a.disabled:after {
position: absolute;
content: "";
display: block;
background: white;
opacity: 0.5; // optional
z-index: 999;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
$('a').on('click', function(){ $(this).addClass('disabled') });
a.disabled:after {
position: absolute;
content: "";
display: block;
background: white;
opacity: 0.5; // optional
z-index: 999;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a hreh="#" tabindex="-1">The Link</a>

TextArea Auto Resize On Paste

Ok, here's my problem. I"m using this plugin (http://james.padolsey.com/javascript/jquery-plugin-autoresize/) to autoresize my textarea when there's more text. When I paste using keyboard, it autoresizes perfectly. However, when I paste using mouse, it doesn't work.
So my code to resize textareas are:
$('textarea').autoResize({
// On resize:
onResize : function() {
$(this).css({opacity:0.8});
},
// After resize:
animateCallback : function() {
$(this).css({opacity:1});
},
// Quite slow animation:
animateDuration : 300,
// More extra space:
extraSpace : 40
});
My code to call the autoresize function on paste:
$('textarea').bind('paste', function() {
$('this').autoResize({
// On resize:
onResize : function() {
$(this).css({opacity:0.8});
},
// After resize:
animateCallback : function() {
$(this).css({opacity:1});
},
// Quite slow animation:
animateDuration : 300,
// More extra space:
extraSpace : 40
});
});
However, this doesn't seem to work. Any ideas?
According to this question you need to use setTimeout on your paste event to wait a few milliseconds before you try to retrieve the value.
$('textarea').bind('paste', function() {
var $textarea = $(this);
setTimeout(function() {
$("div").text($textarea.val());
}, 250);
});
Example on jsfiddle
So maybe it might work like the following:
$('textarea').bind('paste', function () {
var $textarea = $(this);
setTimeout(function () {
$textarea.trigger("change.dynSiz");
}, 250);
});
Example on jsfiddle
The main idea is that: plugin doesn't track paste events, it tracks only just keyboard events. Thus you'll need either to find another plugin, or modify that one (and track mouse events too).
Here's a part of code (of that plugin), where you should look for:
// Bind namespaced handlers to appropriate events:
textarea
.unbind('.dynSiz')
.bind('keyup.dynSiz', updateSize)
.bind('keydown.dynSiz', updateSize)
.bind('change.dynSiz', updateSize);
Maybe, add .bind('click.dynSiz', updateSize) there.
I'm not very familiar with jQuery and don't know, what such event names mean.
Super light weight:
Has anyone considered contenteditable? No messing around with scrolling,a nd the only JS I like about it is if you plan on saving the data on blur... and apparently, it's compatible on all of the popular browsers : http://caniuse.com/#feat=contenteditable
Just style it to look like a text box, and it autosizes... Make its min-height the preferred text height and have at it.
What's cool about this approach is that you can save and tags on some of the browsers.
http://jsfiddle.net/gbutiri/v31o8xfo/
<style>
.autoheight {
min-height: 16px;
font-size: 16px;
margin: 0;
padding: 10px;
font-family: Arial;
line-height: 16px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
overflow: hidden;
resize: none;
border: 1px solid #ccc;
outline: none;
width: 200px;
}
</style>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script>
$(document).on('blur','.autoheight',function(e) {
var $this = $(this);
// The text is here. Do whatever you want with it.
console.log($this.html());
});
</script>
<div class="autoheight contenteditable" contenteditable="true">Mickey <b>Mouse</b></div>

Categories

Resources