Conflict between two scripts for in-page anchor links - javascript

I have two small scripts that, when working alone, have no problems.
However, when appearing together in the same document, they fail to work properly.
Script #1: Launch Modal Dialog Box
All pages on my website have links to the following features:
Login Page
Contact Page
E-mail Sign-Up
When a user clicks on one of these links, a lightbox appears and the relevant modal slides in.
To prevent the page from scrolling in the background when the lightbox is active, I have this script:
$(document).ready(function(){
$("[href$='#contact'],[href$='#email'],[href$='#login']").click(function(){
$("body").addClass("noscroll");
});
$("a[href$='#close']").click(function(){
$("body").removeClass("noscroll");
});
});
The CSS is simply:
.noscroll {
overflow: hidden;
}
This function works perfectly, as far as I can tell.
Script #2: Smooth Scrolling
I have several web pages with long content (e.g., Terms of Service, Privacy Policy, etc.)
To make these pages more user-friendly, I've added a table of contents on the top. Each item in the TOC is an anchor link leading to the relevant section on the page.
Example:
TOC
<ol>
<li>Copyrights</li>
<li>Trademarks</li>
<li>Indemnification</li>
</ol>
Content
<h3 id="trademarks">Trademarks</h3>
<p> text text text </p>
The standard behavior for in-page links is an immediate jump to the content. For a more elegant experience, I added a smooth scrolling effect:
$('a[href*="\\#"]').on('click', function(event){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
});
Like script #1, this seems to work perfectly.
However, when both scripts appear together on the page, nothing works properly.
There are no console errors. The main problem is that the modal script activates the CSS (scrollbar disappears), but doesn't launch the lightbox.
How can both of these scripts work together?

This should do it. However, I coded it blindly. If it doesn't work I could use testing it on the live example, to see where it fails. It should work, though. What it does is simple: it skips smooth-scrolling if any of the these have been pressed: (#contact, #email, #login or #close).
$(document).ready(function(){
$("[href$='#contact'],[href$='#email'],[href$='#login']").click(function(){
$("body").addClass("noscroll");
});
$("a[href$='#close']").click(function(){
$("body").removeClass("noscroll");
});
$('a[href*="\\#"]').on('click', function(event){
var href = $(event.target).closest('a').attr('href'),
exceptions = ['#contact', '#email', '#login', '#close'],
skip = false;
for (i = 0; i < exceptions.length; i++) {
if (href.indexOf(exceptions[i]) > -1) {
skip = true;
}
}
if (!skip) {
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
}
});
});
Note. The above script combines the two scripts you showed in your question and should replace both.

What does the '\\' on the second script's selector? Having this said, I don't think it is the problem.
As far as I can see, first script is selecting the links by their hrefs starting with a dash character and following four different words.
Second script also selects links contain a dash character in their hrefs.
Normally attached multiple handler to an elements same event should not conflict and they all run. But second script also stops event processing with : event.preventDefault();
I'm assuming this is intended so you need to be more specific on selecting the HTML elements before attaching the event handlers to prevent unwanted behaviours. For example you can modify your second script to be :
$("[href$='#copyrights'],[href$='#trademarks'],[href$='#indemnification']").click(function(event){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
});

Related

How to keep elements non-refreshed

