Edge browser caret positioning on touch device - javascript

I'm working on a web app which uses simple-keyboard javascript library.
By looking at the source code, I can see that the library synchronizes its internal keyboard buffer and caret position with the input field's ones by executing some sync code (selectionStart) on certain events: keyup, mouseup, touchend.
https://github.com/hodgef/simple-keyboard/blob/master/src/lib/components/Keyboard.js#L574
On a touch device and only in Edge browser, there is an issue with it. The problem is that Edge doesn't seem to allow placing the caret by clicking somewhere within the bounds of the text, but allows the user to drag the caret cursor.
This 'dragging' doesn't seem to fire touchend event, so the input's cursor and virtual keyboard caret go out of sync.
Does anyone know if I can prevent this dragging behaviour in Edge (and allow positioning within the text with a simple touch) or if there is some Edge specific event for dragging the cursor?
Example:
/**
* This seems to work in any browser **Except** on a touch device in Edge browser
*/
document.addEventListener("keyup", caretEventHandler);
document.addEventListener("mouseup", caretEventHandler);
document.addEventListener("touchend", caretEventHandler);
function caretEventHandler(event) {
let targetTagName;
if (event.target.tagName) {
targetTagName = event.target.tagName.toLowerCase();
}
if (targetTagName === "textarea" || targetTagName === "input") {
document.querySelector(".selectionStart span").innerHTML =
event.target.selectionStart;
}
}
body {
font-family: sans-serif;
margin: 0;
}
input {
width: 100%;
height: 50px;
text-align: left;
padding-left: 10px;
}
.selectionStart {
padding: 10px;
}
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
<link href="src/styles.css" rel="stylesheet" />
</head>
<body>
<input
class="input"
value="Click anywhere in this string to get selectionStart"
/>
<div class="selectionStart">selectionStart: <span></span></div>
<script src="src/index.js"></script>
</body>
</html>

Related

Drag doesn't work after mouseup in scope of drop container (Chrome, Edge)

When an element is dragged around and dropped somewhere in the page, the next element should have the same dragging behaviour as the first element.
I decided to implement the dragging with mouseevents instead of the drag and drop API. The dragged element should be rotatable during the dragging process with press on a button and this is not possible with the drag and drop API.
The problem happens if an element is dragged to the socpe of the drop container and the mouseup event happens in this scope. When the next element is dragged it isn't dragged as expected. There appears a grabbing cursor instead of a mouse cursor and the element doesn't follow the cursor. (In Chrome and Edge, in Firefox everything's fine)
Everything works as expected if an element is dragged over scope of the drop container and the mouseup event gets fired outside the scope.
Here is a link to a gif where you can see the problem.
The problem happens in Chrome and Edge, but not in Firefox. There is a mouseevent feature not supported in Chrome/Edge but in Firefox: "Support for mouseEventInit optional region field". Enabling "Experimental Web Platform Features" in Chrome still didn't solve the problem.
Checking the events in Chrome developer tools and Firefox Developer Tools one difference is that the offsetX and offsetY is in Firefox "0" but in Chrome a value is assigned. Don't know if this points to the potential issue.
How can the right dragging behaviour can be also implemented for Chrome and Edge?
const dragContainer = document.querySelector('#drag-container')
const dropContainer = document.querySelector('#drop-container')
const element1 = document.querySelector('#element-1')
const element2 = document.querySelector('#element-2')
makeElementDraggable(element1)
makeElementDraggable(element2)
function makeElementDraggable(element) {
element.addEventListener('mousedown', startDrag)
// Regards to: https://javascript.info/mouse-drag-and-drop
function startDrag(ev) {
element.style.position = 'absolute'
element.style.zIndex = 1000
document.body.append(element)
moveAt(ev.pageX, ev.pageY)
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', reset)
}
function onMouseMove(ev) {
moveAt(ev.pageX, ev.pageY)
}
function moveAt(pageX, pageY) {
element.style.left = pageX + 10 + 'px'
element.style.top = pageY + 'px'
}
function reset() {
document.removeEventListener('mousemove', onMouseMove)
element.removeEventListener('mousedown', startDrag)
}
}
#drag-container {
width: 250px;
height: 500px;
border: 1px solid black;
}
#element-1 {
background-color: aqua;
width: 250px;
height: 50px;
}
#element-2 {
background-color: blueviolet;
width: 200px;
height: 50px;
}
#drop-container {
height: 500px;
width: 500px;
border: 1px solid black;
}
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="drag-container">
<div id="element-1"></div>
<div id="element-2"></div>
</div>
<div id="drop-container"></div>
<script src="script.js"></script>
</body>
</html>

