Javascript - Run my script only if landscape is detected - javascript

I am running a script to show a notification within a menu with scroll, but I do not know how to detect if the device has orientation landscape to validate the script.
The call onClick="VerHayMas();" works perfectly, but if the user open the menu once, clicking on #boton-menu and with your device in portrait, after changing the orientation to landscape the script no longer meet the objective.
The script has its logic ONLY if the device is in landscape, which is
when the menu needs to show the notification.
So, is it possible that my script is only valid with (max-width:999px) and (orientation:landscape), ignoring the portrait...?
I am a beginner in JS, and I do not know how to do it, really.
Any idea?
Thanks in advance!
HTML & CSS
#mas-menu {display:none}
<div id="boton-menu" onClick="VerHayMas();">+</div>
Script:
var clicksVerHayMas = 0;
function VerHayMas() {
clicksVerHayMas = clicksVerHayMas + 1;
if (clicksVerHayMas == 1) {
document.getElementById('mas-menu').style.display = 'block';
window.setTimeout(function() {
$('#mas-menu').fadeOut('slow');
}, 4000);
}
};
EDIT:
I have tried with the following script, but it does not work. If the user makes a call to onClick="VerHayMas();" in portrait mode, the script is no longer running in landscape mode.
What am I doing wrong here?
const matchesMediaQuery = window.matchMedia('(max-width:999px) and (orientation:landscape)').matches;
if (matchesMediaQuery) {
var clicksVerHayMas = 0;
function VerHayMas() {
clicksVerHayMas = clicksVerHayMas +1;
if(clicksVerHayMas == 1){
document.getElementById('mas-menu').style.display = 'block';
window.setTimeout(function(){
$('#mas-menu').fadeOut('slow');
},4000);
}};
}

I'd keep it simple, if screen height is less than width, then the user is in landscape mode. You can grab the height and width from the global window object.
if (window.innerWidth > window.innerHeight) {
// The user is in landscape mode!
userInLanscapeFunc();
}
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight

You can solve this using matchMedia:
const matchesMediaQuery = window.matchMedia('(max-width:999px) and (orientation:landscape)').matches;
if (matchesMediaQuery) {
// do something
}
Make sure to note the browser support in the MDN link.
EDIT TO PROVIDE CONTEXT:
Because the user may be moving around their screen, you will want to make this evaluation inside VerHayMas, each time it is run, to determine if the main body of the script should be executed:
var clicksVerHayMas = 0;
function VerHayMas() {
var isLandscapeAndMeetsSizeRequirements = window.matchMedia('(max-width:999px) and (orientation:landscape)').matches;
if (isLandscapeAndMeetsSizeRequirements) {
clicksVerHayMas = clicksVerHayMas + 1;
if (clicksVerHayMas == 1) {
document.getElementById('mas-menu').style.display = 'block';
window.setTimeout(function() {
$('#mas-menu').fadeOut('slow');
}, 4000);
}
}
};
So VerHayMas will be run on every click, but only if the screen meets the requirements as determined by the media query string will it execute the code inside the if block.

Related

Scroll bottom in JavaScript

I have a working bottom function in JavaScript to detect if the user scrolls at the bottom. However, a problem comes when the user has a strange resolution (like windows scale) or when you zoom. The function is not working anymore and can't detect the bottom.
Here is what I did :
const bottom = e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight;
if (bottom) {
this.props.getNewValues();
}
Is there a way to avoid that? Even when you don't zoom, this is not working for people displaying the site on a TV or something like this (like a friend of mine did)
Thanks you
EDIT : I'm applying this on a precise element and I repeat that my solution is working except by unzooming. Unzooming provides float values that made the response not really accurate (it goes from 1 to 50px of difference based on the zoom made)
I use this function (can't take credit as someone else wrote it - sorry for no credit - it was ages ago). Maybe you can adapt this to your use case:
(function($) {
//CHECK SCROLLED INTO VIEW UTIL
function Utils() {
}
Utils.prototype = {
constructor: Utils,
isElementInView: function (element, fullyInView) {
var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height();
if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
}
}
};
var Utils = new Utils();
//END CHECK SCROLLED INTO VIEW UTIL
//USING THE ELEMENT IN VIEW UTIL
//this function tells what to do do when the element is or isnt in view.
//var inView = Utils.isElementInView(el, false); Where FALSE means the element doesnt need to be completely in view / TRUE would mean the element needs to be completely in view
function IsEInView(el) {
var inView = Utils.isElementInView(el, false);
if(inView) {
//console.log('in view');
} else {
//console.log('not in view');
}
};
//Check to make sure the element you want to be sure is visible is present on the page
var variableOfYourElement = $('#variableOfYourElement');
//if it is on this page run the function that checks to see if it is partially or fully in view
if( variableOfYourElement.length ) {
//run function on page load
IsEInView(variableOfYourElement);
//run function if the element scrolls into view
$(window).scroll(function(){
IsEInView(variableOfYourElement);
});
}
//END USING THE ELEMENT IN VIEW UTIL
})(jQuery);

