WordPress dropdown menus overlapping - hovering one opens another - javascript

So I'm creating a theme for WP, and the menu is acting up. I suppose the dropdowns somehow overlap in the back, sometimes when I hover over one item, its submenu opens, but as I move the curses towards its submenu, the submenu of the item next to it opens instead.
Example:
Any ideas?
EDIT:
I noticed that when I hover over a top-level menu item for more than 2 seconds and then move the curser towards the submenu, the glitch doesn't happen.
What I found after doing a lot of digging is that once I hover over a top-level menu item, there is a class being added to it by my theme (Divi), and when I move the curser to another, the class is removed, but with a certain delay, so when I hover over a new top-level menu item, the previously hovered one still has the class appended to it for about 1 second.
I found the following code in the theme's files and I assume it is to blame, however I tried changing the 200 to 0 and the delay is still taking place (I'm tracking the classes being added and removed as I hover using DevTools on Chrome):
window.et_pb_toggle_nav_menu = function($element, state, delay) {
if ( 'open' === state ) {
if ( ! $element.closest( 'li.mega-menu' ).length || $element.hasClass( 'mega-menu' ) ) {
$element.addClass( 'et-show-dropdown' );
$element.removeClass( 'et-hover' ).addClass( 'et-hover' );
}
} else {
var closeDelay = typeof delay !== 'undefined' ? delay : 200;
$element.removeClass( 'et-show-dropdown' );
$element.removeClass( 'et-touch-hover' );
setTimeout( function() {
if ( ! $element.hasClass( 'et-show-dropdown' ) ) {
$element.removeClass( 'et-hover' );
}
}, closeDelay );
}
};

Have you tried playing with the z-index on hover? Something like:
.item {
z-index: 0;
&:hover {
z-index: 1;
}
}
I'm guessing right now without the code to use as a reference.

Related

React + Rsuite dropdown: prevent page from scrolling down when dropdown items go off screen

I'm making a chrome extension using react. In my app I'm using the Rsuite Dropdown component. I'm using nested menus with lots of items, so on some of the menus the list of items in the dropdown extends past the screen. The issue is that I hover over the menu, the dropdown opens, it extends past the screen, the window scrolls to the bottom of the dropdown, my mouse is now shifted off of the menu selector so the dropdown closes and the window scrolls back up. My goal is to have the dropdown open without the window scrolling down to the bottom.
Gif of problem
My Code:
I just have one component in my App.js, which is just a dropdown of all my bookmarks
<Dropdown title="Bookmarks">
{bookmarks.map((mark) => {
return (mark.children === undefined ? <BookmarkItem Bookmark={mark}/> : <BookmarkFolder Bookmarks={mark}/>)
})}
</Dropdown>
For all the bookmarks, I check if its a folder or an actual bookmark, if its a folder, I insert a folder component (which does this exact thing recursively)
const BookmarkFolder = ({Bookmarks}) => {
return (
<Dropdown.Menu title={Bookmarks.title}>
{Bookmarks.children.map((mark) => {
return (mark.children === undefined ? <BookmarkItem Bookmark={mark}/> : <BookmarkFolder Bookmarks={mark}/>)
})}
</Dropdown.Menu>
);
};
If its a bookmark, I display the bookmark title as a dropdown item
/* Limit title length to 25 characters */
const limitLength = (title) => {
if (title.length > 25) {
return `${title.substring(0, 22)}...`;
}
else {
return title;
}
}
return (
<Dropdown.Item>
{limitLength(Bookmark.title)}
</Dropdown.Item>
);
I've been trying to programmatically scroll the page up when a bookmark item renders:
useEffect(() => {
window.setTimeout(() => window.scrollTo(0,0), 500);
}, []);
But this isn't working.
Help is greatly appreciated!

How to make an event toggle HTML class on one element while removing it from others?

