How to move textfield up when keyboard appears - html

In my website textfield not focusing up when default android keyboard comes. It hides the textbox. any simple solution for that issue.

there will be position:fixed property (in a div related to the text field) ,which prevents the text field from jumping up ...just disable the position property ... i had the same problem

this is a basic code to scroll page up and down when virtual keyboard appears
JsFiddle Demo
jQuery
var keyboardHeight = 150;
$(document).ready(function() {
$("textarea, input").focusin(function() {
var element = $(this);
var viewportHeight = $(window).height();
var windowScrollTop = $(window).scrollTop();
var offsetTop = element.offset().top - windowScrollTop;
var validOffset = viewportHeight - keyboardHeight;
$("#keyboard").fadeIn();
if(offsetTop <= 0) {
$('html, body').animate({
scrollTop: windowScrollTop + offsetTop
}, 1000);
}
else {
if(viewportHeight > keyboardHeight) {
if(offsetTop > validOffset) {
$('html, body').animate({
scrollTop: windowScrollTop + offsetTop
}, 1000);
}
}
}
});
$("textarea, input").focusout(function() {
$("#keyboard").fadeOut();
});
});
html
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<textarea rows="11"></textarea>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div id="keyboard"></div>
css
body {
background: transparent;
padding-bottom: 150px; /* height of virtual keyboard */
}
textarea {
width: 100%;
background: transparent;
border: solid 1px red;
border-radius: 10px;
color: white;
outline: none;
}
#keyboard {
position: fixed;
width: 100%;
height: 150px;
left: 0;
bottom: 0;
background: rgba(13, 13, 13, 0.5);
display: none;
}

Related

Correctly Increasing The Size Of A Video Camera Without Ruining The Aspect Ratio

I have a web page that displays a video where the user can see them self with the computer's camera.
The issue is the camera is too small and when I make the height and width 400px, the aspect ratio is ruined.
Not only this, but the top camera output fill the entire border.
The following is an image showing this happening:
top-camera
The following is the facial-login.html file:
<!DOCTYPE html>
<html>
<head>
<style>
#video {
border: 1px solid black;
width: 320px;
height: 240px;
}
#photo {
border: 1px solid black;
width: 320px;
height: 240px;
}
#canvas {
display: none;
}
.camera {
width: 320px;
display: inline-block;
}
.output {
width: 320px;
display: inline-block;
}
#startbutton {
display: block;
position: relative;
margin-left: auto;
margin-right: auto;
bottom: 36px;
padding: 5px;
background-color: #6a67ce;
border: 1px solid rgba(255, 255, 255, 0.7);
font-size: 14px;
color: rgba(255, 255, 255, 1.0);
cursor: pointer;
}
.contentarea {
font-size: 16px;
font-family: Arial;
text-align: center;
}
/* .sendButton {
background-color: #4CAF50;
border: none;
color: white;
padding: 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 12px;
} */
.sendButton {
position: absolute;
top: 327px;
text-align: center;
}
</style>
<!--The title of the HTML document.-->
<title>Facial Image Recognition</title>
</head>
<body>
<div class="contentarea">
<h1 align="center">Facial Image Recognition</h1>
<div class="camera">
<video id="video">Video stream not available.</video>
</div>
<!--An id on a <button> tag assigns an identifier to the button.
The id allows JavaScript to easily access the <button> element
and manipulate it.-->
<button id="startbutton">Capture Image</button>
<!--The following button will trigger the JavaScript function.-->
<!-- <button class="sendButton">Submit Facial Image</button> -->
<button class="sendButton">Submit Facial Image</button>
<!--The HTML canvas tag is where the image frames are stored
before they are converted into an image of proper format
to be shown using the <img> tag.-->
<canvas id="canvas"></canvas>
<div class="output">
<img id="photo" alt="The image captured will appear in this box.">
</div>
</div>
<script>
var data;
(function() {
// We will scale the photo width to this.
var width = 400;
// The height will be computed based on the input stream.
var height = 0;
var streaming = false;
var video = null;
var canvas = null;
var photo = null;
var startbutton = null;
function startup() {
video = document.getElementById('video');
canvas = document.getElementById('canvas');
photo = document.getElementById('photo');
/*The following line is executed when a user clicks on the
"Capture Image" button.
document.getElementById returns the element whose 'id'
is 'startbutton'.*/
startbutton = document.getElementById('startbutton');
// Access the video stream from the webcam.
navigator.mediaDevices.getUserMedia({
video: true,
audio: false
})
// Upon success, stream video in a video tag.
.then(function(stream) {
video.srcObject = stream;
video.play();
})
.catch(function(err) {
console.log("An error occurred: " + err);
});
video.addEventListener('canplay', function(ev) {
if (!streaming) {
height = video.videoHeight / (video.videoWidth / width);
if (isNaN(height)) {
height = width / (4 / 3);
}
video.setAttribute('width', width);
video.setAttribute('height', height);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
streaming = true;
}
}, false);
startbutton.addEventListener('click', function(ev) {
takepicture();
ev.preventDefault();
}, false);
clearphoto();
}
/*Collect the frames of the photo from the canvas and then
convert it into a PNG format, so that it can be shown in
the HTML page.*/
function clearphoto() {
var context = canvas.getContext('2d');
context.fillStyle = "#AAA";
context.fillRect(0, 0, canvas.width, canvas.height);
var data = canvas.toDataURL('image/png');
photo.setAttribute('src', data);
}
/*Capture a frame from the video stream.*/
function takepicture() {
var context = canvas.getContext('2d');
if (width && height) {
canvas.width = width;
canvas.height = height;
/*The canvas takes a snapshot of the video.*/
context.drawImage(video, 0, 0, width, height);
/*toDataURL('image/png') returns a data URL containing a
representation of the image in PNG format.
'data' will hold the URL link of each image that is
captured from the camera.*/
data = canvas.toDataURL('image/png');
/*'src' is the name of the attribute whose value is to be set.
'data' is a string containing the value to assign to the attribute.
The data is fed as a source of the image element.*/
photo.setAttribute('src', data);
let facialImageURL = '<img src="'+data+'"/>';
// document.write('<img src="'+data+'"/>');
}else {
clearphoto();
}
}
/*The following code will call the startup() function when
the HTML page is loaded.*/
window.addEventListener('load', startup, false);
})();
var URL = "{% url 'facial-login-result' %}";
/*POST the data (the facial image) to the server via AJAX.*/
function SendFacialImage(){
var facialImage = {'data': data};
$.post(URL, facialImage, function(response){
if(response === 'success')
{
alert('Facial Image Successfully Sent!');
}
else{
alert('Error Sending Facial Image!');
}
});
}
$(document).ready(function(){
$('#sendButton').click(function(){
SendFacialImage();
});
});
</script>
</body>
</html>

