Why is my javascript preventing the browser from going to a link - javascript

I have a script on http://joelglovier.com to add a class of "active" to each navigation element when it's corresponding section in the document. The script is adapted with permission from w3fools.com, so it was written without my scenario in mind.
The difference is that on w3fools.com, the nav links only refer to elements on the page, whereas in my navigation, there is one element at the end that refers to a new page.
The problem is that as I have adapted it, it works fine for the links that refer to sections on the page. However, for some reason unbeknownst to me (sorry - JS/jQuery novice) it is blocking the browser from following the link to the new page (the Blog link).
I tried reading through the code and understanding what the script is doing - however I cannot seem to understand why it is blocking that external link from being clicked, or more specifically how to fix it.
Can anybody suggest the simplest way to remedy my issue without breaking the original functionality of the script for it's purpose?
See it live here: http://joelglovier.com
Or...
Markup:
<div id="site-nav">
<div class="wrap">
<nav id="nav-links">
Top
Background
Projects
Random
Credits
Blog <span class="icon"></span>
</nav>
</div>
Javascript:
(function($) {
$(function() {
var $nav = $('#nav-links'),
$navLinks = $nav.find('a.scroll'),
cache = {};
$docEl = $( document.documentElement ),
$body = $( document.body ),
$window = $( window ),
$scrollable = $body; // default scrollable thingy, which'll be body or docEl (html)
// find out what the hell to scroll ( html or body )
// its like we can already tell - spooky
if ( $docEl.scrollTop() ) {
$scrollable = $docEl;
} else {
var bodyST = $body.scrollTop();
// if scrolling the body doesn't do anything
if ( $body.scrollTop( bodyST + 1 ).scrollTop() == bodyST) {
$scrollable = $docEl;
} else {
// we actually scrolled, so, er, undo it
$body.scrollTop( bodyST - 1 );
}
}
// build cache
$navLinks.each(function(i,v) {
var href = $( this ).attr( 'href' ),
$target = $( href );
if ( $target.length ) {
cache[ this.href ] = { link: $(v), target: $target };
}
});
// handle nav links
$nav.delegate( 'a', 'click', function(e) {
// alert( $scrollable.scrollTop() );
e.preventDefault(); // if you expected return false, *sigh*
if ( cache[ this.href ] && cache[ this.href ].target ) {
$scrollable.animate( { scrollTop: cache[ this.href ].target.position().top }, 600, 'swing' );
}
});
// auto highlight nav links depending on doc position
var deferred = false,
timeout = false, // so gonna clear this later, you have NO idea
last = false, // makes sure the previous link gets un-activated
check = function() {
var scroll = $scrollable.scrollTop(),
height = $body.height(),
tolerance = $window.height() * ( scroll / height );
$.each( cache, function( i, v ) {
// if we're past the link's section, activate it
if ( scroll + tolerance > v.target.position().top ) {
last && last.removeClass('active');
last = v.link.addClass('active');
} else {
v.link.removeClass('active');
return false; // get outta this $.each
}
});
// all done
clearTimeout( timeout );
deferred = false;
};
// work on scroll, but debounced
var $document = $(document).scroll( function() {
// timeout hasn't been created yet
if ( !deferred ) {
timeout = setTimeout( check , 250 ); // defer this stuff
deferred = true;
}
});
// fix any possible failed scroll events and fix the nav automatically
(function() {
$document.scroll();
setTimeout( arguments.callee, 1500 );
})();
});
})(jQuery);

You're trying to tell it to scroll to "http://..." which doesn't exist on the current page, so it fails and does nothing.
It should work if you change your code to this
// handle nav links
$nav.delegate( 'a', 'click', function(e) {
// alert( $scrollable.scrollTop() );
e.preventDefault(); // if you expected return false, *sigh*
if ( cache[ this.href ] && cache[ this.href ].target ) {
// preserve http:// links
if (this.href.substr(0, "http://".length) == 'http://')
location.href = this.href;
else
$scrollable.animate( { scrollTop: cache[ this.href ].target.position().top }, 600, 'swing' );
}
});

Related

Change URL hash on scroll and keep back button working

