I've been trying to figure out why opening accordions on this page causes the page to scroll to the top. The accordions are using Bootstrap 3.
I've determined that the code causing it is a click event listener in https://www.parkinson.ca/wp-content/plugins/cornerstone/assets/js/site/cs.6f62d0f.js. Removing this listener from Chrome DevTools solves the issue. Somewhere along the way, code is called within this file that causes the page to scroll to the top.
However, I'm trying not to delve into a plugin's code and, instead, prevent that event listener from firing by creating my own event listener:
document.body.addEventListener("click", (function(e) {
var isAccordion = e.target.getAttribute('data-toggle') == 'collapse';
if (isAccordion) {
var accordionHref = e.target.getAttribute('href');
$(accordionHref).collapse('toggle');
e.stopImmediatePropagation();
}
}));
Unfortunately, I found that, immediately after this code is executed, jQuery creates a TransitionEvent since the accordion CSS classes change, which is eventually picked up by the JS file above, causing the scrolling to happen anyway.
How do I fix this?
Related
I have an xpage (viewed via web browser) which has many <xe:dialog...> controls on it, resulting in bootstrap modal dialogue boxes.
I want to run some client-side script when any dialogue is closed.
So I tried ..
$('.modal').on('hide.bs.modal', function() { ...}
However this didn't work, I suspect because when the xpage is loaded there aren't actually any elements with class 'modal', until one is opened. Then a partial refresh injects the relevant HTML.
So I tried running that line above in the event when the modal opens (in the xpages onShow event), but that didn't fire either. I guess the event might be 'when the modal opens but before it's displayed' meaning the elements aren't ont he screen then either.
So I also tried (hack, hack) a setTimeout of 2 seconds to allow the modal to show first, but still no luck.
So .. question is ..
Using xpages bootstrap modals, via the standard xe:dialog control, how can I attach a client-side javascript event whcih will run when the modal is closed / hidden ?
You can use Event Delegation to bind the listener to a parent element of the (non-existing) modals and trigger a function when a click happens on elements matching the .modal selector in that parent element:
$(document).on("hide.bs.modal", ".modal", function () {...});
I do something similar to this, where a button selection on one modal, closes said modal, and then depending on the button that was clicked, opens the next modal. Instead of doing that, could you not run your script in the same way?
var
currentModal = $(this);
//click next
currentModal.find('.btn-close').click(function(){
currentModal.modal('hide');
OTHER STUFF?
EDIT - My full code:
<script type="text/javascript">
$("div[id^='myModal1']").each(function(){
var
currentModal = $(this);
//click next
currentModal.find('.btn-next').click(function(){
currentModal.modal('hide');
currentModal.closest("div[id^='myModal']").nextAll("div[id^='myModal3']").first().modal('show');
});
//click prev
currentModal.find('.btn-prev').click(function(){
currentModal.modal('hide');
currentModal.closest("div[id^='myModal']").nextAll("div[id^='myModal2']").first().modal('show');
});
});
$(window).on('load',function(){
$('#myModal1').modal('show');
});
</script>
I've been making some basic mobile navigation and am using a click event to show/hide the menu.
A reduced code sample:
jQuery('.menu-button').click(function(){
jQuery('.header-nav').toggle();
console.log('clicked');
});
I've been remotely debugging on mobile and the console.log always works, but the .header-nav toggle() seems to randomly not trigger - I can't spot a pattern to it, but it always remains in the DOM (which it should), so it being somehow removed is not the reason why it is not firing.
Any ideas?
Thanks to Kevin B's comment it seems that the click event is firing multiple times. To fix this, the following was used:
$(element).off().on('click', function() {
// function body
});
Reference: jQuery click events firing multiple times
I'm in the process of teaching myself how to write a jQuery plugin. I am using the jquery-hover-dropdown-box as a base example. It's not just copy/paste though, I've made a number of changes trying to get a better understanding of it all. For example I'm not incorporating the hover event, I added a filter, and currently not using any defaults to name a few. Clicking on a div's scroll bar fires the blur event in I.E is the only post I've found with what looks like a good resolution to this and I tried implementing something similar but was unsuccessful.
Complete Example: jsFiddle
Issue:
I click in the input and the dropdown opens but the first time I click on the scroll bar, the dropdown closes. When I open the dropdown a second time and click on the scroll bar, it does not close (as I would expect). From what I can tell, my issue is in the blur on the input. I understand that when I click in the scroll bar, the input has lost focus. I tried to implement something similar to this post on Scrollbars not working on dropdown in IE8 but was unable to get it working.
Steps to Reproduce:
Click in the input to open the dropdown
Click anywhere in the scroll bar and the dropdown closes (should stay open and scroll)
Click in the input a second time and the dropdown opens
Click anywhere in the scroll bar and the dropdown stays open (as it should)
Question:
What am I doing wrong that is causing the dropdown to close only the first time I click on the scroll bar?
What I've Tried:
When I'm appending the ul to the div (currently commented out around line 68 in the jsFiddle), I added the code below. I figured that if I stopped the action from being triggered with a mousedown on the ul it would fix my issue. Although it did fix the issue in Chrome, it persists in IE8.
Update: I changed the code below from $list.mousedown... to $container.mousedown... since $list is the ul and $container is the div that contains it. My thought was that it extend the area. The result was the same though.
...
$container.append($list);
$list.mousedown(function(e) {
e.preventDefault();
});
...
Since this seemed to be close, I tried taking a similar approach in the blur event. The issue explained above happens when I use this code. In Chrome, clicking the scroll bar does not fire the blur event but in IE8, it does. The first time the dropdown is opened and you click in the scroll bar, it logs "hiding". Open the dropdown again and click the scroll bar and it logs "bind mousedown". Click anywhere outside the dropdown and it closes (as it should) and logs "hiding" (as it should). To me it seems backwards, but obviously I'm not understanding it correctly. (The code below is around line 134 in the jsFiddle)
Code edit: Updated with Goran.it suggestion to prevent multiple bindings from happening.
...
// where $dom is the 'div' containing the 'ul'
$dom.unbind('mousedown.auto_dropdown_box_ul')
.bind('mousedown.auto_dropdown_box_ul', function(e) {
console.log('bind mousedown');
e.preventDefault();
});
setTimeout(function() {
console.log('hiding');
$dom.addClass('auto_dropdown_hide').hide();
}, 100);
...
I've also tried removing the blur event. I know this would prevent the dropdown from closing if you tabbed out of the input but figured it was worth a try. In Chrome it works exactly how I expected, clicking outside the input closes the dropdown, clicking the scroll bar does not close it and tabbing out does not close it. In IE8, clicking outside the dropdown does not close it though, nor does it close when you tab out, but clicking in the scroll bar does work. This is the code I added after removing blur (it's not included in the jsFiddle).
// below where the 'blur' event was
$(document).click(function(e) {
if (e.target == dropdownArray[0].input[0] || e.target == dropdownArray[0].dom[0]) {
console.log('matches');
e.preventDefault();
} else {
console.log('does not match');
dropdownArray[0].dom.addClass('auto_dropdown_box_hide').hide();
}
});
Again, this is my first attempt, I'm still learning. I'm sure there are multiple things that I'm probably doing wrong, that I can improve, etc. Before I tackle those, I would just like to understand what I'm doing wrong here and what I need to do to correct it. After reading the plugin concepts, I know there is much for me to learn.
I found few issues on a first look, you should change the :
$dom.bind('mousedown.auto_dropdown_box_ul'
to:
$dom.unbind('mousedown.auto_dropdown_box_ul').bind('mousedown.auto_dropdown_box_ul'
To prevent multiple events binding to the dom node, you can also use .one event handling of jQuery.
In the same event handling you should also put:
console.log('bind mousedown');
e.preventDefault();
return false;
To be sure event is not firing.
Hope this helps (I'm not having IE8 for a long time now)
I believe I finally figured this one out. After multiple tries I thought I'd change up the format to one that seemed, at least to me, a little more straight forward.
Here is the complete jsFiddle
The underlying fix was correctly setting/adjusting which element has focus and when. Since mousedown executes before click, I stuck with that event on the dropdown. In the mousedown event, I set isVisible = true and set focus back on the input (although the latter is not completely necessary). In the blur event, I'm checking isVisible. If it's true, that means that a click happened in the scroll bar so don't close the dropdown. If it's false, close the dropdown. Throughout events, I'm keeping track of isVisible so I know it's state when blur executes. Again, I changed up the format so the two fiddles do look different. I'm sure I could go back and implement something similar to the original fiddle and get it working but I just liked this way more. Here is a snippet of the relevant changes:
{
// some code above
// where $list is the 'ul'
$list.bind('mousedown', methods.onDropdownMousedown);
// where $obj is the 'input'
$obj.bind('blur', methods.doOnBlur);
},
onDropdownMousedown: function(e) {
$input.focus(); // not really needed, just in case
isVisible = true;
},
doOnBlur: function(e) {
if (isVisible) {
$input.focus();
isVisible = false;
} else {
// where $container is the 'div' containing the list
$container.addClass('auto_dropdown_box_hide').hide();
isVisible = false;
}
isVisible = false;
}
I'm using this script
jQuery(document).ready(function($) {
$(".scroll").click(function(event){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 2000);
});
});
in order to smooth scroll down when my nav elements are clicked... the problem is that if a link is clicked before page finish loading, when it finishes the page will go back to top again.
I thought event.preventDefault(); was to avoid that. Help please.
you should use the document.onLoad event instead.
document.ready is invoked after all of the HTML is brought down into the document and ready for parsing.
onLoad on the other hand is invoked after all images / resources are loaded into the page as well.
If you wait for this event, then you should have desired results. although they won't have any click functionality until then.
Furthermore, preventDefault does not avoid this. All that does is disable the default action of the element you apply it to. so it prevent's whatever the default action would be for your 'scroll' elements
I have a silly (and hopefully easily fixed) problem, which I will now attempt to describe.
The scenario-> I am trying to create a context menu using HTML / CSS / JS. Just a DIV with a high z-order that appears where a user right-clicks. Simple, and that portion works. The portion which does not is my attempt to make the menu disappear if the user clicks somewhere where a context menu is not supported; I am attempting to achieve this end with a general function in the BODY tag that fires onclick. Since the BODY tag is given a z-order of -1, and any other tags which might trigger the context menu to appear are given a higher z-order value, my hope was that if I right-clicked an element with a z-order of, say, 3, then it would fire the showMenu() function; instead, it appears that it does this, as well as passes the event to the underlying BODY tag, which causes the menu to become hidden again.
As you might imagine, it is incredibly frustrating. Does anyone know how to make prevent events from being passed down? (The INPUT button is what you may want to look at, the A anchor is something similar, but not coded to work just yet).
Here's the HTML code:
http://pastebin.com/YeTxdHYq
And here's my CSS file:
http://pastebin.com/5hNjF99p
This appears to be a problem with IE, Firefox, and Chrome.
A lot of DOM events "bubble" from the bottom object up through container objects, which means they'll eventually reach the body. But you can stop this - try adding the following code to the click handler on your element:
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
...where e is the variable you already have in your function representing the event object.
event.stopPropagation(); should work in modern browsers, but the old IE way was event.cancelBubble = true; - to be safe you can just do both (but as shown above check that .stopPropagation is defined before trying to call it).
With the above code added, if you click on the element your function will stop container objects (include the body) from seeing the click. If you click somewhere else your function isn't called so then the body will process the click.
There's more info about this at MDN and QuirksMode.org.
Note: I've ignored the z-order issue because in this case I think it is a non-issue - all elements are descendents of the body so (unless you stop it) I would expect events to bubble to the body regardless of z-order.