How to accept D&D for div, but propagate clicks? - html

I have a windows full-sized div container which reacts to incoming drag&drop events for files.
<div id="drag-overlay">
<div id="drag-overlay-text">This is shown while drag is active...</div>
</div>
Unfortunately the container doesn't propagate clicks to underlying objects like buttons anymore. Is there a simple CSS fix, or do I need to register a click-handler on the div container and manually propagate the clicks/drags manually? Latter doesn't really feel like a good solution
#drag-overlay {
position: absolute;
top: 0;
z-index: 1;
bottom: 0;
left: 0;
right: 0;
height: 100%;
width: 100%;
opacity: 0;
}
Registration of the drag and drop handler:
var holder = document.getElementById('drag-overlay');
holder.ondragover = () => { ...
holder.ondragleave = () => { ...
holder.ondragend = () => { ...
holder.ondrop = (e: DragEvent) => { ...
...

I'm guessing that the problem is the buttons are technically "under" the drag-overlay since its absolutely positioned, so no actions to them can be seen.
Since you didn't post a lot of code, I put together this working sample, that shows putting the button outside of #drag-overlay and absolutely positioning it with a higher z-index than #drag-overlay.
var btn = document.querySelector("button");
btn.addEventListener("click", function(e) {
e.preventDefault();
console.log("click");
});
#drag-overlay {
position: absolute;
top: 0;
z-index: 1;
bottom: 0;
left: 0;
right: 0;
height: 100%;
width: 100%;
opacity: 0;
}
button {
position: absolute;
top: 0;
z-index: 2;
left: 0;
right: 0;
}
<button>TEST</button>
<div id="drag-overlay">
<div id="drag-overlay-text">This is shown while drag is active...</div>
</div>

Related

Toggle HTML using a button in tampermonkey

I have been trying to get a script working to toggle a piece of HTML when i toggle a button,
But so far i have not been able to get it working,
let newImg5 = document.createElement("img");
newImg5.src = "https://www.pcinvasion.com/wp-content/uploads/2016/12/discord.jpg";
newImg5.style = `position: absolute; bottom: 15px; left: 15px; z-index: 100000; width: 50px; height: 50px; cursor: pointer;`;
document.body.prepend(newImg5);
newImg5.addEventListener("click", () => {
toggle.html <iframe src="https://discordapp.com/widget?id=68awdawdawdawds8&theme=dark" width="350" height="500" allowtransparency="true" frameborder="0"></iframe>
});
It sounds like you want to do something like this:
let newImg5 = document.createElement("img");
newImg5.src = "https://www.pcinvasion.com/wp-content/uploads/2016/12/discord.jpg";
newImg5.style = `position: absolute; bottom: 15px; left: 15px; z-index: 100000; width: 50px; height: 50px; cursor: pointer;`;
document.body.prepend(newImg5);
/* create iframe */
let iframe = document.createElement('iframe');
iframe.setAttribute('id', 'iframe');
iframe.setAttribute('src', 'https://discordapp.com/widget?id=68awdawdawdawds8&theme=dark');
iframe.setAttribute('width', '350');
iframe.setAttribute('height', '500');
iframe.setAttribute('allowtransparency', 'true');
/* Make iframe appear on click */
newImg5.addEventListener("click", () => {
document.body.append(iframe);
});

How to change data visible range to % percent

I am using this for my header that changes in a one page scroll up and down page. I noticed that it's not responsive so i am asking you if you maybe know a way to make that responsive. Like changing the 0-690 into a percentage so that it will work on mobile and also on a tv screen.
HTML
<div class="header header-1" data-visible-range="0-690">Portfolio</div>
<div class="header header-2" data-visible-range="691-2100">Services</div>
<div class="header header-3" data-visible-range="2101-">Contact</div>
CSS
.header-1 {
background-color:dimgray;
display: block;
}
.header-2 {
background-color:dimgray;
}
.header-3 {
background-color:dimgray;
}
.header {
position: fixed;
top: 0;
left: 0;
height:8vmax;
width: 100%;
display: none;
visibility:hidden;
transition: visibility .4s, opacity .4s ease-in-out;opacity:0;
font-size:4vmax;padding:1.58vmax;color:white;
}
What if, instead of basing it off pixels, you just checked to see if an element hit the top of the page, and then changed the header?
We'll call these elements "triggers." See my code below for an example of how they work.
let updateHeader = () => {
let scrollTop = $(window).scrollTop(),
triggerTitle = "Hi";
$('.trigger').each((i, el) => {
let topPos = $(el).offset().top,
distance = topPos - scrollTop;
if (distance < 0)
triggerTitle = $(el).data('title');
});
$('header h2').text(triggerTitle);
}
$(window).scroll(updateHeader);
$(window).on('touchmove', updateHeader);
body {
margin: 0;
}
#container {
height: 1000px;
}
header {
width: 100%;
position: fixed;
top: 0;
background-color: red;
}
p {
margin: 200px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<header><h2>Hi</h2></header>
<p class="trigger" data-title="section1">
trigger1
</p>
<p class="trigger" data-title="section2">
trigger2
</p>
<p class="trigger" data-title="section3">
trigger3
</p>
</div>
As you scroll down the page, each trigger hits the top of the page, and the text in the header will change to the the value of the latest trigger's data-title. You could position these triggers appropriately above each of your website's sections, so that, no matter what size the screen, the header should update at the right time. Here's a codepen.
EDIT
Try this JS instead for maximum compatibility (no es6 involved).
function updateHeader() {
var scrollTop = $(window).scrollTop(),
triggerTitle = "Hi";
$('.trigger').each(function(i, el) {
var topPos = $(el).offset().top,
distance = topPos - scrollTop;
if (distance < 0)
triggerTitle = $(el).data('title');
});
$('header h2').text(triggerTitle);
}
$(window).scroll(updateHeader);
$(window).on('touchmove', updateHeader);

Sidebar that changes content width

I am currently developing a plugin for existing websites.
Its purpose is to display a sidebar with my content. To that end, the website owner creates an empty div, references my javascript file and calls my code with the ID of the empty div.
My plugin is then creating an iFrame in that empty div and loads its content. It also is responsible for styling the provided div so that it actually is a sidebar: It changes the width and height of that div and attaches it to the right edge of the screen.
So, all of that is basically working - loading my iFrame and styling the div.
The problem is that I am not satisfied with the result.
I have tried two different styles for the div:
Approach 1: float right
I used this CSS:
float: right;
height: 100%;
width: 100px;
The problem with this is that it doesn't change the total width of the rest of the page. In other words, elements on the website with a width: 100% will be shown below my sidebar.
https://jsfiddle.net/DHilgarth/mmzefm14/
Approach 2: Absolute positioning
I used this CSS:
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100px;
This approach has the problem that my sidebar now simply overlaps the controls from the website.
https://jsfiddle.net/DHilgarth/34hmnw9h/1/
Is there a way to achieve what I want? A sidebar that basically reduces the available size of the body for all elements, except mine?
I have now chosen to actually do exactly what I asked for: I reduce the available width of the body tag.
This is not trivial because of box-sizing, padding, margin, border etc and I am sure I have missed a lot of edge cases but for now, the following logic is working for me:
If box-sizing is border-box: set the right padding of the body element to the width of my sidebar.
Otherwise, set the width of the body element to the width of the body element minus the width of the sidebar. On resize of the window, the width of the body has to be adjusted accordingly.
Code:
function initSidebar() {
loadSidebar("sidebar");
}
// This code would be loaded from a javascript file I provide
function css(element, property) {
return window.getComputedStyle(element, null).getPropertyValue(property);
}
function getSidebarWidth(sidebarElement) {
var boundingRect = sidebarElement.getBoundingClientRect();
return boundingRect.right - boundingRect.left;
}
function styleBorderBoxBody(bodyElement, sidebarElement) {
bodyElement.style.paddingRight = getSidebarWidth(sidebarElement) + "px";
}
function resizeBody(bodyElement, previousWindowWidth, previousBodyWidth) {
var currentWindowWidth = window.innerWidth;
var newBodyWidth = previousBodyWidth - previousWindowWidth + currentWindowWidth;
bodyElement.style.width = newBodyWidth + "px";
return {currentWindowWidth, newBodyWidth};
}
function styleBody(bodyElement, sidebarElement) {
var boxSizing = css(bodyElement, "box-sizing");
if(boxSizing == "content-box" || !boxSizing || boxSizing == "") {
var sidebarWidth = getSidebarWidth(sidebarElement);
var width = bodyElement.clientWidth - sidebarWidth;
bodyElement.style.width = width + "px";
sidebarElement.style.right = (-sidebarWidth) + "px";
var windowWidth = window.innerWidth;
window.addEventListener("resize", function(e) {
var newWidths = resizeBody(bodyElement, windowWidth, width);
width = newWidths.newBodyWidth;
windowWidth = newWidths.currentWindowWidth;
});
} else if(boxSizing == "border-box") {
styleBorderBoxBody(bodyElement, sidebarElement);
window.addEventListener("resize", function(e) { styleBorderBoxBody(bodyElement, sidebarElement); });
}
}
function loadSidebar(sidebarId) {
var sidebarElement = document.getElementById(sidebarId);
sidebarElement.className = "sidebar";
var bodyElement = document.getElementsByTagName("body")[0];
styleBody(bodyElement, sidebarElement);
}
// end: my code
initSidebar();
* {
margin: 0;
padding: 0;
}
html {
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
font: 14px/1.1 Helvetica, Sans-Serif;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
}
#editor {
width: 100%;
height: 500px;
}
/* this class would be loaded from a CSS file I provide */
.sidebar {
border-color: green;
border-style: solid;
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 100px;
}
<div id="sidebar"></div>
<h1>Some UI from the existing website</h1>
<textarea id="editor">The text area</textarea>

how to disable dragend animation in html5

I created a draggable element by setting its draggable attribute. When I drop the element, there is an animation of the element snapping back to its origin position:
How can the snap-back animation be disabled? I tried calling preventDefault() on the dragend event, but it had no effect on the animation.
The following snippet shows the basics:
document.getElementById('test').addEventListener(
'dragend', evt => {
evt.preventDefault();
}
);
#container {
border: 1px solid black;
min-width: 300px;
min-height: 200px;
position: relative;
}
#test {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
top: 25px;
left: 40px;
}
<div id="container">
<div id="test" draggable='true'></div>
</div>
Not every browser will show the dragged #test jumping back to the original position.
In order to prevent the animation, you need the drop event to fire. For the drop event to fire, you need to call preventDefault() in the handler for dragover.
document.addEventListener('dragover', function(e) { e.preventDefault() })
Example in MDN docs shows the same thing: https://developer.mozilla.org/en-US/docs/Web/Events/drop#Example
An old blog post describing the quirks of HTML5 Drag and Drop API: https://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
As was said earlier, you need to explicitly describe onDragOver handler on the parent's container (where you will drop your draggable element) and put .preventDefault() on event to prevent this animation.
Here is a simple React code example for better understanding of this mechanic (you can position the box inside the container by dragging it):
App.jsx
import './App.css'
const App = () => {
function handleDragOver(e) {
e.preventDefault()
}
function handleDrop(e) {
let box = document.getElementById('box')
if (box) {
box.style.top = e.clientY + 'px'
box.style.left = e.clientX + 'px'
}
}
return (
<div className="container" onDragOver={handleDragOver} onDrop={handleDrop}>
<div id="box" draggable></div>
</div>
)
}
export default App
App.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
position: relative;
}
#box {
width: 100px;
height: 100px;
background-color: lightgreen;
position: absolute;
}

