'transitionend' event does not fire consistently - javascript

The following code works inconsistently with Chrome but also Firefox (with 'transitionend'). The function slogan_fade_next is just console.log('end');. I always get the classname applied to the first span element but anything after that is hit-and-miss when I click the refresh button, reload, or anything else.
The class of slogan-fadein applied to slogan[] changes the opacity of the element from zero to one but the callback function fade_setup isn't called consistently.
function fade_setup(){
var el = document.getElementsByClassName('slogan')[0];
el = el.getElementsByTagName('span');
for(var i=0;el[i];i++){
el[i].addEventListener('webkitTransitionEnd',slogan_fade_next,false);
}
el[0].className='slogan-fadein';
}
document.addEventListener('DOMContentLoaded', fade_setup);

instead of
document.addEventListener('DOMContentLoaded', fade_setup);
can you use
document.addEventListener('load', fade_setup)
With your current implementation, the JavaScript may be running before the browser has finished applying styles and, therefore, before any transitions are defined.

The problem is caused by a timing issue with applying the styles and anything else as mentioned by Stephen. The problem is, things aren't settled by the time I try to fire the first fade in so I triggered that with window.onload=slogan_fade_next;. Everything has settled in by the time my first element has done its thing.
I've given absolutely no more thought to this other than "it works" and I'm sure I'll come up with a better way to do this.

Related

Run function onscroll, unless parent has class in Javascript

I'm puzzled; I have a window.onscroll = function() { .. } which works fine, except for some cases. In these cases, the <html> element has one of two specific classes. So that seems easy enough; don't run the onscroll if either of those classes exist. But, how?
Roughly, I have this set up;
if (!html.classList.contains('firstClass') && !html.classList.contains('secondClass')) {
window.onscroll = function() { ... }
}
But the onscroll function runs every time. I've also tried to put the if statement inside the onscroll, but no luck.
Now I'm unsure if the markup of the if statement is correct. So I've also tried in in a simpler fashion, where the statement is always true or false;
if (html.classList.contains('thirdclass') { }
In this example, the code either runs or it doesn't, no matter if the class gets added or removed. It might have to do with how the DOM works, and the html element maybe not getting picked up?
I'm unsure if the markup in the if statement is even correct; all sources I find on this use jQuery, and none of them clearly state how to run if (element has one of either two class classes) {}.
Who can help me get on the right track?
edit:
Well slap me silly. I set up a jsfiddle to demonstrate, but in there it does work as expected(!). This leaves me to think that it has to do with the ecosystem this code is running in (Magento 2 frontend). Maybe how the js is initialized? (Yes, I do need to call jquery sadly);
define([
"jquery"
],
function($) {
"use strict";
// code here
});
Could that be the case?
Based on your description, I guess your html tag initially dont have the classes firstClass and secondClass.
So, here the problem is that you are registering an event listener to onscroll event only if the html element don't have the classes firstClass and secondClass. As initially it is true (because initially the html element doesn't have the class required classes), it will register the event listener and it will always fire whenever you scroll.
Also your code will never fire the event listener if initially the classes are firstClass and secondClass.
Now, what you need to change to achieve your goal is to add the if statement inside the onclick listener instead of outside.
Here's the code:
window.onscroll = function () {
if (!html.classList.contains('firstClass') && !html.classList.contains('secondClass')) {
// Do stuff
}
};
What the above code does is that it first registers the event listener no matter what the class of the html element. But it will execute the code inside the if block only if the html element don't have both the classes. So, your goal is achieved here.
Hope this helps :)

Prevent anchor tag to jump