On a one page layout with fixed top menu and anchor navigation I have a "scrollspy" in place that changes the fragment identifier on scroll, gives the menu link an active class depending on scroll position and animates the scrolling to the anchor with Velocity.js.
Unfortunately what it also does, when clicking the browser back button it takes me through all the steps of the scrolled way, meaning I load the site and scroll down and up a tiny bit and then hit the back button frequently the browser will also scroll down and up but won't go to either the last visited id or back in browser history actually.
Here is the jsfiddle.
// jQuery on DOM ready
// In-Page Scroll Animation with VelocityJS
// ------------------------------------------------ //
// https://john-dugan.com/fixed-headers-with-hash-links/
$('.menu-a').on('click', function(e) {
var hash = this.hash,
$hash = $(hash)
addHash = function() {
window.location.hash = hash;
};
$hash.velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], complete: addHash });
e.preventDefault();
});
// ScrollSpy for Menu items and Fragment Identifier
// ------------------------------------------------ //
// https://jsfiddle.net/mekwall/up4nu/
$menuLink = $('.menu-a')
var lastId,
// Anchors corresponding to menu items
scrollItems = $menuLink.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+ 30; // or the value for the #navigation height
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
$menuLink
.parent().removeClass("active")
.end().filter("[href='#"+id+"']").parent().addClass("active");
}
// If supported by the browser we can also update the URL
// http://codepen.io/grayghostvisuals/pen/EtdwL
if (window.history && window.history.pushState) {
history.pushState("", document.title,'#'+id);
}
});
With the above code the following works fine:
The hash or fragment identifier updates fine when clicked on the menu link using VelocityJS for the scrolling animation.
The active class is given to the corresponding menu link on scrolling.
The fragment identifier also updates fine when scrolling instead of clicking the menu link.
Question
Part 1: When you scroll a tiny bit on the fiddle and then hit the back button you will see that the scrollbar "travels" the exact same way, remembering the scrolling that was done.
I need the back button to work like it normally does.
a) Either go back in browser history and return to the page/site you were on and
b) when having clicked an anchor link (i) and then anchor link (ii) and then the back button the page should go back to anchor link (i).
Part 2: Since history.pushState is not supported in IE8 I am looking for a way to use window.location.hash = $(this).attr('id'); instead. No matter what I have tried towards the end of the code I simply cannot get window.location.hash = $(this).attr('id'); to work. I don't really want to use HistoryJS or something for this but am interested to learn this and write it myself.
Apart from the back button broken behaviour all the other behaviour that I want is already there, now I just need to fix the back button behaviour.
edit
I think I might have found a solution here, will test and then reply in detail if I get this to work.
Related:
smooth scrolling and get back button with popState on Firefox - need to click twice
jQuery in page back button scrolling
Modifying document.location.hash without page scrolling
How to Detect Browser Back Button event - Cross Browser
To answer the first part of your question, if you don't want to pollute the browser's history, you can use history.replaceState() instead of history.pushState(). While pushState changes the URL and adds a new entry to the browser's history, replaceState changes the URL while modifying the current history entry instead of adding a new one.
There is also a good article including differences between pushState and replaceState on MDN.
For older browsers I decided to include https://github.com/devote/HTML5-History-API and with this in place I got the desired behaviour (more or less).
This answers has:
- a scroll spy for the menu items and sets and active class to those on scroll
- the scroll spy also works for the URL hash, setting the correct hash depending on the section that is currently scrolled to
- a scroll stop function that checks when the user has stopped scrolling and then takes the value form the currently active menu item and sets that as the current URL hash. This is done on purpose to not catch the sections' anchors while scrolling but only the anchor of the section that the user scrolls to.
- a smooth scroll with Velocity.js when clicking on the menu links as well as when using the back and forward buttons
- functions that reacts to loading and reloading the page, meaning if you enter the page with a specific URL hash for a section it will animate the scroll to that section and if the page is reloaded it will animate the scroll to the top of the current section
The code is a rough sketch and could possibly use a few tweaks, this is just for demo purpose. I think I am still a beginner to please point out obvious errors so that I can learn from those. All links to where code snippets come from are included as well.
// In-Page Scroll Animation to Menu Link on click
// ------------------------------------------------ //
// https://john-dugan.com/fixed-headers-with-hash-links/
// https://stackoverflow.com/questions/8355673/jquery-how-to-scroll-an-anchor-to-the-top-of-the-page-when-clicked
// http://stackoverflow.com/a/8579673/1010918
// $('a[href^="#"]').on('click', function(e) {
$('.menu-a').on('click', function(e) {
// default = make hash appear right after click
// not default = make hash appear after scrolling animation is finished
e.preventDefault();
var hash = this.hash,
$hash = $(hash)
$hash.velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], queue: false });
});
// In-Page Scroll Animation to Hash on Load and Reload
// ----------------------------------------------------------- //
// https://stackoverflow.com/questions/680785/on-window-location-hash-change
// hashchange triggers popstate !
$(window).on('load', function(e) {
var hash = window.location.hash;
console.log('hash on window load '+hash);
$hash = $(hash)
$hash.velocity("scroll", { duration: 500, easing: [ .4, .21, .35, 1 ], queue: false });
// if not URL hash is present = root, go to top of page on reload
if (!window.location.hash){
$('body').velocity("scroll", { duration: 500, easing: [ .4, .21, .35, 1 ], queue: false });
}
});
// In-Page Scroll Animation to Hash on Back or Forward Button
// ---------------------------------------------------------- //
$('.menu-a').on('click', function(e) {
e.preventDefault();
// keep the link in the browser history
// set this separately from scrolling animation so it works in IE8
history.pushState(null, null, this.href);
return false
});
$(window).on('popstate', function(e) {
// alert('popstate fired');
$('body').append('<div class="console1">popstate fired</div>');
$('.console1').delay(1000).fadeOut('slow');
if (!window.location.hash){
$('body').append('<div class="console2">no window location hash present</div>');
$('body').velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], queue: false });
$('.console2').delay(1000).fadeOut('slow');
}
console.log('window.location.hash = '+window.location.hash);
var hash = window.location.hash;
$hash = $(hash)
$hash.velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], queue: false });
});
// ScrollSpy for Menu items only - gives selected Menu items the active class
// ------------------------------------------------------------------------ //
// Does not update fragment identifier in URL https://en.wikipedia.org/wiki/Fragment_identifier
// https://jsfiddle.net/mekwall/up4nu/
var lastId,
// Anchors corresponding to menu items
scrollItems = $menuLink.map(function(){
var item = $($(this).attr("href"));
// console.table(item);
if (item.length) { return item; }
});
// Give menu item the active class on load of corresponding item
function scrollSpy () {
// Get container scroll position
var fromTop = $(this).scrollTop()+ $menuButtonHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length - 1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
$menuLink
.parent().removeClass("active").end()
.filter("[href='#"+id+"']").parent().addClass("active");
}
// Active Menu Link href Attribute
activeMenuLinkHref = $('.menu-li.active > .menu-a').attr('href');
// console.log('activeMenuLinkHref '+activeMenuLinkHref);
}
scrollSpy()
$(window).scroll(function(e){
scrollSpy()
});
// On Stop of Scrolling get Active Menu Link Href and set window.location.hash
// --------------------------------------------------------------------------- //
// Scroll Stop Function
//---------------------//
// https://stackoverflow.com/questions/8931605/fire-event-after-scrollling-scrollbars-or-mousewheel-with-javascript
// http://stackoverflow.com/a/8931685/1010918
// http://jsfiddle.net/fbSbT/1/
// http://jsfiddle.net/fbSbT/87/
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);
special.scrollstart = {
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
} else {
evt.type = 'scrollstart';
// throws "TypeError: jQuery.event.handle is undefined"
// jQuery.event.handle.apply(_self, _args);
// solution
// http://stackoverflow.com/a/20809936/1010918
// replace jQuery.event.handle.apply with jQuery.event.dispatch.apply
jQuery.event.dispatch.apply(_self, _args);
}
timer = setTimeout( function(){
timer = null;
}, special.scrollstop.latency);
};
jQuery(this).bind('scroll', handler).data(uid1, handler);
},
teardown: function(){
jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
}
};
special.scrollstop = {
latency: 250,
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout( function(){
timer = null;
evt.type = 'scrollstop';
// throws "TypeError: jQuery.event.handle is undefined"
// jQuery.event.handle.apply(_self, _args);
// solution
// http://stackoverflow.com/a/20809936/1010918
// replace jQuery.event.handle.apply with jQuery.event.dispatch.apply
jQuery.event.dispatch.apply(_self, _args);
}, special.scrollstop.latency);
};
jQuery(this).bind('scroll', handler).data(uid2, handler);
},
teardown: function() {
jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
}
};
})();
// Scroll Stop Function Called
//----------------------------//
$(window).on("scrollstop", function() {
// window.history.pushState(null, null, activeMenuLinkHref);
// window.history.replaceState(null, null, activeMenuLinkHref);
// http://stackoverflow.com/a/1489802/1010918 //
// works best really
hash = activeMenuLinkHref.replace( /^#/, '' );
console.log('hash '+hash);
var node = $( '#' + hash );
if ( node.length ) {
node.attr( 'id', '' );
// console.log('node.attr id'+node.attr( 'id', '' ));
}
document.location.hash = hash;
if ( node.length ) {
node.attr( 'id', hash );
}
});
CSS
.console1{
position: fixed;
z-index: 9999;
top:0;
right:0;
background-color: #fff;
border: 2px solid red;
}
.console2{
position: fixed;
z-index: 9999;
bottom:0;
right:0;
background-color: #fff;
border: 2px solid red;
}
I will also supply a jsfiddle in due time. ;)

