"touchend" event partly not working on iphone mobile browser - javascript

On the mobile version of the website I have made, I use a javascript file to handle the tap of a user to open up the side display.
What I wanted to do was if a user presses the side display it should expand, if the touch area is not the side display shrink back to the original state.
It is currently working on samsung browsers, I have also tried on iphones using a chrome and safari browser and it expands when pressed on the side display but only closes when I press the button located on the lower right hand corner. The areas excluding the side navigation and the background do not initiate the div to return to original state.
Here is my javascript code for handling touch events:
document.getElementById('side_box').addEventListener('touchend', function(event){
var touchobj = event.changedTouches[0] // reference first touch point for this event
const vals = document.getElementById('val-display');
const lst_elem = document.getElementsByClassName('list-element');
const arrow = document.getElementById('arrow');
if(screen && screen.width < 480) {
if (event.target === this || event.target === arrow) {
this.style.opacity = "0.7";
this.style.width = "200px";
vals.style.opacity = "0";
arrow.style.display = "none";
for (let i = 0; i < lst_elem.length; i++) {
lst_elem[i].style.visibility = "visible";
}
} else {
this.style.opacity = "0.3";
this.style.width = "50px";
vals.style.opacity = "1";
arrow.style.display = "block";
for (let i = 0; i < lst_elem.length; i++) {
lst_elem[i].style.visibility = "hidden";
}
}
}
event.preventDefault();
}, false);
The if statement is currently working perfect but there is a problem in the else not initiating when pressed anywhere else except the side display.
You can also check the problem by going on andy.serra.us on your mobile.
Thanks for the help in advance.

Related

Vanilla Javascript change image when in mobile view

How can I change my logo into white when in mobile? But I already have below code for on scroll I am using vanilla javascript. I have the dark and light logo. Its working when on scroll but don't know how to add script for width mobile
addEventListener('scroll', (event) => { });
onscroll = (event) => {
const logoDark = document.querySelector('.nav-logo');
const logoLight = document.querySelector('.nav-logo-light');
logoDark.classList.add("show");
logoLight.classList.add("hide");
if (window.scrollY > 100) {
logoDark.classList.add("hide");
logoLight.classList.add("show");
for (let i = 0; i < navItems.length; i++) {
navItems[i].classList.add('light-text');
}
}
else if (window.scrollY < 100) {
logoDark.classList.remove('hide');
logoLight.classList.remove("show");
}
};
You can use media-query in javascript can also be used in CSS as well
Here's a snippet:
function scrollFunction(isMobile) {
if (!isMobile) {
// If this is a desktop screen add your logic for desktop
} else {
// else if this is a mobile screen add logic for mobile
}
}
var matchMedia = window.matchMedia("(max-width: 400px)") // or whatever you consider mobile width for your use case.
scrollFunction(matchMedia.matches) // Call listener function at run time
matchMedia.addListener(myFunction) // Attach listener function on state changes

How do I add 'keyup' to my code to move my gallery slideshow left and right using the keyboard buttons?

This is my first question on here (and my first ever project!)
I'm trying to add 'keyup' functionality (or something similar) to my image gallery slideshow to allow my slideshow to move left and right upon hitting the left or right button on the keyboard.
At the moment, I'm using CSS keyframes to move my images with a left/right button, but I also have used a timer to play/pause them.
Here is what my code looks like (minus the timer):
var indexOfSlides,slides,dots,captionText;
function startSlides(){
indexOfSlides = 0;
slides=document.getElementsByClassName("slide");
slides[indexOfSlides].style.opacity=1;
captionText=document.querySelector(".captionTextHolder .captionText");
captionText.innerText=slides[indexOfSlides].querySelector(".captionText").innerText;
//disable nextPrevBtn if slide count is one
if(slides.length<2){
var nextPrevBtns=document.querySelector(".leftArrow,.rightArrow");
nextPrevBtns.style.display="none";
for (i = 0; i < nextPrevBtn.length; i++) {
nextPrevBtn[i].style.display="none";
}
}
}
startSlides();
function addSlides(n) {
slideMover(indexOfSlides+n);
}
function slideMover(n){
var i;
var current,next;
var slideMoverAnimClass={
forCurrent:"",
forNext:""
};
var slideTextAnimClass;
if(n>indexOfSlides) {
if(n >= slides.length){n=0;}
slideMoverAnimClass.forCurrent="moveLeftCurrentSlide";
slideMoverAnimClass.forNext="moveLeftNextSlide";
slideTextAnimClass="slideTextFromTop";
}else if(n<indexOfSlides){
if(n<0){n=slides.length-1;}
slideMoverAnimClass.forCurrent="moveRightCurrentSlide";
slideMoverAnimClass.forNext="moveRightPrevSlide";
slideTextAnimClass="slideTextFromBottom";
}
if(n!=indexOfSlides){
next = slides[n];
current=slides[indexOfSlides];
for (i = 0; i < slides.length; i++) {
slides[i].className = "slide";
slides[i].style.opacity=0;
dots[i].classList.remove("active");
}
current.classList.add(slideMoverAnimClass.forCurrent);
next.classList.add(slideMoverAnimClass.forNext);
dots[n].classList.add("active");
indexOfSlides=n;
captionText.style.display="none";
captionText.className="captionText "+slideTextAnimClass;
captionText.innerText=slides[n].querySelector(".captionText").innerText;
captionText.style.display="block";
}
}
Does anyone know how I could go about adding keyup to this to move the images left/right using the keyboard? Any help would be much appreciated!
you could simply add key up event listener.
window.addEventListener('keyup', (e) => {
// assuming the indexOfSlides is the index of current slide and slide mover is the function to move to a specific slide
if(e.which == 37){
slideMover(indexOfSlides - 1);
}else if(e.which == 39){
slideMover(indexOfSlides + 1);
}
})