It is my first post on SO, I am using it already quite a while, always found a solution via search. Now I'm starting to dig deeper into programming - right now learning Java Script - and I couldn't find the exact answer for my beginner problem:
I've created a simple photo gallery where the thumbnails point to the image via href. The images are not displayed by default. By clicking on a thumbnail, the corresponding image appears thanks to the :target pseudo element. This way I can bypass the cascading nature of my HTML structure and address elements higher in hierarchy.
See fiddle:
https://jsfiddle.net/ahu1kaqf/
The problem is, that this "hack" has the side effect of putting the image to the very top of the window due to its default anchor jump behavior.
So what I want to accomplish is to turn off or bypass just the jump behavior.
Therefore, solutions with JS like "preventDefault" or "return false" are not suitable as they turn off the complete anchor behavior.
My idea was to read the yScroll position just before the click and pass it to another function which triggers just after the page jump. By appending an onclick event on the anchor tag I found out that the function executes before the actual jump and I can read the current scrollY position:
function posY(){
console.log(window.scrollY);
scry = window.scrollY;
}
Then, after the anchor event has finished, I would like to pass the variable scry to another function which triggers just after the anchor jump to undo the jump:
function undoJump(){
window.scrollTo(0, scry);
}
It doesn't really work with a click event as the function triggers before the actual jump.
The js code in the fiddle is in script tags because putting just the functions into the js window (of course without script tags) shows an error in the console, I don't know why...
Sorry, I'm really a beginner, thank you all for your help!
https://jsfiddle.net/ahu1kaqf/1/
var classname = document.getElementsByClassName("thumb");
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener("click", posY);
}
function posY(e){
e.preventDefault();
console.log(window.scrollY);
}
Remove the onclick as it's just not the best way to do it. Add a class to the links OR use querySelectorAll based on the parent class. The benefit here is, you don't have to remember to add a class or a onclick. It's less code to deal with and easier to manage.
https://jsfiddle.net/ahu1kaqf/2/
In either case, you can stop the normal event behavior with e.preventDefault();
For the second part, you'll probably just want to set a global in this case. Set a global outside all of the functions and change it on click. You could probably get more complex with objects, and promises and such, but, honestly, it'd be just as easy to set a global value. It's good to try to avoid them, but they can be simple useful solutions depending on the overall complexity of the application in question.
Yes, you need to prevent the default action (which is a navigation action).
In modern browsers, that means you can do this (note I'm passing the global event object as a parameter):
<div class="thumb">thumb1</div>
Then in your js code you can do this:
function posY(e){
e.preventDefault()
console.log(window.scrollY);
}

Wicket - IE8 - Javascript event listeners arent executed, when tags are dynamically added over ajax

I have spent several hours, maybe days stucked on a very weird problem :(
I am creating an application that is based on the Wicket solution. It works perfectly in IE9,IE10, Chrome and FF. Strange is, that i have tested it in IE8 too and it works in 99% of cases (IE instances on different computers + totally identical version of IE8) too. But now the PROBLEM.
PROBLEM:
I am creating dynamic content over AjaxLink button. After clicking the button the WebMarkupContainer model is changed and WebMarkupContainer is refreshed (based on Ajax, so the page isnt reloaded complete, but only the container is).
Every item in the container has added AjaxFormComponentUpdatingBehavior. In onComponentTag method, i add tag.put("onchange","some jsFunctionCalling....");. The problem is, that after clicking on the item, no event is invoked. I have tried add the onchange listener over .add(new AttributeModifier.....), but the result is still same. As i have said, i tried the same code in the same version of IE on another PC and it works perfectly. Interesting is, that after refreh of the page everything work perfect, until new item to WebMarkupContainer is added. After that no item listeners work until the page is refreshed again.
One of the latest idea, that i got is, that problem isn't in the code, but in the settings of IE (maybe security). Have anybody any idea? What setting could be set different and cause these problems? Is there any settings on Wicket site, that can solved this? Is there some setting that can blocked registration of these listeners to DOM, if they are added dynamically over ajax?
I didn't tried it but IMHO there are three options you can try:
Instead of adding "onchange" by yourself, add OnChangeAjaxBehavior and make all work in wicket. Downside is server roundtrip on every event.
Add data-attributes (AttributeModifier.append("data-param1", "foobar")) to push your parameters into html and call ajaxRequestTarget.appendJavaScript("attachOnChangeHandler()"); after the click event on the AjaxLink. attachOnChangeHandler() should be your js function to add onchange handler to every item which needs it. And over data-attributes you can access your parameters.
Since Wicket 6: To avoid mixing to much js with Wicket, you could subscribe to one of the global AJAX events.
The solution in your case would be almost the same as in 2. Just add a listener in js for "/ajax/call/success"
(see if the call relates to your component by checking the id) and add the onchange handler there.
This is IMHO the best solution without mixing custom js with Wicket.
The solution provided by #peterchon (attaching event handlers higher in the DOM than the elements which are going to be replaced by wicket) would work in every other case, but you have "onchange" which applies only to input, textarea and select elements.
BTW the page is "working" after refresh, since the whole page is rendered and browser can properly attach the handlers.
You can try this method:
/* this will catpure the target that triggered the event */
function getEventTarget( e ) {
e = e || window.event;
return e.target || e.srcElement;
}
function doSomething( e ) {
var that = getEventTarget( e );
if( that.tagName.toLowerCase() === 'a' ) { // specify the target, in this cas <a>
// Do something
}
}
parentElement.onclick = doSomething;
This script basically will capture any event, then will pass the variable of target to the function that will perform something.
Hopefully this will work for you.
You try to achieve something using a non-wicket JavaScript/Ajax way. This is fine, but also makes it very messy.
Please check this fine article about passing parameters from JavaScript to wicket and vice versa. I think it will suit your needs.
http://wickedsource.org/2013/01/07/rolling-your-own-ajax-behavior-with-wicket/

Twitter Bootstrap Transition Conflict prototypejs

I created a fiddle for Collapse feature of Twitter Bootstrap using the markup from the demos on your page that works: http://jsfiddle.net/Rymd7/1/
Then once, I add in a reference to prototypejs collapse functionality stops working on each accordian group after clicking through it a couple of times. http://jsfiddle.net/p5SAy/1/ I'm not sure what the issue is or how to correct it.
Is this a bootstrap issue or is there a way to get around this and have these two js libraries exist on the same page?
I have tried jQuery noConflict with no success, but any help is appreciated.
If you can send me back a working fiddle that would be great...or any insight.
Thanks. -John
You are using jQuery and Prototype simultaneously without jQuery.noConflict(). After
<script type='text/javascript' src='http://code.jquery.com/jquery-1.7.js'></script>
<script type='text/javascript' src="http://ajax.googleapis.com/ajax/libs/prototype/1.7.0/prototype.js"></script>
this line was causing javascript error:
$(window).load(function(){
Revised fiddle: http://fiddle.jshell.net/ymbsr/5/ - open http://fiddle.jshell.net/ymbsr/5/show/ in different browsers.
P.S.
After removing jQuery/Prototype conflict I can see that ih Chrome 21 and Opera 12.02 accordion transition never ends (in bootstrap-collapse.js Collapse.transition initiates transition but complete() is never called). Further invocations of Collapse.show()/hide() on the same element are exiting after if (this.transitioning) return.
In Firefox 15.0.1 accordion works fine.
P.P.S.
This strange behavior is a consequence of two features:
this.$element.trigger('hide') (in Collapse#transition()) tries to invoke $element.hide() if method hide() is present in element - that's by design:
Note: For both plain objects and DOM objects, if a triggered event
name matches the name of a property on the object, jQuery will attempt
to invoke the property as a method if no event handler calls
event.preventDefault(). If this behavior is not desired, use
.triggerHandler() instead.
With Prototype in each browser supporting HTML element prototype extensions $element will definitely have hide() method, which actually hides element via setting element.style.display = 'none'.
In current versions of Chrome and Opera transition end event (one of webkitTransitionEnd, oTransitionEnd, otransitionend) will not fire if element is hidden (has display: none style). Firefox ends its transition more successfully, but also may not fire event under some circumstances:
Note: The "transitionend" event doesn't fire if the transition is aborted because the animating property's value is changed before the transition is completed.
How to fix it:
File a bug for bootstrap-collapse.js - it shouldn't rely only on transition end event
File a bug for bootstrap-collapse.js - its hide event intersects with other frameworks (at least with Prototype, but any other framework extending element prototypes may be affected).
Temporarily patch Collapse#transition() from bootstrap-collapse.js as in http://fiddle.jshell.net/ymbsr/7/ - either disable event triggering or change event names.
jQuery.fn.collapse.Constructor.prototype.transition = function (method, startEvent, completeEvent) {
var that = this
, complete = function () {
if (startEvent.type == 'show') that.reset();
that.transitioning = 0;
that.$element.trigger(completeEvent);
}
//this.$element.trigger(startEvent);
//if (startEvent.isDefaultPrevented()) return;
this.transitioning = 1;
this.$element[method]('in');
(jQuery.support.transition && this.$element.hasClass('collapse')) ?
this.$element.one(jQuery.support.transition.end, complete) :
complete();
};
I am using Magento and have had bootstrap/ prototype problems for years. I tried all of the above without luck. Ha you will not believe what worked!
I moved prototype as one of the first scripts to be loaded and left all of the others to be loaded after. That worked for me. I dont know why I didnt try the earlier.

Remove window "resize" listener

This question relates closely to the stack overflow question "window.resize event firing in Internet Explorer".
The Issue:
I am attempting to fix a resizing issue in Internet Explorer 8. Currently, the resize function gets called repeatedly causing IE to essentially lock up - the user can no longer use buttons that call Javascript actions.
Previous Attempt(s):
var resizeTimeout;
var resizeHandler = function() {
clearTimeout(resizeTimeout);
//$(window).unbind('resize', resizeHandler);
//window.removeEventListener('resize');
window.removeEventListener('resize', resizeHandler, false);
scrollHandler();
setTimeout("$(window).resize(resizeHandler);", 100);
return true;
}
//$(window).resize(resizeHandler);
window.addEventListener('resize', resizeHandler, false);
Problems: It appears that window cannot implement addEventListener or removeEventListener and unbinding jQuery doesn't stop IE from continuing to freak out. It works fine in all other browsers.
Desired Behavior: The goal here is really to get IE to stop repetitively executing code so other functions like onclick events work.
Does anyone know how I can remove the resize event after it's been added or simply make IE stop being retarded. (<-- Extra points if you can make IE not be retarded.)
Resolution: Inside of the scrollHandler function a variable was not declared using the var prefix. Adding var made all the evil fairies go away.
I think you're going about this the wrong way. What you should be doing is using that timeout to block the invocation of "scrollHandler()" until the window resizing activity has paused for a little while (like the 100ms delay you're using).
var resizeTimeout;
function resizeHandler() {
cancelTimeout(resizeTimeout);
resizeTimeout = setTimeout(scrollHandler, 100);
}
$(window).resize(resizeHandler);
Trying to do DOM updates (which I assume to be what goes on inside "scrollHandler") in a "resize" handler is really not a good idea in any browser. By doing that, you won't need to get rid of the "resize" handler at all.
edit — OK now I see that that's effectively what you were trying to do. I still think it's a lot simpler this way.

Categories