So, I have a little project that showcases a set of images, small-size. And when you click on one of them, it expands. Basically, JavaScript adds an HTML class of "active" to an element, which transforms it.
const panels = document.querySelectorAll('.panel');
/*adding an event for every image panel that makes
panel active on click */
panels.forEach(panel => {
panel.addEventListener('click', () => {
removeActiveClasses()
panel.classList.add('active')
})
})
//a function that removes active class from a panel
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('active')
})
}
So, when you click on the element, it removes all the .active classes from every other one, and then adds it to a target element. It works perfectly, but I want to be able to delete a class from an element that is currently active, so when I click on an expanded picture, it collapses back. Changing panel.classList.add to panel.classList.toggle obviously doesn't work, because it first removes all active classes and then "toggles" it (or adds, because there is none). How can I delete a class from active element on click, while remaining the other functionality?
Solution: Thanks to CBroe I've managed to make it work. The code now looks like the following:
const panels = document.querySelectorAll('.panel');
/*adding an event for every image panel that makes
panel active on click */
panels.forEach(panel => {
panel.addEventListener('click', () => {
const isActive = panel.classList.contains('active')
removeActiveClasses()
panel.classList.toggle('active', !isActive)
})
})
//a function that removes active class from a panel
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('active')
})
}
A much more efficient way would be to :
document.getElementsByClassName('panel').addEventListener('click', function() {
for (let ele of panels) {
ele.classList.remove('active')
}
let panel = this
panel.classList.includes('active') ? panel.classList.remove('active') : panel.classList.add('active')
)

on item click, items re-renders and scroll comes to the top which is undesired

I have made a component where I am rendering grids of items. On clicking one item, the item is being selected. However there are many items present so there is scroll bar. Whenever I click on an Item, the component is re-rendered (as I am putting the selectedItem in my state), which further re-renders all the other items. But when I click an item after scrolling to the bottom (or middle), the component renders to the top, however I want that to remain on the position it was being clicked.
The components are as follows :
Full-Screen (made using react-portal, contains onClick and changes its state)
--TilesView (all tiles wrapper which renders all the tiles and has an ajax call)
--all Tiles (single tile element)
The part code is as follows :
FullScreen:
componentDidMount() {
if (this.props.selectedPost) {
this.setState({
selectedPost: {
[this.props.selectedPost[0]]: true
}
});
}
}
render() {
const that = this;
//Todo: User fullpage header when space is updated
return (
<Portal container={() => document.querySelector('body')}>
<div className={styles.container}>
<FullPageForm onHide={that.props.onCancel} closeIcnLabel={'esc'} bgDark={true}>
<FullPageForm.Body>
<span className={styles.header}>{'Select Post'}</span>
<div className={styles.body}>
<ExistingAssets onCreativeTileClicked={this.handlePostClick}
selectedCreatives={this.state.selectedPost}
showSelectedTick/>
</div>
</FullPageForm.Body>
</FullPageForm>
</div>
</Portal>
);
}
handlePostClick = (adCreativeAsset, id) => {
event.preventDefault();
this.setState({
selectedPost: {
[id]: adCreativeAsset
}
});
}
In my handlePostClick, I tried doing event.preventDefault() but it didn't work. I have no clue why this is happening, thanks in advance.
Try changing your handlePostClick definition to
handlePostClick = (e, adCreativeAsset, id) => {
e.preventDefault();
//blah blah what you want
}
and in your JSX change onCreativeTileClicked={this.handlePostClick} to onCreativeTileClicked={this.handlePostClick.bind(this)}.
The event you were prevent-defaulting (stopping propagation in real terms) isn't the real event coming from the click but a synthetic one that can be summoned to fill in for an event when there isn't one. You need to stop propagation for the real event.
Hope this helps.

Changing Tab on Image Click

I try for some time now to set the active Tab of this theme when the user clicks an image (above the tabs).
http://www.elegantthemes.com/preview/Nova/
I found the normal tab change code in the scripts.php, but I have no idea of how to change it to make it work with clicking any image that are above the tabs.
$service_li.find('a').click(function(){
var $a = jQuery(this),
next_tab = $a.parent('li').prevAll().length,
next_tab_height = $service_tabs.find('>div').eq(next_tab).outerHeight();
if ( next_tab != active_tab ) {
$service_tabs.css({height:next_tab_height});
$service_div.filter(':visible')
.animate( {opacity: 'hide'},500, function(){
jQuery(this).parent().find('>div').eq(next_tab).animate( {opacity: 'show'},500 );
} )
;
$service_li.removeClass(active_tabstate).filter(':eq('+next_tab+')').addClass(active_tabstate);
active_tab = next_tab;
}
return false;
}).hover(function(){
if ( !jQuery(this).parent('li').hasClass(active_tabstate) && !is_ie ) jQuery(this).fadeTo('slow',.7);
}, function(){
if (!is_ie) jQuery(this).fadeTo('slow',1);
});
}
Maybe someone can help out ?
I don't quite understand what or better yet, why you've conjured that thing over there, but i would use jQuery Tabs, so you can easily access the tab object by entering the id in the URL (firefox only) or by using something like.. .tabs( "select" , index ) , you can find more documentation in the URL above.

jquery and multiple element hover check

I have 3 boxes and once user hovers any, if changes the content of the big main div from default to the related div via featVals hash table
At the if ($('#estate-feature, #carrier-feature, #cleaning-feature').is(':hover')) { part of my code, I want to check if any of these 3 div boxes are currently hovered, if not display the default content (defaultFeat variable).
However I am getting Uncaught Syntax error, unrecognized expression: hover error from Google Chrome Javascript Console.
How can I fix it ?
Regards
$('#estate-feature, #carrier-feature, #cleaning-feature').hover(function () {
var currentFeatCont = featVals[$(this).attr('id')];
headlineContent.html(currentFeatCont);
}, function () {
headlineContent.delay(600)
.queue(function (n) {
if ($('#estate-feature, #carrier-feature, #cleaning-feature').not(':hover')) {
$(this).html(defaultFeat);
}
n();
})
});
:hover isn't an attribute of the element. Also, you are binding to the hover out there so you know that you have left the hover and can restore the default content. If you want the hover-triggered content to remain for a period after the point has left the trigger element then you'll either need to assume that you aren't going to roll over another trigger or implement a shared flag variable that indicates if the default text restore should be halted. e.g.
var isHovered = false;
$('#estate-feature, #carrier-feature, #cleaning-feature').hover(
function() {
var currentFeatCont = featVals[$(this).attr('id')];
headlineContent.html(currentFeatCont);
isHovered = true;
},
function() {
isHovered = false;
headlineContent.delay(600)
.queue(function(n) {
if (!isHovered) {
$(this).html(defaultFeat);
}
n();
})
}
);

Categories