Circular window

I have this fiddle.
https://jsfiddle.net/oeuc8L9y/2/
If you click the background the coordinates where you clicked get centered.
Is it possible to make the pointer events only work inside the hole?
Since I'm using an image for the ring the whole thing blocks the pointer-events but if I set it to pointer-events: none; I can click trough the ring too.
This is good.
This is bad.
I assume a way would be to get the pixel coordinate and calculate if it's inside the hole but I feel like that would only work for a specific screen size and it'd break if resized.
tooltip_X = $("#x-coords");
tooltip_Y = $("#y-coords");
$("#background").on("mouseover", (e) => {
showTooltip(e);
});
$("#background").on("mousemove", (e) => {
updateCoords(e);
moveTooltip(e);
});
$("#background").on("mouseout", (e) => {
hideTooltip(e);
});
$("#background").on("click", (e) => {
move(e);
updateCoords(e);
});
function showTooltip(e) {
$("#tooltip").css("display", "block");
}
function hideTooltip(e) {
$("#tooltip").css("display", "none");
}
function moveTooltip(e) {
var left = 0;
var top = 0;
if (e.pageX + $("#tooltip").width() + 10 < document.body.clientWidth) {
left = e.pageX + 10;
} else {
left = document.body.clientWidth + 5 - $("#tooltip").width();
}
if (e.pageY + $("#tooltip").height() + 10 < document.body.clientHeight) {
top = e.pageY + 10;
} else {
top = document.body.clientHeight + 5 - $("#tooltip").height();
}
$("#tooltip").offset({ top: top, left: left });
}
function updateCoords(e) {
var mouse_x = e.clientX - $("#background").offset().left;
var mouse_y = e.clientY - $("#background").offset().top;
$("#x-coords").text(Number.parseInt(mouse_x));
$("#y-coords").text(Number.parseInt(mouse_y));
}
function move(e) {
var mouse_x = e.clientX - $("#background").offset().left;
var mouse_y = e.clientY - $("#background").offset().top;
var new_x = 0;
var new_y = 0;
if (mouse_x < 250) {
mouse_x = 250;
}
if (mouse_y < 250) {
mouse_y = 250;
}
if (mouse_x > 1670) {
mouse_x = 1670;
}
if (mouse_y > 950) {
mouse_y = 950;
}
new_x = -(mouse_x - 250);
new_y = -(mouse_y - 250);
$("#background").css("margin-top", new_y);
$("#background").css("margin-left", new_x);
}
#container {
position: relative;
width: 500px;
height: 500px;
overflow: hidden;
z-index: 100;
}
#ring {
position: absolute;
border-radius: 100%;
max-height: 500px;
max-width: 500px;
z-index: 90;
pointer-events: none;
}
#lens {
position: absolute;
border: 1px solid red;
/*
something to make it round
*/
z-index: 80;
pointer-events: none;
}
#background {
position: absolute;
width: 1920px;
height: 1200px;
background-image: url("https://wallpaperaccess.com/full/197542.jpg");
z-index: 80;
outline: 5px dotted purple;
outline-offset: -5px;
}
#tooltip {
position: absolute;
white-space: nowrap;
background: #ffffcc;
border: 1px solid black;
padding: 5px;
color: black;
z-index: 999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head> </head>
<body>
<div id="container">
<img id="ring" src="https://pngimg.com/uploads/circle/circle_PNG26.png" alt="Lens Ring" />
<div id="lens"></div>
<div id="background"></div>
<span id="tooltip"> Div Coords (<span id="x-coords"></span>,<span id="y-coords"></span>) </span>
</div>
</body>
</html>