How to prevent function to double animation

In my plugin I handle animations by passing methods in external functions.
Firstly I have to check if the sidebars exists:
var left = cfg.left.selector,
right = cft.right.selector;
function Sidebar( e ) {
if ( e == undefined ) {
console.log( "WARNING: A (or more) sidebar(s) has been left behind" );
} else {
var align, sbw, marginA, marginB, $sbRight, $sbLeft,
$sidebar = $( e );
Once I'm sure that the sidebars (or maybe just one ) exists I define the variables I need to animate all elements:
switch ( e == cfg.right.selector ) {
case true:
align = "right";
marginA = "margin-right";
marginB = "margin-left";
$sbRight = $( cfg.right.selector );
break;
case false:
align = "left";
marginA = "margin-left";
marginB = "margin-right";
$sbLeft = $( cfg.left.selector );
break;
}
var def = cfg[align], //new path to options
$opener = $( def.opener ),
sbMaxW = def.width,
gap = def.gap,
winMaxW = sbMaxW + gap,
$elements = //a very long selector,
w = $( window ).width();
//defining sbw variable
if ( w < winMaxW ) {
sbw = w - gap;
} else {
sbw = sbMaxW;
}
//setting $sidebar initial position and style
var initialPosition = {
width: sbw,
zIndex: cfg.zIndex
};
initialPosition[marginA] = -sbw;
$sidebar.css( initialPosition );
And here are the animations. They are handled as external functions. The first animation works really good. It does its job:
//Animate $elements to open the $sidebar
var animateStart = function() {
var ssbw = $sidebar.width();
animation = {};
animation[marginA] = '+=' + ssbw;
animation[marginB] = '-=' + ssbw;
$elements.each(function() {
$( this ).animate( animation, {
duration: duration,
easing: easing,
complete: function() {
$( 'body, html' ).attr( 'data-' + dataName, 'overflow' );
maskDiv.fadeIn();
}
});
});
},
but the second one is doubled when two sidebars exist!! I need to retrieve the .wrapper offset and then move $elements according to its value. So I thought that it works as in the first animation function, and that it would be as simple as there:
animationReset = function() {
var offset = $wrapper.offset().left;
reset = {};
console.log( offset );
Console returns two time the value so the animation in doubled.
reset[marginA] = '-=' + offset;
reset[marginB] = '+=' + offset;
$elements.each(function() {
$( this ).animate( reset, {
duration: duration,
easing: easing,
complete: function() {
maskDiv.fadeOut(function() {
$( 'body, html' ).removeAttr( 'data-' + dataName );
});
}
});
});
};
So now I run the animations on click functions.
$( $opener ).click( animateStart );
maskDiv.click( animationReset );
}
}
And finally I pass the values running the main function two times.
Sidebar( left );
Sidebar( right );
Why it worked on the first animation and then it is doubled in the second animation?
DEMO: http://dcdeiv.github.io/amazing-sidebar/
FULL CODE: https://github.com/dcdeiv/amazing-sidebar/blob/master/development/jquery.amazingsidebar.js
I think the problem is that you are adding two times the click event at
maskDiv.click( animationReset );
since maskDiv is the main div of the website and there is only one, but the looping is doing it twice.
Try to take that out of the loops definitions and do it only once, but maybe it is difficult because it is defined inside the Sidebar function, so you can try to create a global variable at the top and, after the first click event is added, not add any more:
At the top:
var notAdded = true;
In the sidebar function:
$( $opener ).click( animateStart );
if(notAdded){
maskDiv.click( animationReset );
notAdded = false;
}
Hope it helps!
Here is the cause :
var maskDiv = $( 'body' ).children().filter(function(){
return $( this ).data( dataName ) === 'mask' ;
});
and
maskDiv.click( animationReset );
You have two data-named 'mask' elements on the body.
So the click action is setup on both when you call the Sidebar function.
As you call it twice, you got the reset action run twice ...
EDIT : I was wrong : you have only one mask, but as it is used by both sidebars, you still have a double setup on it.

