Reputation: 7213
I have this CSS to define drop areas, where a user can either drop a section before or after existing sections.
.section:before,
.section:after {
content: "[insert here]";
height: 64px;
line-height: 56px;
width: 100%;
display: block;
border: 3px dashed #aaa;
}
Using JavaScript + JQuery here is the drop listener, that detects the element currently under the mouse:
elem.on('drop', function(e) {
e.preventDefault();
var container = $(elem[0].elementFromPoint(e.clientX, e.clientY));
});
However container
would be the same element for both the :before and :after case.
How will I be able to know if the user has dropped before or after the section?
Upvotes: 5
Views: 128
Reputation: 125521
(Although - as others have mentioned - probably not the the best idea)
Assuming that the content is stacked one above the other with: before -> content -> after
We can calculate the dropping point with respect to the container and then - based on the height of the generated content we can determine if the element was dropped in the before or after zone.
And yes, javascript can actually access css properties of pseudo-elements.
This is done with Window.getComputedStyle()
Syntax: (from MDN)
var style = window.getComputedStyle(element[, pseudoElt]);
pseudoElt Optional
A string specifying the pseudo-element to match. Must be omitted (or null) for regular elements.
So, for example, to get the height of the generated content before the section (let's call it 'target'):
window.getComputedStyle(target, ':before').height
var elem = document.getElementById("el");
var target = document.getElementById("target");
var targetHeight = parseFloat(window.getComputedStyle(target).height);
var beforeHeight = parseFloat(window.getComputedStyle(target, ':before').height);
var afterHeight = parseFloat(window.getComputedStyle(target, ':after').height);
elem.addEventListener("drag", function(e) {
document.body.classList.remove('dropped');
});
target.addEventListener("dragover", function(e) {
this.textContent = "dragging over section";
document.body.classList.add('dragging-over');
addBeforeAfterClasses(e);
});
target.addEventListener("dragleave", function(e) {
document.body.classList.remove('dragging-over');
this.textContent = "section";
e.currentTarget.style.background = "none";
});
target.addEventListener("drop", function(e) {
document.body.classList.add('dropped');
addBeforeAfterClasses(e);
this.textContent = "successfully dropped!";
});
function addBeforeAfterClasses(e) {
var dropOffsetTopWithRespectToContainer = e.clientY - target.offsetTop;
if(dropOffsetTopWithRespectToContainer <= beforeHeight) {
document.body.classList.add('before');
} else {
document.body.classList.remove('before');
}
if(dropOffsetTopWithRespectToContainer > targetHeight - beforeHeight) {
document.body.classList.add('after');
} else {
document.body.classList.remove('after');
}
}
target.ondrop = drop_handler;
target.ondragover = dragover_handler;
function drop_handler(e) {
e.preventDefault();
}
function dragover_handler(e) {
e.preventDefault();
}
.section {
margin: 10px;
position: relative;
}
.section:before,
.section:after {
content: "[insert here]";
height: 64px;
line-height: 56px;
width: 100%;
display: block;
border: 3px dashed #aaa;
}
.dragging-over.before .section:before {
content: "[drop into before]";
border-color: green;
}
.dragging-over.after .section:after {
content: "[drop into after]";
border-color: green;
}
.dropped.before .section:before {
content: "[dropped into before]";
background-color: green;
color: white;
}
.dropped.after .section:after {
content: "[dropped into after]";
background-color: green;
color: white;
}
.elem {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: maroon;
margin: 0 20px;
display: inline-block;
}
<div id="target" class="section">section</div>
<span>drag me:</span>
<div id="el" draggable="true" class="elem"></div>
Upvotes: 1
Reputation: 4046
I think you can not manipulate the pseudo elements ::before
and ::after
, as technically there are not DOM and therefore is inaccessible by any JavaScript.
Upvotes: 2
Reputation: 1847
::before
and ::after
are css pseudo-elements which javascript do not know about. For javascript, they are both their parent element.
You might want to use real html elements to do that.
Upvotes: 3
Reputation: 2225
:before and :after are not part of the DOM, hence they are not accessible to any Javascript.
However the only solution I can think of is to calculate the height of the section and then compare it with the drop x and y coordinates to determine whether it was dropped before or after.
Upvotes: 2