Detecting the opening or closing of a virtual keyboard on a touchscreen device

I have an inelegant workaround for this issue, and am hoping that others may already have more robust solutions.
On a touchscreen, tapping on an editable text field will bring up an on-screen keyboard, and this will change the amount of screen space available. Left untreated, this may hide key elements, or push a footer out of place.
On a laptop or desktop computer, opening an editable text field creates no such layout changes.
In my current project, I want to ensure that certain key items are visible even when a virtual keyboard is open, so I need to detect when such a change occurs. I can then add a class to the body element, to change the layout to suit the presence of the keyboard.
When searching for existing solutions online, I discovered that:
There is no perfect way of knowing that your code is running on a mobile device
There are non-mobile devices that have touchscreens, and which may also have keyboards
A focus element may not be editable
contentEditable elements will open the on-screen keyboard
The address bar may decide to reappear and take up essential screen space at the same time the virtual keyboard appears, squeezing the available space even more.
I have posted the solution that I have come up with below. It relies on detecting a change in height of the window within a second of the keyboard focus changing. I am hoping that you might have a better solution to propose that has been tested cross-platform, cross-browser and across devices.
I've created a repository on GitHub.
You can test my solution here.
In my tests, this may give a false positive if the user is using a computer with a touchscreen and a keyboard and mouse, and uses the mouse first to (de-)select an editable element and then immediately changes the window height. If you find other false positives or negatives, either on a computer or a mobile device, please let me know.
;(function (){
class Keyboard {
constructor () {
this.screenWidth = screen.width // detect orientation
this.windowHeight = window.innerHeight // detect keyboard change
this.listeners = {
resize: []
, keyboardchange: []
, focuschange: []
}
this.isTouchScreen = 'ontouchstart' in document.documentElement
this.focusElement = null
this.changeFocusTime = new Date().getTime()
this.focusDelay = 1000 // at least 600 ms is required
let focuschange = this.focuschange.bind(this)
document.addEventListener("focus", focuschange, true)
document.addEventListener("blur", focuschange, true)
window.onresize = this.resizeWindow.bind(this)
}
focuschange(event) {
let target = event.target
let elementType = null
let checkType = false
let checkEnabled = false
let checkEditable = true
if (event.type === "focus") {
elementType = target.nodeName
this.focusElement = target
switch (elementType) {
case "INPUT":
checkType = true
case "TEXTAREA":
checkEditable = false
checkEnabled = true
break
}
if (checkType) {
let type = target.type
switch (type) {
case "color":
case "checkbox":
case "radio":
case "date":
case "file":
case "month":
case "time":
this.focusElement = null
checkEnabled = false
default:
elementType += "[type=" + type +"]"
}
}
if (checkEnabled) {
if (target.disabled) {
elementType += " (disabled)"
this.focusElement = null
}
}
if (checkEditable) {
if (!target.contentEditable) {
elementType = null
this.focusElement = null
}
}
} else {
this.focusElement = null
}
this.changeFocusTime = new Date().getTime()
this.listeners.focuschange.forEach(listener => {
listener(this.focusElement, elementType)
})
}
resizeWindow() {
let screenWidth = screen.width;
let windowHeight = window.innerHeight
let dimensions = {
width: innerWidth
, height: windowHeight
}
let orientation = (screenWidth > screen.height)
? "landscape"
: "portrait"
let focusAge = new Date().getTime() - this.changeFocusTime
let closed = !this.focusElement
&& (focusAge < this.focusDelay)
&& (this.windowHeight < windowHeight)
let opened = this.focusElement
&& (focusAge < this.focusDelay)
&& (this.windowHeight > windowHeight)
if ((this.screenWidth === screenWidth) && this.isTouchScreen) {
// No change of orientation
// opened or closed can only be true if height has changed.
//
// Edge case
// * Will give a false positive for keyboard change.
// * The user has a tablet computer with both screen and
// keyboard, and has just clicked into or out of an
// editable area, and also changed the window height in
// the appropriate direction, all with the mouse.
if (opened) {
this.keyboardchange("shown", dimensions)
} else if (closed) {
this.keyboardchange("hidden", dimensions)
} else {
// Assume this is a desktop touchscreen computer with
// resizable windows
this.resize(dimensions, orientation)
}
} else {
// Orientation has changed
this.resize(dimensions, orientation)
}
this.windowHeight = windowHeight
this.screenWidth = screenWidth
}
keyboardchange(change, dimensions) {
this.listeners.keyboardchange.forEach(listener => {
listener(change, dimensions)
})
}
resize(dimensions, orientation) {
this.listeners.resize.forEach(listener => {
listener(dimensions, orientation)
})
}
addEventListener(eventName, listener) {
// log("*addEventListener " + eventName)
let listeners = this.listeners[eventName] || []
if (listeners.indexOf(listener) < 0) {
listeners.push(listener)
}
}
removeEventListener(eventName, listener) {
let listeners = this.listeners[eventName] || []
let index = listeners.indexOf(listener)
if (index < 0) {
} else {
listeners.slice(index, 1)
}
}
}
window.keyboard = new Keyboard()
})()
There is a new experimental API that is meant exactly to track size changes due to the keyboard appearing and other mobile weirdness like that.
window.visualViewport
https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API
By listening to resize events and comparing the height to the height to the so called "layout viewport". See that it changed by a significant amount, like maybe 30 pixels. You might deduce something like "the keyboard is showing".
if('visualViewport' in window) {
window.visualViewport.addEventListener('resize', function(event) {
if(event.target.height + 30 < document.scrollElement.clientHeight) {
console.log("keyboard up?");
} else {
console.log("keyboard down?");
}
});
}
(code above is untested and I suspect zooming might trigger false positive, might have to check for scaling changes as well)
As no direct way to detect the keyboard opening, you can only detect by the height and width. See more
In javascript screen.availHeight and screen.availWidth maybe help.
Using visualViewPort
This was inspired by on-screen-keyboard-detector. It works on Android and iOS.
if ('visualViewport' in window) {
const VIEWPORT_VS_CLIENT_HEIGHT_RATIO = 0.75;
window.visualViewport.addEventListener('resize', function (event) {
if (
(event.target.height * event.target.scale) / window.screen.height <
VIEWPORT_VS_CLIENT_HEIGHT_RATIO
)
console.log('keyboard is shown');
else console.log('keyboard is hidden');
});
}
Another approach using virtualKeyboard
This worked, but isn't supported in iOS yet.
if ('virtualKeyboard' in navigator) {
// Tell the browser you are taking care of virtual keyboard occlusions yourself.
navigator.virtualKeyboard.overlaysContent = true;
navigator.virtualKeyboard.addEventListener('geometrychange', (event) => {
const { x, y, width, height } = event.target.boundingRect;
if (height > 0) console.log('keyboard is shown');
else console.log('keyboard is hidden');
});
Source: https://developer.chrome.com/docs/web-platform/virtual-keyboard/
This is a difficult problem to get 'right'. You can try and hide the footer on input element focus, and show on blur, but that isn't always reliable on iOS. Every so often (one time in ten, say, on my iPhone 4S) the focus event seems to fail to fire (or maybe there is a race condition with JQuery Mobile), and the footer does not get hidden.
After much trial and error, I came up with this interesting solution:
<head>
...various JS and CSS imports...
<script type="text/javascript">
document.write( '<style>#footer{visibility:hidden}#media(min-height:' + ($( window ).height() - 10) + 'px){#footer{visibility:visible}}</style>' );
</script>
</head>
Essentially: use JavaScript to determine the window height of the device, then dynamically create a CSS media query to hide the footer when the height of the window shrinks by 10 pixels. Because opening the keyboard resizes the browser display, this never fails on iOS. Because it's using the CSS engine rather than JavaScript, it's much faster and smoother too!
Note: I found using 'visibility:hidden' less glitchy than 'display:none' or 'position:static', but your mileage may vary.
I'm detecting the visibility of a virtual keyboard as follows:
window.addEventListener('resize', (event) => {
// if current/available height ratio is small enough, virtual keyboard is probably visible
const isKeyboardHidden = ((window.innerHeight / window.screen.availHeight) > 0.6);
});

.clone().appendTo - Replace element styles not working?

I have individual three arrows. on click; I want the div below them (letsChat) to change styles and I want to clone and append relevant information in that div. I also want it to revert back to it's original state when it is clicked again or if orientation is changed to portrait.
document.querySelector('#compositionArrow').onclick = function(){
var letsChat = document.querySelector('.lets-chat');
var letsChatButton = document.querySelector('.lets-chat a');
var compositionArrow = document.querySelector('#compositionArrow')
var compositionText = document.querySelector('.composition-text');
if (letsChatButton.style.display='flex' && window.matchMedia("(orientation: landscape)").matches) {
compositionArrow.style.transform='rotate(180deg)';
//letsChat.appendChild(compositionText).cloneNode(true);
//compositionText.clone().appendTo.letsChat; return false;
document.querySelector('.composition-text').clone().appendTo(document.querySelector('.lets-chat'));
letsChat.style.background='#00BCD4';
letsChatButton.style.display='none';
}
else if (letsChatButton.style.display='none' || window.matchMedia("(orientation: portrait)").matches){
compositionArrow.style.transform='rotate(180deg)';
letsChat.style.background='#ff8f00';
letsChatButton.style.display='flex';
}
}
example can be found below: (you may have to play with window
artpenleystudios.com
Here's something that demonstrates part of what you asked. It doesn't take into account orientation change, but it handles the click part. As far as I know, there's no straightforward way to detect orientation change, but here's an article that talks about a few options. Another idea would be to use jQuery Mobile as it fires orientationchange events.
So after much back and forth and after looking at your site more closely, this is what I managed to cobble together.
jQuery('#compositionArrow').click(function() {
var $letsChat = jQuery('.lets-chat');
var letsChat = $letsChat[0];
var letsChatButton = $letsChat.find('a')[0];
// Remove old composition text if it exists.
$letsChat.find('.composition-text').remove();
if (letsChatButton.style.display !== 'none' && window.matchMedia("(orientation: landscape)").matches) {
this.style.transform = 'rotate(180deg)';
$letsChat.append(jQuery('.composition-text').clone());
letsChat.style.background = '#00BCD4';
letsChatButton.style.display = 'none';
}
else if (letsChatButton.style.display === 'none' || window.matchMedia("(orientation: portrait)").matches) {
this.style.transform = '';
letsChat.style.background = '#ff8f00';
letsChatButton.style.display = 'flex';
}
});
It works for me in FireFox on a downloaded version of your site.
Cheers!

How to prevent Canvas to act like an Image on Mobile?

I have an interactive canvas, where you can click on some buttons. But when I test it on mobile, and try to click on the buttons, it doesnt react immediately. I have to press and wait for the action.
test here: http://choix.me/labor/canvas/car.html
here the javascript code for the upBtn:
this.upBtn.addEventListener("mousedown", upClick.bind(this));
this.upBtn.addEventListener("click", upRelease.bind(this));
function upClick()
{
up = true;
speed = 10;
forward = 1;
}
function upRelease()
{
up = false;
speed = 10;
forward = 0;
}
You are using mousedown and click events, neither of which are events that are naturally supported on a mobile browser. They do work but not the same way they work on the desktop. Tie into the touch events, specifically the touchstart and touchend event
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
this.upBtn.addEventListener("touchstart", upClick.bind(this));
this.upBtn.addEventListener("touchend", upRelease.bind(this));
function upClick()
{
up = true;
speed = 10;
forward = 1;
}
function upRelease()
{
up = false;
speed = 10;
forward = 0;
}
not tested code, but the gist is there
It had something to do with CreateJS:
This line fixes it:
createjs.Touch.enable(stage);
from:
Touch Events not registering for HTML5 Canvas Authoring using Flash CC

Categories