How to drag and drop same element multiple times into another div box in JavaScript or jQuery?

I have two HTML div boxes. Let's say box A and box B. I want to drag and drop box A multiple times into box B. If I drop box A outside of box B then box A will revert back to it's original position. After I dropped the box A (clone) into box B I want to move box A (clone) into any position in box B. For now I did the codes to do that.
Now what I want is after I dropped box A into Box B, then if I drag and drop box A (clone) outside of box B, then box A (clone) need to hide or revert into it's original position (box A parent position).
HTML Codes
<div id="boxB"></div>
<br>
<div class="boxA">BOX A</div>
CSS Codes
#boxB {
width: 200px;
border: 5px solid black;
padding: 50px 50px;
margin: auto;
text-align: center;
background-color: #FFFFFF;
}
.boxA {
width: 40px;
border: 2px solid black;
text-align: center;
background-color: #F5D938;
cursor: pointer;
}
JavaScript + jQuery Codes
$(document).ready(function()
{
var x;
$(".boxA").draggable(
{
helper: "clone",
cursor: "move",
revert: true
});
$("#boxB").droppable(
{
accept: ".boxA",
drop: function(event, ui)
{
x = ui.helper.clone();
ui.helper.remove();
x.appendTo('#boxB');
$(x).draggable();
}
});
});
You can see demo : https://jsfiddle.net/zajjith/3kedjgb0/10/
If I drag and drop box A (clone) outside from box B then that clone box A need to revert back to it's original parent box A position or hide or delete.
I hope you understand what I want. Please check my codes and help me.
Refer to the Example at https://jqueryui.com/droppable/#revert
Using your code, you can do the following.
$(function() {
function getBounds(el) {
var p = $(el).position();
p.right = p.left + $(el).width();
p.bottom = p.top + $(el).height();
return p;
}
function isOver(a, b) {
var ap;
if (typeof a == "object") {
ap = a;
} else {
ap = getBounds(a);
}
var bp = getBounds(b);
return (ap.left > bp.left && ap.right < bp.right) && (ap.top > bp.top && ap.bottom < bp.bottom);
}
$(".boxA").draggable({
helper: "clone",
cursor: "move",
revert: "invalid"
});
$("#boxB").droppable({
accept: ".boxA",
drop: function(event, ui) {
var cl = ui.helper.clone();
cl.appendTo(this).draggable({
appendTo: "body",
stop: function(e, ui) {
if (isOver($.extend({}, ui.position, {
right: ui.position.left + ui.helper.width(),
bottom: ui.position.top + ui.helper.height()
}), $("#boxB")) == false) {
var a = getBounds($("body > .boxA"));
ui.helper.animate({
top: a.top,
left: a.left
}, function() {
ui.helper.remove();
});
} else {
console.log("Drop Inside");
}
}
});
ui.helper.remove();
}
});
});
#boxB {
width: 200px;
border: 5px solid black;
padding: 50px 50px;
margin: auto;
text-align: center;
background-color: #FFFFFF;
}
.boxA {
width: 50px;
border: 2px solid black;
text-align: center;
background-color: #F5D938;
cursor: pointer;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="boxB"></div>
<br />
<div class="boxA">BOX A</div>

Contain fixed element within container

Having a flex layout with top, left, middle and right.
Middle is divided into main and foot.
Within the main I want to have fixed elements, kind of like an MDI, as well as static elements.
If one scroll the fixed element should stay in same position of view. But, it should be contained within the main element if it is moved above or to the left of main. As in: not overlap the top, left, right etc.
THIS:
Colors and margins added to make a visual representation of the layout
NOT THIS:
Below is a simplified sample with a container within a container.
If one select the fixed positioning for the sub "window" it stay in place on scrolling, but it overlaps the parent if moved outside.
I can use absolute and reposition it on scroll by using JavaScript, but wondered if there was a pure CSS / layout way to get the same result.
function set_style_pos (e) {
moveable.style.position = e.target.value;
}
function halt (e) {
e.preventDefault();
e.stopPropagation();
}
const drag = {
el: null,
ex: 0,
ey: 0,
xs: 0,
ys: 0,
move: function (e) {
halt(e);
drag.el.style.marginLeft = (e.clientX - drag.sx + drag.ex) + 'px';
drag.el.style.marginTop = (e.clientY - drag.sy + drag.ey) + 'px';
},
end: function (e) {
halt(e);
window.removeEventListener('mouseup', drag.end);
window.removeEventListener('mousemove', drag.move);
},
start: function (e) {
let cs;
halt(e);
window.addEventListener('mouseup', drag.end);
window.addEventListener('mousemove', drag.move);
drag.el = e.target;
cs = getComputedStyle(drag.el);
drag.ex = parseInt(cs.getPropertyValue('margin-left')) || 0;
drag.ey = parseInt(cs.getPropertyValue('margin-top')) || 0;
drag.sx = e.clientX;
drag.sy = e.clientY;
},
check: function (e) {
let t = e.target;
if (t.dataset.moveable == "1")
drag.start(e);
}
};
document.addEventListener('mousedown', drag.check);
document.addEventListener('change', set_style_pos);
lines.textContent = "scroll me\n".repeat(100);
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
flex-direction: column;
color: #444;
font: 14px sans-serif;
}
label {
cursor: pointer;
}
.outer {
display: flex;
padding: 20px;
background: goldenrod;
flex-grow: 1;
overflow: hidden;
}
.inner {
position: relative;
overflow: scroll;
background: gray;
flex-grow: 1;
}
.box {
position: absolute;
width: 140px;
height: 150px;
background: silver;
box-shadow: 0 0 3px red;
cursor: move;
margin-left: 90px;
margin-top: -5px;
padding: 20px;
}
.box div {
font-weight: 700;
pointer-events: none;
text-align: center;
}
<div class="outer">
<div class="inner">
<div class="box" id="moveable" data-moveable="1">
<div>Move Me</div><br />
<label><input type="radio" name="p" value="absolute" checked />absolute</label><br />
<label><input type="radio" name="p" value="fixed" />fixed</label>
</div>
<pre id="lines"></pre>
</div>
</div>
Just use z-index.
Example:
function set_style_pos (e) {
moveable.style.position = e.target.value;
}
function halt (e) {
e.preventDefault();
e.stopPropagation();
}
const drag = {
el: null,
ex: 0,
ey: 0,
xs: 0,
ys: 0,
move: function (e) {
halt(e);
drag.el.style.marginLeft = (e.clientX - drag.sx + drag.ex) + 'px';
drag.el.style.marginTop = (e.clientY - drag.sy + drag.ey) + 'px';
},
end: function (e) {
halt(e);
window.removeEventListener('mouseup', drag.end);
window.removeEventListener('mousemove', drag.move);
},
start: function (e) {
let cs;
halt(e);
window.addEventListener('mouseup', drag.end);
window.addEventListener('mousemove', drag.move);
drag.el = e.target;
cs = getComputedStyle(drag.el);
drag.ex = parseInt(cs.getPropertyValue('margin-left')) || 0;
drag.ey = parseInt(cs.getPropertyValue('margin-top')) || 0;
drag.sx = e.clientX;
drag.sy = e.clientY;
},
check: function (e) {
let t = e.target;
if (t.dataset.moveable == "1")
drag.start(e);
}
};
document.addEventListener('mousedown', drag.check);
document.addEventListener('change', set_style_pos);
lines.textContent = "scroll me\n".repeat(100);
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
flex-direction: column;
color: #444;
font: 14px sans-serif;
}
label {
cursor: pointer;
}
.outer {
display: flex;
padding: 20px;
background: goldenrod;
/*flex-grow:1; Disable to control the height for presentaion*/
height:200px !important;
overflow:hidden; /*to hide scrollme lines*/
}
.inner {
position: relative;
overflow: scroll;
background: gray;
flex-grow: 1;
}
.box {
position: absolute;
width: 140px;
height: 150px;
background: silver;
box-shadow: 0 0 3px red;
cursor: move;
margin-left: 90px;
margin-top: -5px;
padding: 20px;
}
.box div {
font-weight: 700;
pointer-events: none;
text-align: center;
}
.prevent{
width:200px;
height:200px;
display:flex;
background-color:blue;
color:white;
justify-content:center;
align-items:center;
font-weight:bold;
/*--The solution--*/
z-index:1;
}
<div class="outer">
<div class="inner">
<div class="box" id="moveable" data-moveable="1">
<div>Move Me</div><br />
<label><input type="radio" name="p" value="absolute" checked />absolute</label><br />
<label><input type="radio" name="p" value="fixed" />fixed</label>
</div>
<pre id="lines"></pre>
</div>
</div>
<div class="prevent">
Prevent overlap
</div>
I hope this helps.
Use a sticky container and let children be absolute.
Had tested with z-index, all over, before posting but had not found any satisfactory solution that way.
I also tried various with position: sticky, and there is where I found the solution at last :)
One can wrap the sub windows in a sticky container which is positioned top left of the main container.
Pros:
Simple
Fairly clean HTML structure
The window stay below scroll-bars of container
Positioning relative to content wrapper
Cons:
If one want to make it non-fixed / non-sticy one have to move the element to parent and vice versa.
Absolute positioned children will not expand the container – thus not rearranging the DOM flow. (Which was the issue on earlier attempts using sticky).
Tested in FireFox, Chrome, Vivaldi, Opera Mini and Opera.
The core of it:
<div class="outer">
<div class="main">
<div class="wrap-sticky">
<div class="sub-window">
Fixed Window
</div>
</div>
Other "normal" content
</div>
</div>
And:
.outer {
overflow: hidden;
}
.main {
position: relative;
overflow: scroll;
}
.wrap-sticky {
position: sticky;
top: 0;
left: 0;
}
.sub-window {
position: absolute;
}
function get_pos (el) {
let cs = getComputedStyle(el);
return [
parseInt(cs.getPropertyValue('left')) || 0,
parseInt(cs.getPropertyValue('top')) || 0
];
}
function set_style_pos (e) {
let [x, y] = get_pos (moveable);
if (e.target.value == "sticky") {
wrap_sticky.appendChild(moveable);
moveable.style.left = (x - inner.scrollLeft) + 'px';
moveable.style.top = (y - inner.scrollTop) + 'px';
} else {
inner.appendChild(moveable);
moveable.style.left = (x + inner.scrollLeft) + 'px';
moveable.style.top = (y + inner.scrollTop) + 'px';
}
}
function halt (e) {
e.preventDefault();
e.stopPropagation();
}
const drag = {
el: null,
ex: 0,
ey: 0,
xs: 0,
ys: 0,
move: function (e) {
halt(e);
drag.el.style.left = (e.clientX - drag.sx + drag.ex) + 'px';
drag.el.style.top = (e.clientY - drag.sy + drag.ey) + 'px';
},
end: function (e) {
halt(e);
window.removeEventListener('mouseup', drag.end);
window.removeEventListener('mousemove', drag.move);
},
start: function (e) {
halt(e);
window.addEventListener('mouseup', drag.end);
window.addEventListener('mousemove', drag.move);
drag.el = e.target;
[drag.ex, drag.ey] = get_pos(drag.el);
drag.sx = e.clientX;
drag.sy = e.clientY;
},
check: function (e) {
let t = e.target;
if (t.dataset.moveable == "1")
drag.start(e);
}
};
document.addEventListener('mousedown', drag.check);
document.addEventListener('change', set_style_pos);
lines.textContent = "scroll me\n".repeat(100) + "horiz".repeat(100) + 'END';
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
flex-direction: column;
color: #444;
font: 14px sans-serif;
}
label {
cursor: pointer;
}
.outer {
display: flex;
padding: 20px;
background: goldenrod;
flex-grow: 1;
overflow: hidden;
}
.inner {
position: relative;
overflow: scroll;
background: gray;
flex-grow: 1;
}
.box {
position: absolute;
width: 160px;
height: 100px;
background: silver;
box-shadow: 0 0 3px red;
cursor: move;
padding: 20px;
top: 20px;
left: 20px;
}
.box div {
font-weight: 700;
pointer-events: none;
text-align: center;
}
.wrap-sticky {
position: sticky;
top: 0;
left: 0;
}
<div class="outer">
<div class="inner" id="inner">
<div class="wrap-sticky" id="wrap_sticky">
<div class="box" id="moveable" data-moveable="1">
<div>Drag & Move Me</div>
<label><input type="radio" name="p" value="sticky" checked />In sticky</label><br />
<label><input type="radio" name="p" value="absolute" />In main</label>
</div>
</div>
<pre id="lines"></pre>
</div>
</div>