conflicting value for pageY on Ipad

I am testing a page on an IPad (IOS 14.3) in portrait mode . (see code below)
I am outputting the touched Y-value of the screen.
When I tap the screen near the top the output is near 0 (depending on the thickness of finger).
When I tap the screen near the bottom the output is near 1000.
However when I swipe vertically from the top to bottom the values start from 0 but when I reach the bottom with my finger it stops near 600.
The same issue in the other directory, when I start at the bottom is shows a value around 1000 and when it reaches the top is stops around 300.
It almost seems there are missing 300px in each (vertical) direction.
Note: the X-value (horizontal swipes) is accurate, hence I've excluded it in this example. Also on Android the output from the console.log seems fine.
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1.0, user-scalable=yes">
<style>
body,
html {
position: fixed;
width: 100%;
height: 100%;
margin: 0;
padding 0;
background-color: #AAAAAA;
}
</style>
</head>
<body>
<div style='text-align:center;font-size:25px;width:100px;border:1px solid blue;margin:auto' id='feedback'>Hello</div>
</body>
</html>
<script>
var func = function (e) {
var evt = (typeof e.originalEvent === 'undefined') ? e : e.originalEvent;
var touch = evt.touches[0] || evt.changedTouches[0];
document.getElementById('feedback').textContent = 'top:'+touch.pageY;
};
document.body.addEventListener('touchstart', func);
document.body.addEventListener('touchmove', func);
document.body.addEventListener('touchend', func);
</script>
What is the reason the with swipping vertically I am getting different results than when I touch the screen?
It was solved by changing
document.getElementById('feedback').textContent = 'top:'+touch.pageY;
into
document.getElementById('feedback').textContent =
'top:'+touch.clientY;
Although I don't quite see why these would differ in this case.

javascript oninput: press onekey multiple event fired