Style the iframe and then make it visible

I am using a Twitter widget in my site which is in an iframe. I am styling this iframe without any problem.
The problem I have is that I first see the old let's say iframe and then I can see the changes to the styled one.
Is there a way to have the iframe hidden while all the css/style changes are happening on the background and then make it visible?
I using this jquery:
$(document).ready(function(){
hideTwitterBoxElements();
});
var hideTwitterAttempts = 0;
function hideTwitterBoxElements() {
setTimeout( function() {
if ( $('[id*=twitter]').length ) {
$('[id*=twitter]').each( function(){
var ibody = $(this).contents().find( 'body' );
ibody.find(".timeline .stream").css("padding-top", "10px")
if ( ibody.find(".timeline .stream .h-feed li.tweet").length )
ibody.find(".timeline").css("background-color","transparent");
ibody.find(".customisable-border").css("border","none");
ibody.find(".timeline .stream").css("overflow","hidden");
}
});
}
hideTwitterAttempts++;
if ( hideTwitterAttempts < 3 ) {
hideTwitterBoxElements();
$("#twitter").show();
}
}, 1500);
}
And what happens is that when I load the page, the iframe comes after a while (which I also could like to reduce the time if possible) and then I can see for example the overflow changing to hidden.
Thanks in advance.
edited:
Mashing up your code with this one and we've got a pretty good result.
JSFiddle
function hideTwitterBoxElements() {
var hideTwitterAttempts = 0;
if ($('.twitter-timeline').length) {
//Timeline exists is it rendered ?
interval_timeline = false;
interval_timeline = setInterval(function(){
//console.log($('.twitter-timeline').width());
if ($('.twitter-timeline').hasClass('twitter-timeline-rendered')) {
if ($('.twitter-timeline').width() > 10) {
//Callback
clearInterval(interval_timeline);
setTimeout( function() {
if ( $('[id*=twitter]').length ) {
$('[id*=twitter]').each( function(){
var ibody = $(this).contents().find( 'body' );
ibody.find(".timeline .stream").css("padding-top", "10px");
if ( ibody.find(".timeline .stream .h-feed li.tweet").length );
ibody.find(".timeline").css("background-color","transparent");
ibody.find(".customisable-border").css("border","none");
ibody.find(".timeline .stream").css("overflow","hidden");
});
}
hideTwitterAttempts++;
if ( hideTwitterAttempts < 40 ) {
hideTwitterBoxElements();
$("#twitter").show();
}
}, 100);
}
}
},200);
}
}
$(document).ready(function(){
hideTwitterBoxElements();
});

