How to prevent body from scrolling with push-side menu - javascript

I am trying to properly implement a push-side menu plugin (Responsive Menu) into a wordpress theme. Based on SO #Congrim answer, I've managed to achieve a way to lock the body at scroll when push-menu is open (with all the elements including the header fixed) except the interactive links class=edge-ils edge-ils-with-scroll edge-ils-light which will still go Up at push-menu open.
I've saved this sequence into congrim.js file, I've enqueued the script into the theme in functions.php file:
function lockScroll() {
if ($('body').hasClass('lock-scroll')) {
$('body').removeClass('lock-scroll');
}
else {
$('body').addClass('lock-scroll');
}
}
/* I've implemented `onclick="lockScroll();"` in button element,
* using this sequence in the same congrim.js file:
*/
$(document).ready(function() {
$('#responsive-menu-pro-button').click(function() {
lockScroll();
});
});
Removing the jQuery wrap will not give any error in browser console (tested in Chrome) may be still a bad approach to wrapp the code like this in wordpress (?)
In these conditions, unfortunately, overflow: hidden; doesn't apply, at push-side menu open, I can't use this class in CSS file/section:
.lock-scroll {
overflow: hidden;
}
The code will allow me to use only
.lock-scroll {
position: fixed;
}
The question:
Is there any possibility to force the code to implement overflow: hidden;* OR any other a workaround in order to have the interactive links class=edge-ils edge-ils-with-scroll edge-ils-light not going up at push-side menu open, to remain fixed at the position the viewer is clicked before opening the menu?
Please focus on the interactive links issue only, the rest of the scene is fine (header and the logo are in place like it should be, the background pictures are acting like it should as well).
LE: *overflow: hidden; it looks like will produce an unwanted body shifting effect at menu open/close, during the show/hide scrollbar, which is not happening in this stage.
LE2: congrim.js file has been replaced with body-lock.min.js by Outsource WordPress, please see the solution below.
Website testpage here.

Please check the solution given below.
Step 1: Add this CSS .scroll-lock{position:fixed !important;}.
Step 2: Add this JS.
$(document).ready(function() {
var windowTop = 0;
var menuOpen = 0;
var offsetContainerList = 0;
$('#responsive-menu-pro-button').click(function() {
var offsetScrollList = $('.edge-ils-item-link:first').offset().top;
if ($('html').hasClass('scroll-lock')) {
$('#responsive-menu-pro-container').one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",
function(event) {
if (menuOpen==0) {
menuOpen = 1;
$('html').removeClass('scroll-lock');
$('.edge-ils-content-table').css('top', eval(offsetContainerList)-40+'px'); //change image container top position
$('html').scrollTop(windowTop); //scroll to original position
}
else {
menuOpen = 0;
}
});
}
else {
windowTop = $(window).scrollTop();
offsetContainerList = $('.edge-ils-content-table').offset().top;
$('html').addClass('scroll-lock');
$('.edge-ils-content-table').css('top', -offsetScrollList + 'px'); //change image container top position
}
});
});
That's it!

Please add the below code in your custom js file .
jQuery('#responsive-menu-pro-button').click(function(){
var menu_active = jQuery(this).hasClass('is-active');
if(menu_active){
jQuery('body').css('position','fixed');
}else{
jQuery('body').css('position','static');
}
});
I hope it helps you.
Thanks

Your scroll isn't a natural navigator-based scroll, you have a JS somewhere swapping classes to emulate a scroll (edge-appeared,edge-up,edge-down).
On the push-side menu opening, these classes are reset, overflow-hidden won't change that.
You need to find which JavaScript is swapping those classes and prevent it from doing so, I'd be glad to be of further help but you have so many JS files that it would take quite some time to go through all of these. If you succeed in making a Minimal, Complete, and Verifiable example please post it here.

Related

JavaScript function to manipulate CSS custom properties not working on $(window).resize()