How to hide overlay on Click outside a class

I have a html like
<button id="reporting"></button>
<ul class="showHideChkBox">
<li><label><input name="rptHeaders" type="checkbox"><span>Name</span></label></li>
<li><label><input name="rptHeaders" type="checkbox"><span>Client ID</span></label></li>
<li><label><input name="rptHeaders" type="checkbox"><span>Document Name</span></label></li>
</ul>
On click on the button I have popup the Ul class named showHideChkBox.
on the same time I append a overlay to ul
$('<div class="divOpcty"></div>').insertBefore('.showHideChkBox');
CSS
.divOpcty {
bottom: 0;
right: 0;
opacity: .1;
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: #000;
z-index: 1100;
}
the overlay is working but I can't remove this overlay class when click any where on the window except click in the ul li checkbox.
I tried
$('html').on("click", rptRemoveOverlay);
function rptRemoveOverlay() {
if (RPT_Action == 1) {
RPT_Action = 2;
} else {
$(".divOpcty").fadeOut('slow', function () {
$(this).remove();
$('.showHideChkBox').fadeToggle(1000);
});
RPT_Action = 1;
}
}
but here when click on the checkbox the showHideChkBox also hiding.
my need is when click on the button the ul li chceckbox list is showing and also the overlay is showing.and when click any where out side Ul the ul will hide and also the overlay will hide.
thanks in advance