How to retrieve the ajax data whose loading requires a mouse click with PhantomJS or other tools

I'm using PhantomJS to retrieve this page: Target Page Link. The contents I need are under the "行政公告" and "就業徵才公告" tabs. Because this page is written in Chinese, in case you cannot find the tabs, you can use "find" function of the browsers to find the "行政公告" and "就業徵才公告" tabs. Because the contents under the "行政公告" tab are the loaded as the default option, I can easily use the script below to retrieve the page:
var page = require('webpage').create();
var url = 'http://sa.ttu.edu.tw/bin/home.php';
page.open(url, function (status) {
var js = page.evaluate(function () {
return document;
});
console.log(js.all[0].outerHTML);
phantom.exit();
});
But the contents under the "就業徵才公告" tab are not loaded after I use the PhamtomJS to emulate the mouse click with the code below:
var page = require('webpage').create();
var url = 'http://sa.ttu.edu.tw/bin/home.php';
page.open(url, function (status) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
// jQuery is loaded, now manipulate the DOM
$('#sm_adf63b93c89375a0bade42e5360b73274_1_Dyn_2_1').trigger('mouseover');
});
var js = page.evaluate(function () {
return document;
});
console.log(js.all[0].outerHTML);
phantom.exit();
});
This doesn't work as the contents under the "就業徵才公告" tab are not loaded. How should I do to retrieve the contents under the "就業徵才公告" tab?
Update:
After read a PhantomJS example, I refactored the code to below. It didn't work because the contents under the "就業徵才公告" tab are not loaded.
var page = require('webpage').create();
var address = 'http://sa.ttu.edu.tw/bin/home.php';
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit();
} else {
window.setTimeout(function () {
var results = page.evaluate(function() {
$('#sm_adf63b93c89375a0bade42e5360b73274_1_Dyn_2_1').trigger('mouseover');
return document.documentElement.innerHTML;
});
console.log(results);
phantom.exit();
}, 5000);
}
});
If any way could solve this problem is welcomed. Not limited to PhamtoJS.
Tested this code, and it outputs the correct image with the desired tab selected. It wasn't so straightforward because of the underlying structure of the page. Hopefully you can use this as a bit of a learning exercise in processing the DOM.
// utility function to send mouseclick event to an element
function mouseclick( element ) {
// create a mouse click event
var event = document.createEvent( 'MouseEvents' );
event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );
// send click to element
element.dispatchEvent( event );
}
// final function called, output screenshot, exit
function after_clicked( page ) {
console.log( "+after_clicked()" );
page.render( "after_click.png" );
console.log( "Done" );
phantom.exit( 0 );
}
// middle function, click on desired tab
function click_div( page ) {
console.log( "+click_div()" );
var clicked = page.evaluate(
function ( mouseclick_fn ) {
// want the div with class "submenu"
var div = document.querySelector( "div.submenu" );
if ( ! div ) {
return false;
}
// want all the list elements in the div
var li_array = div.querySelectorAll( "li" );
if ( ! li_array ) {
return false;
}
// we want the 2nd list element
var li2 = li_array[1];
if ( ! li2 ) {
return false;
}
// want the anchor inside the 2nd list element
var anchor = li2.querySelector( "a" );
if ( ! anchor ) {
return false;
}
// must focus on anchor to trigger underlying javascript on page
anchor.focus();
// want the div within this anchor, so we can click on the div
var element = anchor.querySelector( "div" );
if ( ! element ) {
return false;
}
// click on this inner div
mouseclick_fn( element );
return true;
}, mouseclick
);
if ( ! clicked ) {
console.log( "Failed to find desired element" );
phantom.exit( 1 );
return;
}
console.log( "- clicked, waiting 5 seconds" );
window.setTimeout(
function () {
after_clicked( page );
},
5000
);
}
// first function, create page, load page
function main() {
console.log( "+main()" );
var page = require('webpage').create();
page.open(
"http://sa.ttu.edu.tw/bin/home.php",
function (status) {
if ( status !== 'success' ) {
console.log( "Failed" );
phantom.exit( 1 );
return;
}
console.log( "- page loaded, waiting 2 seconds..." );
window.setTimeout(
function () {
click_div( page );
},
2000
);
}
);
}
main();