I have a fixed header with :target in-page anchors, and need to adjust the property values dynamically via JavaScript or JQuery so as to maintain the relevant :target's position directly under the header when the window is resized, while adapting to the changes in both the previous section's .container height and the .header_container height that occur with resizing.
The simplest solution seems to be a ::before pseudo-element for the :target pseudo-class, and to then utilize CSS custom properties to dynamically modify the style properties.
I have no trouble correctly positioning the :target with the below function when the page is loaded (or reloaded), or correctly position the first :target on $(window).resize(), however it's failing to do the same for the remaining targets on $(window).resize().
Fiddles
Simplified Code: https://jsfiddle.net/chayanyc/g6p3549s/
Responsive Design (Simplified): https://jsfiddle.net/chayanyc/wuk92dns/
Code Snippets
CSS:
.header_container {height: 98px; margin: 0; padding: 0; position: fixed; top: 0; display: block; z-index: 100;}
.main {margin-top: 98px; width: 100%;}
:target::before {height: var(--target_position1); margin-top: var(--target_position2); content: ""; display: block; visibility: hidden;}
JavaScript:
var headerHeight;
function setTarget() {
headerHeight = document.getElementById('header').offsetHeight;
headerHeight1 = headerHeight + "px";
document.documentElement.style.setProperty('--target_position1', headerHeight1);
document.documentElement.style.setProperty('--target_position2', '-' + headerHeight1);
}
$(window).resize(function () {
setTarget();
});
$(document).ready(function () {
setTarget();
});
There is no complete solution to this Problem,
because you want the target element stay on place on document resize, but if the user do a scroll on his page, it is not possible to know where staying on the same first word of the first line on display.
So here, i just replace on the same target on top when user resize his document, even if he had done a scroll just before.
no need of this CSS part (remove it)
:target::before {margin: 0; content: ""; dis.....
and change your jQuery to:
$(document).ready(function () {
// global info for menu -> target elememt
var InfoTarget = { ID: null, tempo:300 }
$('a').click(function(evt){
InfoTarget.ID = $(this).attr('href') // possible target elm
// check if InfoTarget.ID exist on page
let nbElements = 0
try { nbElements = $(InfoTarget.ID).length }
catch(err) { nbElements = 0 }
if ( nbElements != 1 ) {
InfoTarget.ID = null // not target element found
}
else {
evt.preventDefault() // disable auto scroll to target element
$('html').animate({
scrollTop: ($(InfoTarget.ID).offset().top - $('#header').outerHeight(true))
}, InfoTarget.tempo );
}
});
$(window).resize(function (){
if (InfoTarget.ID) { // if InfoTarget.ID exist <=> InfoTarget.ID != null
$('html').animate({
scrollTop: ($(InfoTarget.ID).offset().top - $('#header').outerHeight(true))
}, InfoTarget.tempo);
}
});
});
My code speaks for itself, but here is a complete explanation:
the principle is simple: the function target css activates on a click on a link <a href="#..."> to trigger a scroll of the page towards the element having for id = to that contained in the initial href.
therefore this code intercepts any click on a link on the page and must first determine whether it is a link to an anchor or not.
To determine if this is a link to an anchor on the page, it simply tests whether an element of the page has this value as this ID, (// check if InfoTarget.ID exists on page).
As this kind of test can also generate an error, this test is placed in a try / catch.
If the result is indeed an anchor, then the action of the click is canceled, (with evt.preventDefault()) which prevents the browser from triggering its automatic scroll to the link;
the reference link is kept in an object variable (global)
var InfoTarget = {ID: null, tempo: 300}
seen on: InfoTarget.ID = $(this).attr('href') // possible target elm
the rest is simple, you have to scroll down to the anchor.
Depending on the width of the page and the previous elements, browsers continuously recalculate the position of each tag present on a page and jQuery can be retrieved this offset position by $(element).offset().Top
as there is a menu bar on your page that masks the top of the page, you must deduct its height from the position in scroll (= $ ('# header'). outerHeight (true))
a scroll = 0 will force a move to the top of the page
a scroll = $(element).offset().top places the element at the top of the page
to which we must deduct the height of the #header
the complete formula is
scrollTop: ( $(InfoTarget.ID).offset().top - $('#header').outerHeight(true) )
this command is placed in a jQuery.animate, for a visually smoother move, and uses the InfoTarget.tempo value as the duration for this animation.
During a resize of the page, and to the extent that a link having a target has been previously clicked (therefore always active) then the same type of scroll is triggered.
The different jQuery methods used are all explained in the jQuery doc (for example: https://api.jquery.com/outerHeight/ )
New Solution -- Lundi 14 oct 2019 / 01:00 (in the night of sunday / monday)
this script must be placed after all the html elements of the body
// scroll to target upon window.location.hash
$(window).on('hashchange', function() {
$('.TargetMark').removeClass('TargetMark')
$(window.location.hash).addClass('TargetMark')
setTimeout( scrollTop2, 220 ) // scroll to target after browser auto scrolling conflit
})
function scrollTop2() {
if ($('.TargetMark').length===1) { // if target exist
$('html').animate({
scrollTop: ($('.TargetMark').offset().top - $('#header').outerHeight(true))
}, 100);
}
}
In this version the target element is added a class (TargetMark) allowing to find it when window resize
ending part
$(document).ready(function () {
//...
// ---------------------------> no call to scrollTop();
//...
});
$(window).resize(function () {
//...
scrollTop2();
//...
});
about toggleMenu conflict:
function toggleMenu() {
$('.navbar-toggle').on('click', function () {
if ($("#js-menu").is(".expand")) {
$("#js-menu").toggleClass("expand");
$("#submenu").removeClass("active_sub").addClass("inactive_sub");
} else {
$("#js-menu").toggleClass("expand");
$("#submenu").removeClass("inactive_sub").addClass("active_sub");
}
resetTarget();
setTimeout( scrollTop2, 220 ) // scroll to target after browser auto scrolling conflit
});
}
I spent a lot of my time on your question, I studied differents approaches and the different automatisms put at work by the navigators themselves and which is necessary to fight to get the result you'r looking for. I came to the conclusion that the problem first came from the architecture of your page.
The fact that the menu ("#header") covers the page ("#main") is a major flaw that prevents to have an effective JS code for your question.
The call on the hash of an anchor triggers one or more scrolls of the page, the resize of the page also entails a scroll calculation because by changing size on the screen, it also changes the size of the page. page (reducing the size of the screen by half makes the page size double), it is the same by changing the size of the font, it also changes the size in page.
Whenever the page size changes, the browser must recalculate a lot of things and some of these mechanisms can trigger one or more scrolls.
What you are asking here is to recalculate a page positioning according to an element of which we can not be certain that it is completely established because this process is executed in parallel with other processes of the browser which can change useful values.
Plus the fact that some of the browser processes also work to scroll the page and that it can be the last done!
So the fact that there is an overlap between the menu and the page add more complexity and makes the possibility of a solution impossible.
Change your layout and 3/4 of your problem will be fixed.
Resize is firing, offset height is not changing. Setting the same value over and over again, yields no change. You might check this:
see the value change
I used the logo for output:
$('.logo').text(headerHeight + ' -' + i++);
You want to scroll down to the one div selected by target without having it to be overlapped by your nav?
.. then extend the areas. see here
add positive margin-top and negative padding-top.
.... to compensate for any nav size changes, use media queries to change your css vars.

Dynamic view-port Calculation for sticky navbar

I'm new to JavaScript, i seem to have got myself in a tricky situation. Currently i have some code which below 200px adds a class to make the navbar sticky. The code which have added can be found below.
function navbarCollapse () {
if ($("#mainNav").offset().top > 200) {
$("#mainNav").addClass("navbar-shrink");
$("#mainNav").removeClass("navbar-font");
} else {
$("#mainNav").removeClass("navbar-shrink");
$("#mainNav").addClass("navbar-font");
}
}
//Execute The Collapsing Navbar Function
navbarCollapse();
//Scroll Event
$(window).scroll(navbarCollapse);
The problem I'm facing is 200px on one device is completely different on another device such as a large monitor
I need to be able to calculate the height of a devices view-port, and then execute the code accordingly.
Any help would greatly be appreciated. Like i said I'm new to JavaScript and I'm probably missing something simple.
Instead of making an offset like this add a class that uses css and do your calculations there.
.nav-offset {
Top: 1%;
}

How to force a drop-down to move down on IE 11?

I have the following drop-down :
<select>
<option></option>
<option>Closed</option>
<option>Open</option>
</select>
with the associated style:
select {
font-family: Cursive;
width:200px;
position: relative;
z-index: 100;
padding-right: 25px;
}
My problem is that the drop-down is moving upward on IE 11:
Where as on chrome it is working fine.
Any idea ?
Like mentioned in the comments, select menus are very browser specific and hard to style. Some even send the options into the twilight zone where they are seemingly not even a part of the window and any events will return null. It might not be worth trying to get this to look the same across browsers, also because of the mobile implementations, but I happened to be making something like this for no apparent reason. As it coincides with your question I might as well post it.
It's not the prettiest thing when it comes to HTML and CSS because it requires four additional elements - one wrapper (commonly used for styling select boxes with overflow hidden but I took a slightly different approach because I thought it looked better) and three absolutely placed elements. One is a styled button, another will hide the scrollbar that appears and the third is a minor hack.
Most important thing is that the user will not be able to click the select menu itself. When this happens, most is lost because after that it's limbo. For that the third element will be used. It will be put on top of the select box. Then when it's clicked, instead of directly opening the menu it will be faked by changing the size of the select element. The div covering the right side also serves another purpose. It's initially placed at the bottom and by getting it's offset we'll know the height of the box. This will be used to resize the button and set the correct size for the overlaying div.
Looks to be behaving quite predicatbly on all major Windows desktop browsers. For the mobile implications this script uses a touch support feature test and reverts to normal layout if that is the case. Could probably be tweaked (with a screen size check) to not exclude trackpad users.
Demo
Not too much relevant CSS. But important to style body background the same as the bar on the right. Transparency is used so the actual menu isn't visible before the image for the button loads.
$(function() {
var hub = $('#box'), list = $('select'),
impel = $('#open'), commit = $('#mark'), tract = $('#refer'),
zenith = tract.position().top,
extent = list.children().length, active;
if (touch()) {
impel.add(commit).add(tract).remove();
hub.fadeTo(0,1);
return;
}
impel.add(commit).height(zenith);
tract.addClass('bar');
hub.fadeTo(0,1).on('mouseup click', function(e) {
e.stopPropagation();
});
commit.mouseup(function() {
flip();
show();
active = true;
});
list.add(impel).click(function() {
flip();
active = !active;
if (active) show();
else hide();
});
$(window).click(function() {
if (active) {
flip();
hide();
active = false;
}
});
function show() {list.attr('size', extent)}
function hide() {list.removeAttr('size')}
function flip() {commit.toggle()}
function touch() {
return 'ontouchstart' in window
|| navigator.maxTouchPoints > 0
|| navigator.msMaxTouchPoints > 0;
}
});

jQuery: Slide animation goes to far, then "jumps" to the right height

I've seen a few questions about a similar issue, but I haven't found a solution that makes sense to me yet. The problem is on the JSFiddle here: http://jsfiddle.net/twchapman/EEXjR/2/
Click on Portfolio to see the behavior.
The functions I wrote:
function changeTab(tab) {
active = tab;
$("#" + tab).slideDown(animspeed);
}
function change(tab) {
if (tab == active) return;
$("#" + active).slideUp(animspeed, function () {
changeTab(tab);
});
}
I'm only using Chrome, but I'm pretty sure you'll get this error on any browser: when the page loads, it slides the content div down, and clicking the links (only Portfolio actually works at the moment) will slide the current div up, then the correct one down.
It's working almost completely as intended, but with one minor issue: when the animations begin, the div's height "jumps", and it's momentarily taller while the animation takes place, then "jumps" to the correct size when finished.
The two common solutions I've found have suggested: 1. Add a width to the style of the div, which already exists, and 2. change the height/margin parameters of the slide function when it's called. To me, the second solution seems like it shouldn't be necessary, as I don't provide any options other than an animation length.
I'm hoping this is just me missing something and being silly, not a big problem with the way I'm doing things.
The problem comes from padding which at times can make jQuery animations jittery.
A fast solution for your problem is to leave your Js untouched and use a natural box model for your layout.
In your css just include:
* { -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
I really suggest to read this Paul Irish blog post and to include this code in all your projects.
Here's a working demo: http://jsfiddle.net/gleezer/EEXjR/3/
Update your js.
function change(tab) {
if(tab == active) return false;
console.log(tab);
console.log(active);
if($("#" + active).length){ //check element is exists.
$("#" + active).slideUp(animspeed, function() {changeTab(tab)})
}else{
changeTab(tab);
}
}

Toggle Galleria Full Screen Mode

I am wondering if anyone knows how to toggle between full screen and normal mode in Galleria
The only way I can think of is to switch between themes : default, and Fullscreen theme (which i bought from there)
If you know an even better way, I would appreciate your help.
I’m just going to add to #Ohgodwhy’s answer:
The best way to get the Galleria instance and use the API is to use the Galleria.ready function:
Galleria.ready(function() {
var gallery = this; // galleria is ready and the gallery is assigned
$('#fullscreen').click(function() {
gallery.toggleFullscreen(); // toggles the fullscreen
});
});
Or, you can access the instance via the $.data object if you know that the gallery is initialized:
$('#fullscreen').click(function() {
$('#galleria').data('galleria').toggleFullscreen(); // toggles the fullscreen
});
I am assuming you have a link/button with the ID 'fullscreen' and the gallery is at ID 'galleria'.
I'm using:
lightbox: true,
before Galleria.run(). This allows you to display fullscreen Overlay after clicking on image in the gallery.
This should work:
JS
Galleria.loadTheme('http://aino.github.com/galleria/demos/categories/themes/classic/galleria.classic.min.js');
$('#galleria').galleria();
Galleria.ready(function() {
var gallery = this;
this.addElement('fscr');
this.appendChild('stage','fscr');
var fscr = this.$('fscr')
.click(function() {
gallery.toggleFullscreen();
});
this.addIdleState(this.get('fscr'), { opacity:0 });
});
CSS
.galleria-fscr{
width:20px;
height:20px;
position:absolute;
bottom:0px;
right:10px;
background:url('fullscreen.png');
z-index:4;
cursor: pointer;
opacity: .3;
}
.galleria-fscr:hover{
opacity:1;
}
Where fullscreen.png is an appropriate image of your choice.
The approach from Richard is working very well.
You could also do it by extending Galleria with-out the ready function:
JS
Galleria.run('.galleria', {
// configure
autoplay: true,
lightbox: true,
idleMode: true,
// extend theme
extend: function() {
var gallery = this; // "this" is the gallery instance
//fullscreen button
this.addElement('fscr');
this.appendChild('stage','fscr');
var fscr = this.$('fscr').click(function() {
gallery.toggleFullscreen();
});
// this.addIdleState(this.get('fscr'), { opacity:0 });
}
});`
And if you'd like to use a fontAwesome icon for the maximize icon you can implement it as following (other CSS styles see Richard's post):
CSS
.galleria-fscr:before {
content: "\f065"; /* char code for fa-expand */
position: absolute;
font-family: FontAwesome;
color: #fff;
}
(keep in mind to include the style sheet of fontAwesome with <link rel="stylesheet" href="css/font-awesome.min.css">)
I'm still having one problem with the maximize button. If I'm hovering over it, it doesn't get white and stays gray. Maybe something with the IDLE state is wrong, but I haven't found a solution yet. (If I remove the code line with this.addIdleState(...) the hovering works. I need to do more tests here.)
I'd also like to change the icon from maximize to the minimize icon once the screen is on fullscreen, but I don't know how to do that yet. That's also on my todo list.
Update 07.02.2014
I figured out how to solve these two issues:
For the "IDLE state" issue - I've removed the IDLE state. Because I don't care if these controls are permanently there and now hovering works as expected. Maybe I check another solution later.
To change an icon on click you can do it with CSS and jQuery:
Add an overriding CSS rule below the first before filter of the maximize icon in your CSS e.g.:
.galleria-fscr.minimize:before{
content: "\f066";
}
Add these JS line after gallery.toggleFullscreen() - that toggles the icon with every click between the normal before style and the minimize before style:
$(".galleria-fscr").toggleClass("minimize");
This works also for a play / resume button (rest of the code is the simillar to the fullscreen code):
JS
...
gallery.playToggle();
$('.galleria-pauseResumeBtn').toggleClass("resume");
From the Galleria documentation.
.enterFullscreen( [callback] )
This will set the gallery in fullscreen mode. It will temporary manipulate some document styles and blow up the gallery to cover the browser screen. Note that it will only fill the browser window, not the client screen (javascript can’t do that).
.toggleFullscreen( [callback] )
Toggles fullscreen mode.
If you need any further explanation of the use of these, please don't hesitate to ask.

Categories