The main goal is to keep non-refreshed the logotext <div class="small-7 medium-4 columns logo"> and the menu <nav class="pagedMenu" role="navigation">,without clipping on page refresh or while the content is loading from a page to another. Also, the menu state should be preserved from a page to another.
I've found here a possible solution that could solve the problem (you could use ajax to fetch the updated content and use jQuery to put the new content on the page and avoid the refresh entirely. Doing it that way, the existing data in the page would remain untouched. said #jfriend00)
So, I have tried to use an Ajax plugin (called AWS). In the AWS option page, I (suppose) that I've done the right thing pointing wrapper as Ajax container ID and also pagedMenu as Menu container class, Transition Effect Enabled, No ajax container IDs blank, no loader selected, having already a pulse loader implemented in the theme.
At this point, all I got it's a menu / side-menu (shiftnav) / pulse dot loader / content loading malfunction, generated perhaps by the wrong defined Ajax container id and/or menu container class(?) OR by a conflict with an existing JS / jQuery code, not so sure.
Also in Chrome console there is an error:
Uncaught SyntaxError: Unexpected token ;
(anonymous function) # ajaxify.js?ver=4.3.1:175
n.extend.each # jquery-2.1.4.min.js?ver=2.1.4:2
n.fn.n.each # jquery-2.1.4.min.js?ver=2.1.4:2
$.bind.$.ajax.success # ajaxify.js?ver=4.3.1:169
n.Callbacks.j # jquery-2.1.4.min.js?ver=2.1.4:2
n.Callbacks.k.fireWith # jquery-2.1.4.min.js?ver=2.1.4:2
x # jquery-2.1.4.min.js?ver=2.1.4:4
n.ajaxTransport.k.cors.a.crossDomain.send.b # jquery-2.1.4.min.js?ver=2.1.4:4
Everything is getting back to normal on page refresh but doesn't help at all, being useless.
I also have to mention that for the menu I've tried to keep the state using jQuery-Storage-API and storage=jQuery.sessionStorage; as you can see in mynewmenu.js file but that will not solve the non-refreshing elements problem.
The menu jsfiddle only, if this helps to have the whole picture, here thanks to #Diego Betto.
You can use this live link as example; there is a similar situation with the above described - Ajax implementation right(?) - and regarding the appearance, menu is kept non-refreshed from one page to another; if you browse Books, Works etc, menu sections you'll see; if there is a model that could be implemented here, I'll be glad to find it.
LE: meanwhile, I've tried another ajaxify solution made by #arvgta - special thanks - without success yet but as far as I've found from the Author, the defined elements should be div's with id's not classes. So, I'll try to find a way to modify somehow the code in order to have id instead on classes.
Also, I'll try to transform and implement in ajaxify.min.js file, the page-container element; jQuery('#page-container').ajaxify(); I'll come back with news.
LE2: I've tried to implement the solution using id's instead of classes but still, the pages are not loading correctly.
At this point we have ajax.min.js file updated with these lines:
(function($){
jQuery(document).ready(function(){
jQuery('#page-container').ajaxify({requestDelay:400,forms:false});
});
})(jQuery);
Also, I've modified the theme file to have id=page-container instead if class=page-container.
In these conditions, on menu click, the links are changed (like it should), menu/ logotext elements seems to working almost fine (sometimes get skippy changing position), but the content is not loading correctly in all cases; Same here, everything is getting back to normal on manual page refresh (f5), but doesn't help.
LE3: It looks like the conflict is (at least) between Revolution Slider plugin and Ajaxify.
errormessage="Revolution Slider Error: You have some jquery.js library include that comes after the revolution files js include." ;="" +=" This includes make eliminates the revolution slider libraries, and make it not work." "<="" span="">"
Site live link here. Any thoughts / alternative in this area? (not interested in using other different platforms, different WordPress themes, etc. just a workaround in this existing situation)
LE4: As far as I can see, there are many users that voted up the Jake Bown answer that could be indeed a solution; but I can't find the reason that didn't work correctly implemented into my theme (without errors) live link here The elements logotext / menu are still fading on refresh, are not kept non-refreshed. Any thoughts #Jake Bown / anyone?
LE final.
Buzinas delivered the closest answer for my needs, taking in consideration my site environment (plugins installed, etc).
From what you said I think I might have found the solution you're looking for - you want to load content dynamically whilst keeping the logo and navigation untouched? If so, this might be what you're looking for.
In the example, the pages are loaded in from a div within the page but could be used to load another URL or file:
$('.viewport ul li a').on('click', function(e) {
e.preventDefault();
var link = this.hash.substring(1, this.hash.length);
if($('.'+link).length) {
$('.viewport span.body').html($('.'+link).html());
}
});
TL;DR
I've created a plunker for you, take a look, and play with it as long as you can. You'll learn a lot from it!
I think you're trying too many things here, but didn't try the simplest:
The main goal is to keep non-refreshed the logotext and the menu ,without clipping on page refresh or while the content is loading from a page to another. Also the menu state should be preserved from a page to another.
If you want to do that, there are a few steps:
Create a 'master' page, that we're going to call index.html from now on.
So, our index must have the static part of our page, e.g menu, logo, footer etc.
Then, our 'subpages' must be cut down (no html, head, body, script, style tags, only the content that should be showed into our master page).
That done, now we must change our links to use AJAX instead of doing full refresh:
/* we add a 'click' event handler to our menu */
document.getElementById('menu-menu-2').addEventListener('click', function(e) {
var el = e.target;
/* then, we see if the element that was clicked is a anchor */
if (el.tagName === 'A') {
/* we prevent the default functionality of the anchor (i.e redirect to the page) */
e.preventDefault();
/* we show our spinner, so the user can see that something is loading */
spinner.classList.remove('hidden');
/* and we call our AJAX function, passing a function as the callback */
ajax(el.href, function(xhr) {
/* we get our main div, and we replace its HTML to the response that came
from the AJAX request */
document.getElementById('main').innerHTML = xhr.responseText;
/* since the request was finished, we hide our spinner again */
spinner.classList.add('hidden');
});
}
});
Ok, now our pages are already working via AJAX, and not reloading our static content.
But now, we see that we have some issues. For example, if someone tries to open one of our pages directly via URL, he'll see unstyled page, without the menu/logo etc. So, what should we do?
We have a few more steps now:
Simulate that our links are effectively transfering between pages using the History API:
/* inside our ajax callback, we save the fake-redirect we made into the pushState */
ajax(el.href, function(xhr) {
document.getElementById('main').innerHTML = xhr.responseText;
/* save the new html, so when the user uses the back button, we can load it again */
history.pushState({
html: main.innerHTML,
title: el.textContent + '| neuegrid'
}, '', el.href);
/* (...) */
});
/* and outside it, we add a 'popstate' event handler */
window.addEventListener('popstate', function(e) {
/* so, if we've saved the state before, we can restore it now */
if (e.state) {
document.getElementById('main').innerHTML = e.state.html;
document.title = e.state.title;
}
});
And we need that when the user enters directly to another page, e.g about-us, we redirect him to the index.html, and then load the about-us page from there.
So we create a redirect.js file, and we reference it in all of our
subpages:
/* save the page that the user tried to load into the sessionStorage */
sessionStorage.setItem('page', location.pathname);
/* and them, we redirect him to our main page */
location.replace('/');
And then, in our index.html page, we see if there is any page in the sessionStorage, and we load it, if there is, otherwise we load our home page.
var page = sessionStorage.getItem('page') || 'home';
/* we look into the menu items, and find which has an href attribute
ending with the page's URL we wanna load */
document.querySelector('#menu-menu-2 > li > a[href$="' + page + '"').click();
And that's it, we're done now. Take a look at the plunker I've been making to you.
And play with it as long as you can, so you'll learn a lot from it.
I hope I could help you! :)
Note: Just for reference, this is our ajax function:
function ajax(url, callback, method, params) {
if (!method) method = 'GET';
var xhr = new XMLHttpRequest();
xhr.open(method, url);
if (callback) xhr.addEventListener('load', function() {
callback.call(this, xhr);
});
if (params) {
params = Object.keys(params).map(function(key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
xhr.send(params);
} else {
xhr.send();
}
}
GOING AJAXED WITH WORDPRESS
demo: http://so.devilmaycode.it/how-to-keep-elements-non-refreshed/
follow these simple steps (let's take as example theme "twentyfifteen" on the WP templates folder):
edit single.php, page.php, index.php and all other pages having get_header() and get_footer() functions and replace it respectively with below code:
NOTE: this is important because if someone (ex: search-engine) reach your pages directly from the link, it is still fully available and 100% working. (useful for SEO)
<?php
//get_header()
if(!isset($_REQUEST['ajax'])){
get_header();
}
?>
<!-- other code --->
<?php
//get_footer()
if(!isset($_REQUEST['ajax'])){
get_footer();
}
?>
open the header.php add the below code inside the <head> section at the very end
<script>
!(function($) {
$(function() {
$('.menu-item a, .widget-area a, .page_item a').on('click', function(e) {
e.preventDefault();
var href = this.href;
var query = href ? (href + (!/\?/g.test(href) ? '?' : '&') + 'ajax=1') : window.location;
/* IMPLEMENT SOME LOGIG HERE BEFORE PAGE LOAD */
/* ex: kill instance of running plugins */
$('#content').hide().empty().load(query, function() {
/* IMPLEMENT SOME LOGIG HERE AFTER PAGE IS LOADED */
/* ex: refresh or run a new plugin instance for this page */
jQuery(this).show();
});
});
});
})(jQuery);
</script>
in the header.php file put the code below at the end of the file, 90% of times you need it under the navigation. In this case we already have this on the "twentyfifteen" theme.
NB: most probably you have the opening tag <div id="content" class="site-content"> inside the header.php file and the closing tag </div> on the footer.php file, this doesn't matter, you can leave it as is.
<div id="content"></div>
NOTE: consider this a proof of concept; it may work as is, but you still need to tailor it to suit your needs; you may need to:
Add a menu (in case it is not already set) by going under Appeareace > Menus > [check Primary Menu] > Save Menu in order to activate the menu. it's tested and working.
You may want to add some other class to the jQuery function like .widget-area a in order to ajax also widget links.
if you are using 3d party plugins you may need to ensure that all dependencies of each plugin are loaded also on the main page from where you want everything is displayed without refreshing content.
you may need to check and kill those 3d party plugin before a new page load and run or refresh plugin needed in the loaded page.

Anchor click even not firing after PJAX page load

I am having a pretty strange problem with a website I am messing around with, and I can't wrap my head around what may be going wrong. I am using PJAX on the site, and the have a div in my body with the id of #page-contents.
The code I am using to setup PJAX is as follows...
<script type="text/javascript">
$(function(){
$(document).pjax('a', '#page-contents', {
fragment: '#page-contents',
timeout: 2000
});
});
</script>
I know that the setup is correct because I edited the PJAX file to fire an alert whenever it swapped out the content of my #page-contents div, and I do see that alert when I would expect to (i.e., on link clicks).
I have a navbar along the top (a bootstrap navbar) and I was initially having trouble keeping track of which navbar item would be marked as active. I have solved this problem using the following javascript code.
<script type="text/javascript">
$("a").click(function() {
$(".navbar-nav li").removeClass("active");
var nextPage = $(this).attr("href");
nextPage = nextPage.substring(nextPage.indexOf(window.location.hostname) + window.location.hostname.length);
switch(true) {
case nextPage == "/about":
$("#about-nav").addClass("active");
break;
case nextPage == "/contact":
$("#contact-nav").addClass("active");
break;
case nextPage == "/resume":
$("#resume-nav").addClass("active");
break;
case nextPage.indexOf("/projects") != -1:
$("#projects-nav").addClass("active");
break;
default:
break;
}
});
</script>
This works fine for all links I have in my navbar, but I have found that any links I have inside my #page-contents div will not trigger my above script. I know that PJAX is still working as the page changes and the alert I inserted displays.
A few things I have found in my own testing:
I have also found that if I directly load an address that contains a non-navbar link and then click that link, it will work. But coming back to that page via a pjax reload and then clicking the link will not fire my event.
Adding a test class to one of my anchors and then associating some event with that class has the same problems.
Does anybody know why my script would not be getting executing? Or maybe I am just missing something obvious.
Thank you in advance!
P.S.: The website in question is my personal site I am working on, the link is http://rosshays.me, the page I first noticed this on was my about page. (The site is a work in progress as you'll clearly see.) As mentioned about, going to the about page directly and clicking the link will work, but if you navigate to the about page and then try to click the link in the page, it will not work.
Ross-
I had a similar issue and I know how to solve this; this script is not binding to the new elements because it is not being re-ran on the new elements once they are loaded.
Please put your function in an external .js file. Once complete, you can add this script to your header:
$(document).on('pjax:complete', function() {
$.ajaxSetup({ cache: true});
$.getScript("YOUR SCRIPT FILE PATH HERE', true);?>");
});
You will have to add more $.getScript calls for any other javascript/jQuery that is needed in order to enable the events you want to take place. (Example: you may need to reload jQuery)
This will re-apply the jquery and javascript to the new elements that are loaded via PJAX.
*One thing to note: If you are using twitter bootstrap, do not re-call the bootstrap script with $.getScript as it will cancel itself out on every other re-load.

Open link then execute Jquery

I have links in my footer that I want linking to particular sections of a slide i have built on my site
I am currently linking the footer links to these sections via
LINK!
Which works on the page that has the content slide. However I also want these links to work from other webpages. I came up with the solution below to load the "showandscroll" after its been redirected to the page/anchor of the slider
<a id="sem-seo" nohref title="">LINK!</a>
$("#sem-seo").click(function() {
window.location.assign("portfolio.html#anchor2");
$(window).bind("load", showAndScroll(1, 2));
});
But for some reason (loads the page fine and goes to the section) it just does not load the showAndScroll Query
Any thoughts? Ive done hours of research and created a few questions regarding this today but needing the end of a deadline so need a solution.
here is a of the landing page (I want to be able to link to the different sections from other pages)
Fiddle
Your issue is your code will never execute.
$("#sem-seo").click(function() {
//THIS LINE CAUSES A NEW PAGE TO LOAD
window.location.assign("portfolio.html#anchor2");
//THAT MEANS THIS CODE WILL NEVER BE REACHED
$(window).bind("load", showAndScroll(1, 2));
});
You need to apply your code on the destination page, you can't execute javascript code for any page except the one you are on.
Also, don't attach handlers within handlers. If someone repeatedly clicks on #sem-seo, you will attach multiple load handlers to your window, which is not what you want.
UPDATE
I think this will resolve your issue. On your origin page, add this to the link:
<a id="sem-seo" href="portfolio.html#anchor2?show=true" title="">LINK!</a>
And on your destination page, add this script:
$(function(){
var url = window.location.href;
if(url.indexOf('?show=true') != -1 || url.indexOf('&show=true') != -1)
$(window).bind("load", showAndScroll(1, 2));
});

How to prevent scrolling to the top after unhiding/hiding text?

There is an old StackOverflow question on how to unhide/hide text using +/- symbols.
Cheeso posted a nice solution with some sample code. It was just what I was looking for, although the original poster didn't agree. :-)
I'm using the code on a web site that is intended to be used on mobile devices. The only problem is that the page jumps back to the top of the screen whenever the +/- is tapped.
Is there anyway to get around that? Thanks.
In your click event handler, return false.
$('a.selector').click(function() {
return false;
});
Here is the answer that Cheeso provided to me in email. I am posting it here for the benefit of others who follow. This didn't quite work and I am in the process of figuring out why.
If you change this line
$('div p a[href="#"]').click(function() { expando(this); });
to this:
$('div p a[href="#"]').click(function(ev) { ev.preventDefault(); expando(this); });
...I think it should stop scrolling to the top.
When a user clicks on a link that has a hash character, the browser is expected to scroll to the location on the page where the fragment marker is placed. Like a bookmark. For example, in this URL: http://en.wikipedia.org/wiki/Causes_of_WWII#Militarism The fragment (bookmark) is #Militarism , and if you click that link, your browser will scroll to that section.
In the case of that sample I wrote, the hrefs are bare # characters, which implies an empty fragment. And I suppose the browser is scrolling to the default location, which (I guess) is "the top of the page".
To avoid this, just call ev.preventDefault() in the click handler. This is a jQuery trick that suppresses the normal handling of the click; in your case, it suppresses the part where the browser tries to scroll to a non-existent anchor.
Implement event.preventDefault() in the click handler.
$('a').click(function(e) {
e.preventDefault();
// more code here
});

Middle Click JS Function

I have a button on the site I am working on that uses a sprite sheet animation and so needs to be set as a background image. I require a regular click on the button to delay the redirect to another page by a fraction of a second for the animation to play, however I still wish for middle mouse clicks to function to open in new tab, without a delay.
Currently I have this working in Javascript but it seems a pretty bad idea for everything to be handled that way and not to just have a href.
So I have made this:
<script type="text/javascript">
function delayed(){
window.stop();
setTimeout('window.location = "http://www.dog.com";', 800);}
</script>
I am a link
The idea being that a regular click triggers the function and incurs a delay whereas a middle mouse click will just go straight to the href link.
This works in Firefox. However in Chrome and Safari the middle click triggers the function and as a result opens the dog link in the same window (on the finished version the links will be the same of course).
Basically all I need is a href that delays on click but still functions normally on middle click. My working solution uses Javascript to open in new tab on middle click but it strikes me that this may override browser settings and is probably a bad idea.
EDIT:
In the meantime I had found this solution using Jquery:
$(document).ready(function() {
$(".delayed").click(function() {
var href = $(this).attr('href');
setTimeout(function() {window.location = href}, 800);
return false;
});
});
...and the HTML:
<a href="http://www.google.com/" class='delayed'></a>
This worked but encountered the same problem with Chrome treating a middle click as a left click and hence opening it in the same window.
I have now modified it to include the content from sransara so that... I think... everything is resolved. Again using Jquery:
$(document).ready(function() {
$(".delayed").click(function(event) {
var href = $(this).attr('href');
if(event.button == 0){
event.preventDefault ? event.preventDefault():event.returnValue = false;
setTimeout(function() {window.location = href}, 800);
}
});
});
Seems to work in all browsers. Hopefully these can be of use to anyone stumbling upon this page in the future.
This is just a quick solution, but I think it mostly fits into your need.
The code of HTML anchor tag:
I am a link
Here is the Javascript:
function delayed(event){
window.stop();
if(event.button == 0){
event.preventDefault ? event.preventDefault():event.returnValue = false;
setTimeout(function(){ window.location = "http://www.yahoo.com"; }, 800);
}
}
There are few simple changes:
I have removed the return false from onclick event, but the new code line event.preventDefault ? event.preventDefault():event.returnValue = false;, prevents default action when left clicked.
And added a button code check to Javascript.
Working demo code is here.
This is a quick solution, some area for improvement is to:
Take out the inline onclick event and add an event listener dynamically with JS.

Categories

Resources