swap backstretch image when changing active div

I'm using Backstretch jQuery plugin to create full screen background images, but have a 1 page scrolling website and would like to change the background image depending on whichever content div is active.
There are multiple ways to scroll to each panel on the site, including directional buttons, clicking on the panel, and selecting link from nab menu, so would need to be able to call this function in different places.
Currently the site adds a class 'active' to whichever div has been selected for CSS styling, and then scrolls to that location. Effectively, I would need to change the path to $.backstretch("http://example.com/assets/image.jpg"); when the active panel changes. I would like to run a function along with that to swap the background image to specific path for some panels, else to select a random image from a small array when not one of the specific panels.
My instinct would be to use a switch statement, but need to request help.
It is a WordPress site and the panels are output dynamically, so I cannot hard code this is; it needs to work in relation the id and hash tags in the same way as the active panel selection is currently working.
My JS code, as it currently stands, is below. I'm not very competent with JS so I appreciate there are probably more efficient ways to arrange this code, but my current skill level with it limits me there.
Many thanks for any help you can offer.
jQuery(function( $ ){
$.easing.elasout = function (x, t, b, c, d) {
return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
};
$.backstretch("http://example.com/assets/image.jpg");
$('#content').scrollTo( 0 );
$.scrollTo( 0 );
$('.menu a').click(function(e){
e.preventDefault();
var link = e.target;
link.blur();
if( link.title )
$(this).parent().find('span.message').text(link.title);
});
// clicking from menu
$('.menu a').click(function(){
$target = $(this.hash);
$.scrollTo( $target, 1000, { easing:'elasout', queue:true, offset:{ top:-150,left:-300 }});
$('div.panel.active').removeClass('active');
$target.addClass('active');
return false;
});
//clicking on a panel
$('.panel').click(function(){
$target = $(this);
$.scrollTo( $target, 1000, { easing:'elasout', offset:{ top:-150,left:-300 }});
$('div.panel.active').removeClass('active');
$target.addClass('active');
return false;
});
// click on up button
$('#verticals a.up').click(function(){
if ( $('div.panel.active').prev('div.panel').length){
$target = $('div.panel.active').prev();
$.scrollTo( $target, 500, {offset:{ top:-150,left:-300 }});
$('div.panel.active').removeClass('active');
$target.addClass('active');
return false;
}
else {
return false;
}
});
// click on down button
$('#verticals a.down').click(function(){
if ( $('div.panel.active').next('div.panel').length){
$target = $('div.panel.active').next();
$.scrollTo( $target, 500, {offset:{ top:-150,left:-300 }});
$('div.panel.active').removeClass('active');
$target.addClass('active');
return false;
}
else {
return false;
}
});
// click on right button
$('#horizontals a.right').click(function(){
if ( $('div.panel.active').parent().next('div.col').length){
$target = $('div.panel.active').parent().next('div.col').children('div:nth-child(1)');
$.scrollTo( $target, 1000, { easing:'elasout', queue:true, offset:{ top:-150,left:-300 }});
$('div.panel.active').removeClass('active');
$target.addClass('active');
return false;
}
else {
return false;
}
});
// click on left button
$('#horizontals a.left').click(function(){
if ( $('div.panel.active').parent().prev('div.col').length){
$target = $('div.panel.active').parent().prev('div.col').children('div:nth-child(1)');
$.scrollTo( $target, 1000, { easing:'elasout', queue:true, offset:{ top:-150,left:-300 }});
$('div.panel.active').removeClass('active');
$target.addClass('active');
return false;
}
else {
return false;
}
});
$(document).ready(function(){
$('.menu li').hover(
function () {
$('ul', this).slideDown(200);
$('ul', this).parent().addClass('active');
},
function () {
$('ul', this).slideUp(200);
$('ul', this).parent().removeClass('active');
}
);
$('.panel').tinyscrollbar();
$("#key-facts").fadeTransition();
});
});
Got there eventually. Here it is for anyone who finds this in search of solace:
var a = [
['115', 'filename.jpg'],
['148', 'filename.jpg'],
['150', 'filename.jpg'],
['153', 'filename.jpg'],
['155', 'filename.jpg'],
['157', 'filename.jpg']
// ... etc, continue as required
]
function setBackground(id){
 for (var i = 0; i < a.length; i++){
  if (a[i][0] == id){
   $.backstretch('http://insert base URL here' + a[i][1]);
   return;
  }
 }
var aRandom = [
'filename.jpg',
'filename.jpg'
]
// array of images for id with undefined image to be randomly selected from
var b = aRandom[Math.floor(Math.random()*aRandom.length)];
 $.backstretch('http://insert base URL here' + b);
}

Categories