I need a few objects on my pages to animate out when a user clicks a link. I want each object to scale and fade out but not all objects such as the navigation buttons.
I was thinking that upon a user clicking a link, the page delays 1 second before opening the redirecting the link to allow fade out giving the animation time to take effect.
Look at the JS event window.onbeforeunload
https://developer.mozilla.org/en-US/docs/Web/API/window.onbeforeunload
It will hopefully be enough to just run the exit animations when this function is triggered - it generally takes the browser around a second to unload the page completely but this varies depending on your browser, page size and cpu speed.
Assuming you're using plain JS and you know how to do CSS transitions, the simple way to make animations occur on page exit is something like this:
window.onbeforeunload = function(e){
document.getElementById('myDiv').className = 'out';
}
Where myDiv id the element you want to animate and out is the CSS class representing the final stage of your transition.
Here is a JSfiddle: http://jsfiddle.net/X5vKS/
If you need finer control over the wait time, you could use the onbeforeunload function with setTimeout to delay the page exit by the length of time of your animation. This is slightly complex for a JS beginner but is quite doable.
Related
Since some time last year, YouTube made it so that every page is not actually loading an entirely new page, but primarily just re-loading the contents in div#content. You can notice this when you click on a link in YouTube and see the red loading bar at the top of the page.
I have a Greasemonkey script that modified elements on YouTube, but now that YouTube doesn't reload the entire page, the Greasemonkey script no longer fires on every "new" page. How can I make the Greasemonkey script fire on every "new" page that I load on YouTube?
I'm using jQuery in this Greasemonkey script. I tried using functions like .on() with DOMNodeInserted but I can't find the right combination to make it work properly. With the event listeners that I've been using, I end up running my script hundreds of times for each page load, such as with the following:
$('div#page').on('DOMNodeInserted', 'div#content', function() { });
Another solution I was thinking of was making all links on YouTube load pages like normal, without the new way that they are doing it.
I figured it out myself after some research. First off, I don't like solutions that use setTimeout. This is often one method suggested in favor over the deprecated DOMNodeInserted for instance (which I use in some of my scripts, but try to avoid as much as possible), but if possible, I always prefer a solution where the script actually executes after a specific event. I've posted the solution I initially used in the first section below, then the final solution I used in the second section. All code below requires jQuery.
Decent solution, but not the best
At first, I had a solution where I added a click event to all A elements, which would run a timer that ran my script after 2 seconds. This isn't elegant, because if the page loads quickly, then there's a split second where the script hasn't run. And if the page loads for more than two seconds, then the script doesn't run at all. Script below:
$('a').click(function()
{
setTimeout(youtubeFunction, 2000);
});
Much better solution
So I began looking for a solution that was related to what I wanted to accomplish. I eventually found other people with a similar problem to mine (such as people wanting to create a Chrome script that modifies YouTube pages). This led me to this particular Stack Overflow solution, which basically says that the red loading bar at the top of YouTube pages was a CSS transition element, and that it created a transitionend (case sensitive) event when it was finished. The code in the linked solution wasn't complete (for me anyway), but it did explain how to achieve a working solution. The code I have runs only once per page, which is perfect. So here's what I have now:
function youtubePageChange()
{
youtubeFunction();
$('body').on('transitionend', function(event)
{
if (event.target.id != 'progress') return false;
youtubeFunction();
});
}
$(youtubePageChange);
To explain the code above, basically I run the code once for when you first load a YouTube page (such as by typing the URL in the address bar). Then for every subsequent click that requires the progress bar, the code runs again.
Red progress bar code
Oh, and for future reference, when the red progress bar appears at the top of YouTube pages, the site temporarily adds a new DIV to the end of BODY, with the following code:
<div id="progress" class="waiting" style="transition-duration: 400ms; width: 99%;"><dt></dt><dd></dd></div>
You can set a listener which gets called when the page has finished loading.
This is for the new YouTube material design:
body.addEventListener("yt-navigate-finish", function() {
//your code
});
And this for the old:
window.addEventListener("spfdone", function() {
//your code
});
(if you are using *monkey, you'll need to use unsafeWindow)
Keep in mind that the old design will be discontinued, so your script may not work after that.
Hooking into the popstate might be an option, but i was unable to make that work correctly for some reason (youtube may be preventing it from propagating), so i came up with this that shows the concept:
var currentState = "";
setInterval(function(){
if (currentState != history.state["spf-referer"]) {
currentState = history.state["spf-referer"];
console.log("Do Stuff!");
}
},250)
Just watches for the history.state to change, at which point it will log. The state should change any time the url changes, even if it wasn't due to a page reload.
Sorry...can't show any significant code because it is too deeply buried within an app but I think I can describe the problem easily. I have a 2 page form that has a large amount of content on page 1 and just a very small amount on page 2. Switching to page 2 is handled by the following:
$('#B2').on('click', function () {
if ($('#page1').valid()) {
// code to show page 2
$('#page1').hide();
$('#page2').show();
All works very well except that when the user is presented page 2 it is very far down the page...the same "relative spot" as they were on with page 1 but it seems to the user as if they are seeing a blank page. If they scroll up they will eventually see the page 2 content. I want to somehow force this window scroll. (Another little "gotcha" is that all of this is in a "wrapped" container within a CMS.) The only thing that seems to work is to actually press the up arrow several times or scroll the mouse wheel.
I have tried to add each of the following lines (individually) immediately after the $('#page2').show();
window.scrollBy(0,-400);
window.scrollTo(0,0);
Any ideas as to what else I can try?
You need to target something on the page. Target id=page2. Execute the code below after your show/hide logic.
$('html, body').animate({
scrollTop: $("#page2").offset().top
}, 2000);
I appreciate the help given...I finally just made a workaround by adding a page before my long page and forcing it to be artificially long (past the "Continue" button) so that it keeps that relative position when the real page is shown. Not exactly an elegant solution but the page added has some information that needed to be shown anyway so no big deal.
Okay, so my problem is that I want to make a page flip transition into this custom url that I am creating through javascript.
$("#btnSave").click(function(e){
e.preventDefault();
window.location = "mypage_with_params.html?" + selectedParams; //selectedParams is a list
return false;
});
What function can I call to make the window fire into this url with a page flip animation?
This is actually a pretty hard thing to do. Transitions between pages don't really work, though it's OK to transition to things on the same page, perhaps using AJAX.
I wrote a little bit up on how to do a basic flip here: http://css3.bradshawenterprises.com/flip/, though browser support isn't that great.
In order to simulate a page transition, you'd need to load the new page via AJAX into a div behind the current one, then flip from one to the other, then likely reset everything using JS.
I am creating an app using jQuery Mobile and PhoneGap.
I "delegate" a button on "tap" to perform some heavy processing and display a loading spinner. If users continue to tap on my app, the taps get queued up and fall through to be processed by the app after the heavy processing completes - and end up clicking on unwanted stuff.
How can I prevent this?
(From what I understand, stopImmediatePropagation doesn't help as these are new user events.)
Thanks
To inactive taps on the whole page you could overlay the whole page with a transparent div. Although it might be considered a borderline hack - this would actually use minimal js and css!
The caveat is that it would not give any visual indicator that the page is inactivated.
To do that one could, use a semitransparent gray for the overlay or, as I've done below, show a loading message.
First off, a small CSS discussion:
To make the div cover the whole page set width and height 100%. To position it correctly, use position:absolute and for the transparent background use an rgba background-color property (see below). You should also declare a z-index (can be increased if needed) to ensure that it goes on top of everything else and remove tap-callout using the -webkit-tap-highlight-color property. Set display to none and then show it during your heavy lifting.
I made a jsfiddle which hopefully clears things up.
Here I've made div with an id of "inactivator" which features the properties discussed above.
I've also made a button with an id of "inactivate" to which I've delegated jQuery's show function.
I also took the liberty to add jQuery Mobile's default loading message to show simultaneously just to give a visual indicator of the app thinking (so it's not mistaken for lag).
Here I've added a timeout function so that the loading message and "inactivator" hides after 5 second. Obviously in your case the same code should instead be fired upon completion of your "heavy processing" rather than after five seconds.
(New, additional answer since I didn't understand the question correctly but the old answer still might be helpful to other people.)
The easiest way I can think of is inactivating the button at the start of your javascript function and then reactivating it when it's suitable:
$('#YourButton').addClass('ui-disabled');
At the end of your function (or whenever you'd want it active again:
$('#YourButton').removeClass('ui-disabled');
So it took me a while to figure it out... you have to return FALSE from the delegate function for parent elements to ignore the event. The return false line below fixes my issue:
$(document).delegate("#finish", "tap", onFinish);
var onFinish = function() {
$.mobile.loadingMessage = "Finishing...";
$.mobile.showPageLoadingMsg();
setTimeout(function(){
HEAVYPROCESSING();
$.mobile.changePage($("#choosearticle"));
}, 50);
return false; // important - stops the two click fall through problem!
}
I intend to have a busy waiting spinner as per shown in this post: How to show loading spinner in jQuery? - since it's the cleanest and easiest to implement:
$('#loadingDiv')
.hide() // hide it initially
.ajaxStart(function() {
$(this).show();
})
.ajaxStop(function() {
$(this).hide();
})
;
and couple it up with the animations from http://www.ajaxload.info/
I have multiple "views" in my page i.e., different parts of my page can be updated/modified with the corresponding ajax calls.
I'd like to "position" this #loadingDiv close to where the 'action is' so to speak. How should I go about doing it?
Few things that come to mind:
Have multiple divs all over the place and have them hidden and show them per element as per the corresponding action - seems naive and wasteful
Have an empty <span></span> to 'hold' the #loadingDiv - show it when something happens in that span. I don't know how to do this though...
Something else??
Basically how best to approach positional busy waiting/signalling rather than have a single global one? Or is the single-global option preferred i.e., To have a "fixed" div, hidden show up on the top/center of the page for every activity?
Just want to know which option most of you have used/preferred to tackle something like that and how do you suggest I go about it...
There are some things to consider:
Can the user cause problems if he interacts with other parts of the page while the request is loading?
In this case block the whole UI with a lightbox like transparent overlay.
Are the actions tiny and small, irrelevant to the rest of the application?
Use the local, positioned spinner. If it's a button, change the button's contents from eg. "Save row" to "Saving..." with a spinner.
If the request is significant but you want to let the user to mess around, and the GUI is complex
You can overlay only parts of the screen. http://sfiddle.net/Lv9y5/39/
Local updates, the non blocking way
Use jQuery.position to create a Spinner object from scratch. It should have a .show(node) and .hide() method, and maybe a .setMessage(txt);
The DOM reference passed to the show method is the element the user clicked on. With the reference, you can use jQuery .position() to determine where to absolute position the loading div. The loading div should be placed after the BODY element.