SharePoint 2016 on premise : how to scroll to top of the page?

My use case is very simple: I'm in a custom list form (modified NewForm.aspx, added with SharePoint Designer). I've added a button and I want that when the users clicks on it, the page scrolls back to the very top.
I've tried to following approach :
In the aspx
<button onclick="return MyScrollTop()">SCROLL TOP</button>
In the javascript
function MyScrollTop() {
//All my attemps go here
return false;
}
I'm not detailing how I'm making sure that the function is called (it can be tricky sometimes in SharePoint, with the MDS and _spBodyOnLoadFunctionNames.push, but I'm 100% certain that my function is called as I see it in the browser's debugger.
I'm using IE11, both in "10" and "Edge" modes.
Here are my attempts (I tried them one by one, not in the same function)
//attempt #1 (as seen on W3C)
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
//attempt #2 (as seen on Stack Overflow for regular javascript)
window.scrollTo(0,0);
//attempt #3 (as seen on Stack Overflow for some corner case - desperate attempt)
window.scroll(0,0);
//attempt #4 (as seen on Stack Overflow to fight SharePoint's '_maintainWorkspaceScrollPosition' hidden control on a page reload or unload)
var scrollX = document.getElementById('__SCROLLPOSITIONX');
var scrollY = document.getElementById('__SCROLLPOSITIONY');
if (scrollX && scrollY) {
scrollX.value = 0;
scrollY.value = 0;
}
var workspaceY = document.getElementById('_maintainWorkspaceScrollPosition');
if (workspaceY) {
workspaceY.value = 0;
}
None of these work. When I click on the buttons, the breakpoints show me that my script is executed, but it's like window.scrollTo and others have no effect at all.
I've put a breakpoint in this SharePoint function from init.js to see if I can hook myself somewhere, but I'm not sure wht I should do :
if (!g_setScrollPos) {
if (browseris.firefox && browseris.firefox36up)
window.scrollTo(0, 0);
if (Boolean((ajaxNavigate.get_search()).match(RegExp("[?&]IsDlg=1")))) {
if (!isIE7 || elmWorkspace.scrollHeight < elmWorkspace.clientHeight)
elmWorkspace.style.overflowY = "auto";
}
var scrollElem = document.getElementById("_maintainWorkspaceScrollPosition");
if (scrollElem != null && scrollElem.value != null) {
elmWorkspace.scrollTop = Number(scrollElem.value);
}
g_setScrollPos = true;
}
CallWorkspaceResizedEventHandlers();
g_frl = false;
I finally managed to do it like this :
var w = document.getElementById("s4-workspace");
w.scrollTop = 0;

How to prevent iOS keyboard from pushing the view off screen with CSS or JS

I have a responsive web page that opens a modal when you tap a button. When the modal opens, it is set to take up the full width and height of the page using fixed positioning. The modal also has an input field in it.
On iOS devices, when the input field is focused, the keyboard opens. However, when it opens, it actually pushes the full document up out of the way such that half of my page goes above the top of the viewport. I can confirm that the actual html tag itself has been pushed up to compensate for the keyboard and that it has not happened via CSS or JavaScript.
Has anyone seen this before and, if so, is there a way to prevent it, or reposition things after the keyboard has opened? It's a problem because I need users to be able to see content at the top of the modal while, simultaneously, I'd like to auto-focus the input field.
first
<script type="text/javascript">
$(document).ready(function() {
document.ontouchmove = function(e){
e.preventDefault();
}
});
then this
input.onfocus = function () {
window.scrollTo(0, 0);
document.body.scrollTop = 0;
}
For anyone stumbling into this in React, I've managed to fix it adapting #ankurJos solution like this:
const inputElement = useRef(null);
useEffect(() => {
inputElement.current.onfocus = () => {
window.scrollTo(0, 0);
document.body.scrollTop = 0;
};
});
<input ref={inputElement} />
I struggled with this for awhile, I couldn't find something that worked well for me.
I ended up doing some JavaScript hackery to make it work.
What I found was that Safari wouldn't push the viewport if the input element was in the top half of the screen. That was the key to my little hack:
I intercept the focus event on the input object and instead redirect the focus to a invisible (by transform: translateX(-9999px)). Then once the keyboard is on screen (usually 200ms or so) I trigger the focus event on the original element which has since animated on screen.
It's a kind of complicated interaction, but it works really well.
function ensureOffScreenInput() {
let elem = document.querySelector("#__fake_input");
if (!elem) {
elem = document.createElement("input");
elem.style.position = "fixed";
elem.style.top = "0px";
elem.style.opacity = "0.1";
elem.style.width = "10px";
elem.style.height = "10px";
elem.style.transform = "translateX(-1000px)";
elem.type = "text";
elem.id = "__fake_input";
document.body.appendChild(elem);
}
return elem;
}
var node = document.querySelector('#real-input')
var fakeInput = ensureOffScreenInput();
function handleFocus(event) {
fakeInput.focus();
let last = event.target.getBoundingClientRect().top;
setTimeout(() => {
function detectMovement() {
const now = event.target.getBoundingClientRect().top;
const dist = Math.abs(last - now);
// Once any animations have stabilized, do your thing
if (dist > 0.01) {
requestAnimationFrame(detectMovement);
last = now;
} else {
event.target.focus();
event.target.addEventListener("focus", handleFocus, { once: true });
}
}
requestAnimationFrame(detectMovement);
}, 50);
}
node.addEventListener("focus", handleFocus, { once: true });
Personally I use this code in a Svelte action and it works really well in my Svelte PWA clone of Apple Maps.
Video of it working in a PWA clone of Apple Maps
You'll notice in the video that the auto-complete changes after the animation of the input into the top half of the viewport stabilizes. That's the focus switch back happening.
The only downside of this hack is that the focus handler on your original implementation will run twice, but there are ways to account for that with metadata.
you could also do this if you don't want scrollTo the top(0, 0)
window.scrollBy(0, 0)
const handleResize = () => {
document.getElementById('header').style.top = window.visualViewport.offsetTop.toString() + 'px'
}
if (window && window.visualViewport) visualViewport.addEventListener('resize', handleResize)
Source: https://rdavis.io/articles/dealing-with-the-visual-viewport
In some situations this issue can be mitigated by re-focusing the input element.
input.onfocus = function () {
this.blur();
this.focus();
}
Both IOS8 and Safari bowsers behave the same for input.focus() occuring after page load. They both zoom to the element and bring up the keyboard.(Not too sure if this will be help but have you tried using something like this?)
HTML IS
<input autofocus>
JS is
for (var i = 0; i < 5; i++) {
document.write("<br><button onclick='alert(this.innerHTML)'>" + i + "</button>");
}
//document.querySelector('input').focus();
CSS
button {
width: 300px;
height: 40px;
}
ALso you will have to use a user-agent workaround, you can use it for all IOS versions
if (!/iPad|iPhone|iPod/g.test(navigator.userAgent)) {
element.focus();
}

Resetting scale in Phaser

I have a game made in phaser and we're trying to add fullscreen functionality to it. When I call just
this.game.scale.startFullScreen(false);
it keeps the games maxHeight and maxWidth, since they're set in the preload, so it shows a black full screen with the game centered, so I created a wrapper for it, which works, but not when a user hits escape as opposed to the "Exit fullscreen button". The start wrapper sets the maxWidth and maxHeight to null, which then allows total full screen, and the stop wrapper sets them back to their default values, and when you press the "exit fullscreen" button it works fine, but when I hit escape it calls my function, but doesn't reset the screen, so it exits browser full screen mode, but is still taller than the browser window.
Here's my full code:
var startFullscreen = function() {
// remove maxwith and maxheight
game.scale.maxWidth = null;
game.scale.maxHeight = null;
// set to fullscreen
game.scale.startFullScreen(false);
}
var stopFullscreen = function() {
// reset maxWidth and maxHeight
game.scale.maxWidth = 1000;
game.scale.maxHeight = 600;
// turn off fullscreen
if (game.scale.isFullScreen) { // if the user hit escape, fullscreen is already exited and we only need to reset the scale
game.scale.stopFullScreen();
} else {
// what goes here?
}
}
$(document).keyup(function (e) {
if (e.keyCode == 27) { // escape key maps to keycode `27`
stopFullscreen();
}
});
Any help is appreciated. Thanks in advance!
I moved the resetting to after we go to full screen, that way they're already set when exit full screen gets called, so it renders correct, but I'm still open to better solutions.
var startFullscreen = function() {
// remove maxwith and maxheight
game.scale.maxWidth = null;
game.scale.maxHeight = null;
// set to fullscreen
game.scale.startFullScreen(false);
setTimeout(function () {
// resets height and width so the game will render correctly when fullscreen exits
game.scale.maxWidth = 1000;
game.scale.maxHeight = 600;
}, 500);
}

jquery or not / Cross Browser Compatible iframe resize (IE, Chrome, Safari, Firefox)

Here is my issue. I have been looking hard for a cross browser iframe resize code to use and i just cant find one. All i have seen has issues in one browser over another. Here is what i am doing. I am loading an iframe into the page in an jquery tools overlay. This iframe will load contents of a page (on the same domain so dont need to worry about cross domain). When a user clicks an action on that form the iframe will again need to resize (i have it working for when the iframe increases but not when the iframe decreases).
I have a js file that is included in the iframe which has this function
$(window).load(function(){
parent.adjust_iframe();
});
That function then calls the parent pages function like so:
function adjust_iframe() {
//i have tried both body and html and both dont work in IE
var h = $("#overlayFrame").contents().find("body").height();
if(h==0)
h="500";
else
h=h+3;
$("#overlayFrame").css({'height': h});
window.scrollTo(0,0);
}
The above code works fine in Chrome and firefox but not in IE.
Any help here? I really need a cross browser compatible light weight solution that doesnt involve some heavy jquery plugin that isnt supported.
Thanks!
Try
$(window).load(function(){
var bodyHeight = $('body').height();
parent.adjust_iframe( bodyHeight );
});
and
function adjust_iframe(newHeight) {
//i have tried both body and html and both dont work in IE
if(newHeight == 0) {
newHeight = 500;
} else {
newHeight += 3;
}
$("#overlayFrame").css({'height': newHeight});
window.scrollTo(0,0);
}
Because the problem is probably that the page cannot access the iframes contents..
I have 2 suggestions:
When you are setting the CSS height, explicitly tell it pixels.
$("#overlayFrame").css({'height': h + 'px'});
When your iframe code is calling parent.adjust_iframe, send the current width/height.
parent.adjust_iframe($('body').height());
BONUS suggestion: Do a little investigation and tell us what version of IE and why it doesn't work. Put some alerts in there and find out if the height is getting derived etc.
I've searched my archived files and found script which sets new size of iframe window. It was working on IE6, FF,...
/**
* Parent
*/
<iframe id="myframe" name="myframe" ...>
<script type="text/javascript">
var iframeids=["myframe"];
if (window.addEventListener) {
window.addEventListener("load", resizeCaller, false);
}else if (window.attachEvent) {
window.attachEvent("onload", resizeCaller);
} else {
window.onload=resizeCaller;
}
var iframehide="yes";
var getFFVersion=navigator.userAgent.substring(navigator.userAgent.indexOf("Firefox")).split("/")[1];
var FFextraHeight=parseFloat(getFFVersion)>=0.1? 20 : 0;
function resizeCaller() {
var dyniframe=new Array();
for (i=0; i<iframeids.length; i++){
if (document.getElementById)
resizeIframe(iframeids[i]);
if ((document.all || document.getElementById) && iframehide=="no"){
var tempobj=document.all? document.all[iframeids[i]] : document.getElementById(iframeids[i]);
tempobj.style.display="";
}
}
};
function resizeIframe(frameid){
var currentfr=document.getElementById(frameid);
if (currentfr && !window.opera){
currentfr.style.display="";
if (currentfr.contentDocument && currentfr.contentDocument.body.offsetHeight)
currentfr.height = currentfr.contentDocument.body.offsetHeight+FFextraHeight;
else if (currentfr.Document && currentfr.Document.body.scrollHeight)
currentfr.height = currentfr.Document.body.scrollHeight;
if (currentfr.addEventListener)
currentfr.addEventListener("load", readjustIframe, false);
else if (currentfr.attachEvent){
currentfr.detachEvent("onload", readjustIframe);
currentfr.attachEvent("onload", readjustIframe);
}
}
};
function readjustIframe(loadevt) {
var crossevt=(window.event)? event : loadevt;
var iframeroot=(crossevt.currentTarget)? crossevt.currentTarget : crossevt.srcElement;
if (iframeroot)resizeIframe(iframeroot.id);
};
function loadintoIframe(iframeid, url){
if (document.getElementById)document.getElementById(iframeid).src=url;
};
</script>
/**
* child iFrame html
*/
<body onResize="resizeIE()">

Categories

Resources