i'm just starting a typing text project not for english typing text. it's only for Bengali language. my typing project is 99% done for english language but in Bengali language i found a tiny but a big problem.
i have a input box that will match all the word one by one. you type a word and press space it will check the word for matching and after that move for the next word. it's work fine.
how i check that:in inputbox oninput event event.data === " " than move to the next word.
but in Bengali language when i press the key "c" (not as first character but in the middle of word first character) its fired the oninput event multiple time. with various event.data value include the space also. that's why when press c in keyboard its just go to the next word.
now you cannot find out the multiple event in the console because you don't have the software in your machine. so for that i include a screen short of this:
see_the_picture_for_butter_understanding
onkeyup event problem: see_the_picture
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
#font-face {
font-family: 'SutonnyMj';
src: url('assets/fonts/SutonnyMj.ttf'),
url('assets/fonts/sutonnymj.woff2') format('woff2'),
url('assets/fonts/sutonnymj.woff') format('woff');
font-weight: normal;
font-style: normal;
}
#textbox {
width: 200px;
height: 200px;
font-family: 'SutonnyMj';
font-size: 50px;
}
</style>
<body>
<textarea id="textbox" type="text"></textarea>
<script>
var textBox = document.getElementById("textbox");
textBox.oninput = function(e) {
console.log(event); // multiple event fire when the Software is Enable
if(event.data === " ") {
// move_to_the_next_word();
}
}
</script>
</body>
</html>
Notes: It's happen because i use a software called Bijoy Bangla for writing Bengali. (It's require for Bengali Typing Test)
As mentioned by #Ahmad 'input' event is fired after each change, but you can be more specific using 'keyup' event which will provide you more control and attributes for event object. For example you will be able to handle 'Space' using event.which statement. Here an example:
var textBox = document.getElementById("textbox");
textBox.onkeyup = function(e) {
console.log(event);
if(event.which === 32) { //space keycode
// move_to_the_next_word();
}
}
Try this!
function runScript(e) {
if (e.keyCode == 67) {//c
console.log("you have entred 'c' char")
}
if(e.keyCode == 32){//space
console.log("space ")
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<input id="scriptBox" type="text" onkeyup="return runScript(event)" />

Detecting mousewheel with onscroll

I tried by several ways to detect accurately mousewheel / DOMMouseScroll event, but it seems that the result will vary much from browser to another browser, and above all from hardware to another hardware. (ex: MacBook Magic Trackpad fires many mousewheel events, etc.)
There has been many attempts of JS library to "normalize" the wheelDelta of a mousewheel event. But many of them failed (I don't find the relevant SO question anymore but there are some that point this failure).
That's why I try now a solution without the mousewheel event, but rather onscroll event. Here is an example of scrolling / mousewheel detection with a hidden container that scrolls (#scroller), and the normal container (#fixed_container) with normal content.
As #scroller has a finite height (here 4000px), I cannot detect scrolling / mousewheel
infinitely...
How to allow endless scroll events (by setting an infinite height for #scroller? how?) ?
Code / Live demo :
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
body { overflow:hidden; }
#scroller { height: 4000px; }
#fixed_container { position:fixed; top:0px; left:0px; }
#text { position:absolute; top:100px; left:100px; }
</style>
<script type="text/javascript">
window.onscroll = function(e) {
console.log("scroll event detected! " + window.pageXOffset + " " + window.pageYOffset);
e.preventDefault();
return false;
}
</script>
</head>
<body>
<div id="scroller"></div>
<div id="fixed_container">
<div id="text">
Bonjour
</div>
</div>
</body>
</html>
"How to allow endless scroll events"
This should do it:
$(window).scroll(function() {
var st= $(window).scrollTop();
var wh= $(window).height();
var sh= $('#scroller').height();
if(sh < st+wh*2) {
$('#scroller').css({
height: st+wh*2
});
};
});
Tested in IE11, Firefox, Chrome, Opera, and Safari.
In the fiddle below, clicking adds text, so you can see it scroll:
Fiddle

Click Element isn't showing/hiding properly

I have an issue with my code, I'm trying to create a function to hide and show a div
and it's working, but it dosnt work at first, It works only on the second click, so i have to click the link first to get it to start working properly, how can i fix it so that it works on first click?
more info:
im trying to have a div appear and then disapear usin the display and hide functions, the catch is i also want it to disapper when im outside of the div, if its visible, its all working but the problem is when i first load the page thn click the link to display the div, it dosnt appear, only when i click it a second time does it appear. this is the problem i want to fix
this is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="js/jquery.foggy.min.js"></script>
<style>
body {
background: black;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
background-size: 100%;
color: white;
font-family: 'Segoe UI';
font-size: 24px;
}
.box
{
width: 100%;
margin: auto;
top: 0px;
left: 20%;
right: 0px;
bottom: 0px;
background-color: white;
opacity: 0.4;
position: fixed;
overflow-y: scroll;
overflow-x: scroll;
}
</style>
</head>
<body>
<script lang="en" type="text/javascript">
$(document).ready(function () {
});
$(document).mouseup(function (e) {
var container = $("#boxwrapper");
if (!container.is(e.target) && container.has(e.target).length === 0) {
if (container.is(':visible'))
Hide();
}
});
function Display() {
$("#boxwrapper").show();
$("#boxwrapper").addClass("box");
$("#main").foggy();
}
function Hide() {
$("#boxwrapper").hide();
$("#main").foggy(false);
}
</script>
<div id="main">
Display Div
</div>
<div id="boxwrapper">
</div>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>
Why don't you use click() method insead of mouseup()?
$('a').click(function (e) {
var container = $("#boxwrapper");
if (container.is(':visible')) {
Hide();
} else {
Display();
}
return false;
});
If you don't want to bind this event to every <a> on your site, add class to your element and bind click to this class. E.g.:
Display Div
and then in your script:
$('a.divToggle').click(function (e) { });
See this working fiddle
JavaScript
function display() {
if ($('#boxwrapper ').css('display') === 'none') {
$('#boxwrapper').show();
} else {
$('#boxwrapper').hide();
}
}
The issue could be a whitespace or anything, since is very hard to reproduce it, but here some advices or things that could be causing the issue:
Organize your code
First of all, you need to organize your code and load the JS libraries at the end of the file or wrap your functions inside the $(document).ready.
If you are using jQuery already, why to use the onClick event on the element itself if you can do it with jQuery.
Instead of all code inside the document mouseUp event, you could just add display: none in the css to #boxwrapper.
Instead of Hide() and Show() functions, you could just use toogleClass('box') jquery function
Difference between Click and MouseUp events
With a mouseup event, you can click somewhere else on the screen, hold down the click button, and move the pointer to your mouseup element, and then release the mouse pointer. A click event requires the mousedown and mouseup event to happen on that element.
Prevent Default Maybe?
You are not preventing Default on your click event. You can do it like:
Display Div

Categories

Resources