Allow select text on a HTML 5 draggable child element

Having a table with draggable rows where each row is draggable=true, how can the user still be able to select text from a column?
<table>
<thead>..</thead>
<tbody>
..
<tr draggable="true">
<td>..</td>
<td>Cool text but you can't select me</td>
<td>..</td>
</tr>
..
</tbody>
</table>
Another simple example (https://codepen.io/anon/pen/qjoBXV)
div {
padding: 20px;
margin: 20px;
background: #eee;
}
.all-copy p {
-webkit-user-select: all; /* Chrome all / Safari all */
-moz-user-select: all; /* Firefox all */
-ms-user-select: all; /* IE 10+ */
user-select: all; /* Likely future */
}
<div class="all-copy" draggable="true">
<p>Select me as text</p>
</div>
There are two things we need to do.
One thing is limitting the drag event only trigger on specified area, for example, the drag handle.
The other thing is that we only set the text on the div with content class can be selected. The reason why we do so is that the element that has been set to draggable, on which browser will add a default rule user-select: none.
const itemEl = document.querySelector('.item');
const handleEl = document.querySelector('.handle');
let mouseDownEl;
itemEl.onmousedown = function(evt) {
mouseDownEl = evt.target;
}
itemEl.ondragstart = function(evt) {
// only the handle div can be picked up to trigger the drag event
if (mouseDownEl.matches('.handle')) {
// ...code
} else {
evt.preventDefault();
}
}
.item {
width: 70px;
border: 1px solid black;
text-align: center;
}
.content {
border-top: 1px solid gray;
user-select: text;
}
<div class="item" draggable="true">
<div class='handle'>handle</div>
<div class='content'>content</div>
</div>
One way to make that work, is to actually check which element fired the event, e.target, against the element that has the listener attach to itself, #draggable (in this case using this).
if (e.target === this) {...}
This will allow default behavior on element positioned inside the draggable element, such as selecting a text and so on.
Note, since Firefox has issue with draggable="true", I used a different drag method.
Stack snippet
(function (elem2drag) {
var x_pos = 0, y_pos = 0, x_elem = 0, y_elem = 0;
document.querySelector('#draggable').addEventListener('mousemove', function(e) {
x_pos = e.pageX;
y_pos = e.pageY;
if (elem2drag !== null) {
elem2drag.style.left = (x_pos - x_elem) + 'px';
elem2drag.style.top = (y_pos - y_elem) + 'px';
}
})
document.querySelector('#draggable').addEventListener('mousedown', function(e) {
if (e.target === this) {
elem2drag = this;
x_elem = x_pos - elem2drag.offsetLeft;
y_elem = y_pos - elem2drag.offsetTop;
return false;
}
})
document.querySelector('#draggable').addEventListener('mouseup', function(e) {
elem2drag = null;
})
})(null);
#draggable {
display: inline-block;
background: lightgray;
padding:15px;
cursor:move;
position:relative;
}
span {
background: white;
line-height: 25px;
cursor:auto;
}
<div id="draggable">
<span>Select me as text will work<br>when the mouse is over the text</span>
</div>