Graceful Javascript Degradation - external source files - javascript

Easy question for a coder well-versed in JS.
I'm building a Wordpress site that uses jQuery AJAX methods, reloading either my entire content area when a top nav link is clicked or my main content area when a sidebar nav link is clicked. I want to be sure that the AJAX call is only issued if the user's browser supports JavaScript. I found some reference material here and on other sites that said by referencing my script externally, a browser unequipped with JavaScript would simply ignore all JS files. Is this accurate? I considered using php:
$my_arr = get_browser(null,true);if $my_arr['javascript'] == 1 {
echo '<script type="text/javascript" src="path/to/script"';
}
The UX I'm going for is if JS is enabled, then fire AJAX calls; if JS is disabled, just send the user to the page they've requested.
e.g.
<?php
/**
* The template for displaying all pages.
*
$ajxy = $_GET['ajxy'];
if(!is_null($ajxy)) {
$ajax_code = $ajxy;
}
if(!$ajxy) {
get_header();
}
?>
<?php if(!$ajax_code) { ?>
<div id="primary">
<div id="content" role="main">
<div class="container_12" id="contentWrapper">
<?php } ?>
<div id="contentContainer" <?php if($ajax_code) { echo 'class="ajxn"'; } ?>>
<?php while ( have_posts() ) : the_post(); ?>
<div class="grid_8" id="contentGrid">
<?php
get_template_part( 'content', 'page' );
?>
</div>
<?php get_sidebar(); ?>
<?php endwhile; // end of the loop. ?>
</div>
<?php if(!$ajax_code) { ?>
</div>
</div><!-- #content -->
</div><!-- #primary -->
<?php } ?>
<!---My Ajax Loading Script -->
<script type="text/javascript" src="<?php echo get_template_directory_uri(); ?>/js/ajxy.js"></script><!---My Ajax Loading Script -->
<?php
if(!$ajxy) {
get_footer();
}
?>
and the script:
function ajxnOff(list, ajxnCode, wrapper, container) {
jQuery(list).click(function(e) {
e.preventDefault();
var $lnkGoz = jQuery(this).attr("href");
var $lnkGozAjx = $lnkGoz + '?ajxy=' + ajxnCode;
var $ajxyContainer = wrapper;
var $ajxyCurThing = container;
$ajxyCurThing.fadeOut(400, function() {
$ajxyContainer.html('<div id="loaderA"></div>');
jQuery("div#loaderA").fadeIn(400);
jQuery.ajax({
url: $lnkGozAjx,
success: function(data) {
jQuery("div#loaderA").delay(2000).fadeOut(400, function() {
$ajxyContainer.html(data);
jQuery("div.ajxn").fadeIn(400);
jQuery.remove("div#loaderA");
});
}
});
});
});
}
jQuery(document).ready(function() {
ajxnOff(jQuery("ul#topNavList a"), 1, jQuery("div#contentWrapper"), jQuery("div#contentContainer"));
ajxnOff(jQuery("ul#sidebarNavList a"), 2, jQuery("div#contentGrid"), jQuery("div#contentPageContainer"))
});
I've been learning to code on my own for about 6 months and don't have any books on the subject, so any help from the experts around here is greatly appreciated.

Here is a simple pattern to do unobtrusive ajax navigation with fallback to non-ajax links.
In your HTML:
<a class="ajaxnav" href="page.html">Text</a>
In your script:
$(".ajaxnav").click(function(event) {
event.preventDefault();
// do ajax nav here;
// URL is in event.currentTarget.href, modify it however necessary
});
If javascript is not supported, the script is simply not run, and you're left with standard web anchors with valid HREFs. If javascript is supported, the script replaces all "ajaxnav" link handling with your ajax click handler. Easy as pie.

Yes, if the user's browser either doesn't support JS or has JS disabled, script tags are essentially ignored. It doesn't hurt to include them no matter what, you just have to plan your site for what happens when they're not utilized.
As far as AJAX versus page reload goes, you simply code your site as if there were no AJAX, i.e. all links should have appropriate href attributes point to where they should go. If JS is enabled, you attach your AJAX to the links via its onclick handler and prevent the default action by returning false from whatever function handles the click event.

Related

How to take the page number the user want for Turn.js

I'm using the turn.js to make a catalog. I grab the pages from the database with PHP and I want to make some control buttons like search specific page. How can I parse the value from the searchbox to take the place of number 10 here $("#flipbook").turn("page", 10); and run it?
<div class="flipbook-viewport">
<div class="container1">
<div class="flipbook">
<?php
if (isset($_GET['eb_catalogs_id'])){
$catalogos_id = $_GET['eb_catalogs_id'];
$query= "SELECT c_catalog_name FROM eb_catalogs WHERE c_id = $catalogos_id";
$test= $conn->query($query);
$catalogname =$test->fetchColumn();
$query1 = ("SELECT * FROM eb_catalog_".$catalogname."");
$pages = $conn->query($query1);
$i = 1;
foreach($pages as $page){
echo "<div class='p".$i."' style='background-image:url(https://untuneful-carload.000webhostapp.com/img/catalogs/".$catalogname."/".$page['eb_catalog_imgs'].")'></div>";
$i++;
}}else{
echo "nothing";
}
?>
</div>
</div>
</div>
<script type="text/javascript">
function loadApp() {
// Create the flipbook
$('.flipbook').turn({
width:922,
height:600,
elevation: 50,
});
}
// Load the HTML4 version if there's not CSS transform
yepnope({
test : Modernizr.csstransforms,
yep: ['js/turn.js'],
nope: ['js/turn.html4.min.js'],
both: ['css/basic.css'],
complete: loadApp
});
alert("The current page is: "+$("#flipbook").turn("page"));
</script>
here is the code of the page so far.. I know how to make an input field but I dont know how to parse the value of the input field to the function that jumps to the specific page the user wants.
If you pass the page number to next page, you may get it using $_post or $_get and execute it on page load:
<script>
$(window).on("load",function(){
$("#flipbook").turn("page", <?php echo ($_GET["page"]) ?>);
})
</script>
If you are in the same page and just want to flip the book, you can easily get the number using val():
<input id="pageNumber">
<button onclick="flipPage()">GO</button>
<script>
function flipPage(){
var pageNumber=$('#pageNumber').val();
$("#flipbook").turn("page", pageNumber);
}
</script>

Dynamic page update by AJAX

I've got a problem.
I'm using AJAX to load pages and it works correctly, but I can't escape a bug.
When I load page, first time it works correctly but then I go to another page, AJAX loads the page I want, but it has double tags like <head> and <footer>.
I mean when I load page a second time, the page loads the same page in <div>.
It's like picture in picture.
I use in templates code like this:
<?php echo $header ?>
My content
<?php echo $footer ?>
And every page load the same code after I get back to previous page by link.
My ajax code:
function showContent(link) {
var cont = document.getElementById('content');
var loading = document.getElementById('loading');
window.history.replaceState('', 'Title', link);
cont.innerHTML = loading.innerHTML;
var http = createRequestObject(); // создаем ajax-объект
if( http ) {
http.open('get', link); // инициируем загрузку страницы
http.onreadystatechange = function () { // назначаем асинхронный обработчик события
if(http.readyState == 4) {
cont.innerHTML = http.responseText; // присваиваем содержимое
}
}
http.send(null);
} else {
document.location = link; // если ajax-объект не удается создать, просто перенаправляем на адрес
}
}
// создание ajax объекта
function createRequestObject() {
try { return new XMLHttpRequest() }
catch(e) {
try { return new ActiveXObject('Msxml2.XMLHTTP') }
catch(e) {
try { return new ActiveXObject('Microsoft.XMLHTTP') }
catch(e) { return null; }
}
}
}
What Can I do?
Because if I delete Tags header and footer my page doesn't have design at all.
And as u see, I change URL (important for me).
I need solution which will help me load templates without double-tagging.
In your template, be sure that you have something like
<?php echo $header ?>
<div id="content">My content</div>
<?php echo $footer ?>
And that id="content" is unique, only there and not in your $header or $footer.
This can happen if you are not clearing the previous content and the new content is being "appended" to the existing DOM.
So following points could be your solution.
In each ajax call, before updating the container element, clear the existing element, eg. cont.innerHTML = '';
Remember to keep track of any event bindings that are coming with the incoming response.
Move this line var cont = document.getElementById('content'); inside the ajax call.
If the pages you're pulling in with the JavaScript XHR (Ajax) also contain the PHP header and footer code, then you'll need to replace those also with your XHR:
<div id="content">
<?php echo $header ?>
My content
<?php echo $footer ?>
</div>
Wrap your content div tag around the header and footer in order to overwrite them rather than duplicate them.
Alternatively, the way I've implemented a PHP template system is like this:
index.php
<?php
// GET PAGE
if ( isset($_GET['page'])
&& '' != $_GET['page']
&& !preg_match('!^(/|\.|(ht|f)tp://)!', $_GET['page'])
) $page = $_GET['page'];
else $page = 'home.html';
// EXECUTE TEMPLATE
require('template.php');
?>
template.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
</head>
<body>
<!-- plain HTML header goes here -->
<!-- RETRIEVE PAGE -->
<?php require('pages/' . $page); ?>
<!-- plain HTML footer goes here -->
</body>
</html>
samplepage.html
<h2>Sample Page Header</h2>
<p>Sample page content goes here.</p>
phppage.php
<h2>PHP Page Header</h2>
<p><?php echo 'PHP page content goes here.'; ?></p>
Everything goes to the index.php file. You can use PHP to block direct access to page files, or if using Apache web server you can use .htaccess to redirect all requests to the index.php file.
The technical URL looks like http://example.net/index.php?page=samplepage.html. But, using .htaccess can be effectively converted to http://example.net/samplepage.html with:
RewriteRule ^(.*)$ index.php?page=$1&%{QUERY_STRING} [L]

(WP) Code works in standalone codepen, but not on live site

I'm working on a gallery of sorts in Wordpress right now and I'm a bit stuck.
The idea is to change the post thumbnail on hover. The replacement image will be coming from a field generated by the Advanced Custom Fields plugin.
Now, I've managed to pull in both URLs and stored them in variables, but I still won't work. It works on a standalone CodePen, but not on the Wordpress site itself.
Wordpress code:
jQuery(document).ready(function() {
var firstthumb = '<?php echo the_post_thumbnail_url(); ?>';
var secondthumb = '<?php if( get_field('multiple_thumbs') ): ?><?php echo the_field('multiple_thumbs'); ?><?php endif; ?>';
jQuery('.member-thumbnail').hover(function() {
jQuery('.attachment-thumbnail').attr('src', secondthumb);
}, function() {
jQuery('.attachment-thumbnail').attr('src', firstthumb);
});
});
And it returns this:
jQuery(document).ready(function() {
var firstthumb = 'http://www.cozeh.com/wp2/wp-content/uploads/2016/01/pic2.png';
var secondthumb = 'http://www.cozeh.com/wp2/wp-content/uploads/2016/01/multiple2.png';
jQuery('.member-thumbnail').hover(function() {
jQuery('.attachment-thumbnail').attr("src", secondthumb);
}, function() {
jQuery('.attachment-thumbnail').attr("src", firstthumb);
});
});
Here's a link to the beta version.
And here's the codepen.
Would appreciate any explanation as to why this doesn't work or if you have any alternative solutions.
Edit: Updated code
The problem is that in the codepen you are not wrapping the img in an a tag, but you are doing it on the WordPress site. So to make it work in wordpress you need to remove the link that is wrapping the image or change you jQuery code, replacing this code:
jQuery('.member-thumbnail').hover(function() {
...
});
To this one:
jQuery('.member-thumbnail a').hover(function() {
...
});
Marking as solved.
Turns out it wasn't a script issue after all.
WP 4.4.+ was appending srcsetto the images as part of their move to make all images responsive. The img srcwas changing but not the srcsethence the problem.
Found a workaround to disabling the responsive images for now.
And I edited the code so it only affects one of the thumbnails, not every single one.
<?php if ( has_post_thumbnail() ) { ?>
<div class="member-<?php the_ID(); ?>-thumbnail">
<?php the_post_thumbnail('thumbnail'); ?>
</div>
<script type="text/javascript">
jQuery(document).ready(function() {
var firstthumb = '<?php the_post_thumbnail_url(); ?>';
var secondthumb = '<?php if( get_field('multiple_thumbs') ): ?><?php echo the_field('multiple_thumbs'); ?><?php endif; ?>';
jQuery('.member-<?php the_ID(); ?>-thumbnail').hover(function() {
jQuery('.member-<?php the_ID(); ?>-thumbnail .attachment-thumbnail').attr('src', secondthumb);
}, function() {
jQuery('.member-<?php the_ID(); ?>-thumbnail .attachment-thumbnail').attr('src', firstthumb);
});
});
</script>
Thanks for the input everybody.

Why is my admin-ajax so slow compared to other sites that also use it?

Here is my site.
If you hover over one of the projects and click the plus icon, the Ajax call goes out and the response returns in 1-4 seconds on average. I'm not understanding why it's so slow compared to a similar site that also uses admin-ajax.php (try hovering/clicking on one of the projects on that site to compare). All of the images called by Ajax are optimized. I also optimized my database tables. I'm not sure what else I can do.
Here is a comparison of the response time of admin-ajax.php from both sites. As you can see, the other site takes 480ms while mine takes 2s:
Here is how I have my Ajax call set up. Sorry, I didn't simplify the code because I think maybe the reason for the delay can only be found in the full code. The actual Ajax call is about halfway down.
(function($) {
// Function to allow an event to fire after all images are loaded
$.fn.imagesLoaded = function () {
var imgs = this.find('img[src!=""]');
// If there are no images, just return an already resolved promise
if (!imgs.length) {
return $.Deferred().resolve().promise();
}
// For each image, add a deferred object to the array which resolves when the image is loaded
var dfds = [];
imgs.each(function(){
var dfd = $.Deferred();
dfds.push(dfd);
var img = new Image();
img.onload = function(){dfd.resolve();};
img.src = this.src;
});
// Return a master promise object which will resolve when all the deferred objects have resolved
// IE - when all the images are loaded
return $.when.apply($, dfds);
};
// Function for additional styling
function projectStyles() {
// Check the first slide input
$('#slider input:first').attr('checked', 'checked');
$('#project-wrapper').addClass('activated');
// Make the articles grey again after activation
$('article.project').addClass('grayscale grayscale-fade').css('opacity', '0.4');
// CSS effects
$('.post-container').addClass('fadeInUp');
$('.close-button').addClass('fadeInDown');
// Remove pesky, sticky 'hover' class
$('article.project').removeClass('hover');
}
// Make the max-height of the container exact for a smoother transition
function matchContainerHeight() {
var heightHandler = function() {
var containerHeight = $('#project-container').outerHeight();
$('#project-wrapper.activated').css('max-height', containerHeight);
};
setTimeout(heightHandler, 100);
$(window).on('resize', heightHandler);
}
// Open the project container
function openProject() {
var post_id = $(this).data('id'), // data-id attribute for .post-link
ajaxURL = site.ajaxURL; // Ajax URL localized from functions.php
// Add a loading icon
$('<span class="loading-icon"></span>').insertBefore(this);
// Add the 'active' class to make sure the div stays dark while loading
$(this).closest('article.project').addClass('active hover-sticky');
// Make all the articles grey when an article is clicked
$('article.project').addClass('grayscale grayscale-fade grayscale-sticky').css('opacity', '0.4');
// No hover on images while a project is loading
$('article.project img').addClass('nohover');
// Remove all corner ribbons
$('article').removeClass('current');
$('.corner-ribbon').remove();
// Add a corner ribbon to note the current activated project
$(this).closest('article.project').removeClass('active').addClass('current');
$('<div class="corner-ribbon">Current</div>').prependTo('article.current');
// Call Ajax
$.ajax({
type: 'POST',
url: ajaxURL,
data: {'action': 'load-content', post_id: post_id },
success: function(response) {
// Wait until all images are loaded
$('#project-container').html(response).imagesLoaded().then(function() {
// Fire again to rearrange the slide in the DOM
resize();
// Remove all 'hover' classes
$('article.project').removeClass('hover-sticky grayscale-sticky');
$('article.project img').removeClass('nohover');
// Remove the loading icon
$('.loading-icon').remove();
// If the user has scrolled...
if ($(window).scrollTop() !== 0) {
// First scroll the page to the top
$('html, body').animate({
scrollTop : 0
},400, function() {
matchContainerHeight();
projectStyles();
});
// If the user has not scrolled...
} else {
matchContainerHeight();
projectStyles();
}
return false;
});
}
});
}
// User event
$('#content').on('click', '.post-link', function(e) {
e.preventDefault();
var projectTitle = $(this).data('title'), // data-title attribute for .post-link
projectSlug = $(this).data('slug'); // data-slug attribute for .post-link
// Calls openProject() in context of 'this' (.post-link)
openProject.call(this);
$('head').find('title').text(projectTitle + ' | Keebs');
});
})(jQuery);
Here is the Ajax response file. I'm using the ACF plugin, but I tried the response without any of the ACF fields and the wait time was the same. I also tried removing everything within the my_load_ajax_content() function but the wait time was still the same as well. So I'm guessing something else is causing the long wait time. I also tried GET instead of POST but the response time was around the same:
<?php
/**
* Ajax functions
*/
// Return the post content to the AJAX call
function my_load_ajax_content () {
$args = array(
'p' => $_POST['post_id'],
'post_type' => 'projects'
);
$post_query = new WP_Query( $args );
while( $post_query->have_posts() ) : $post_query->the_post(); ?>
<div class="post-container">
<div id="project-left-content">
<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
<?php the_content(); ?>
<?php if( get_field('client') ): ?>
<div class="client">
Client(s): <?php the_field('client'); ?>
</div>
<?php endif; ?>
<div class="project-cats">
<?php
$cat_names = wp_list_pluck( get_the_category(), 'cat_name');
echo join( ', ', $cat_names );
?>
</div>
<?php if( get_field('url') ): ?>
<div class="project-link">
<a class="first after" href="http://<?php the_field('url'); ?>" target="_blank"><?php the_field('url'); ?></a>
</div>
<?php endif; ?>
</div>
<div id="project-right-content">
<?php if( have_rows('slides') ): ?>
<div id="slider">
<!-- Slider Setup -->
<?php if( have_rows('slides') ):
$slideNumber = 0;
while ( have_rows('slides') ) : the_row();
$slideNumber++;
?>
<input type="radio" name="slider" id="slide<?php echo $slideNumber; ?>">
<?php endwhile;endif; ?>
<!-- Slide -->
<?php if( have_rows('slides') ): ?>
<div id="slides">
<div id="overflow">
<div class="inner">
<?php if( have_rows('slides') ):
while ( have_rows('slides') ) : the_row();
$slideImage = get_sub_field('slide_image');
?>
<article>
<img src="<?php echo $slideImage; ?>" alt="<?php the_title(); ?>">
</article>
<?php endwhile;endif; ?>
</div><!-- #inner -->
</div><!-- #overflow -->
</div><!-- #slides -->
<?php endif; ?>
<!-- Controls -->
<?php if( have_rows('slides') ):
$slideNumber = 0;
?>
<div id="active">
<?php while ( have_rows('slides') ) : the_row();
$slideNumber++;
?>
<label for="slide<?php echo $slideNumber; ?>"></label>
<?php endwhile; ?>
</div><!-- #active -->
<?php endif; ?>
</div><!-- #slider -->
<?php endif; ?>
</div><!-- #project-right-content -->
</div><!-- .post-container -->
<?php
endwhile;
wp_die();
}
add_action ( 'wp_ajax_nopriv_load-content', 'my_load_ajax_content' ); // when the user is logged in
add_action ( 'wp_ajax_load-content', 'my_load_ajax_content' ); // when the user is not logged in
Does anybody see something that I should be doing differently?
Looks like your site is hosted on dreamhost and most likely on shared hosting offering they have. The other website you mentioned looks like it is hosted on its own VPS. Shared hosting is often known for their slow database performance.
Your best option might be to use a caching solution like 'WP Super Cache' or 'W3 Total Cache' that saves the webpage to memory or disk on first request and serves from there on subsequent requests bypassing the database.
These are both wordpress plugin and can be easily installed from the admin plugins section.
https://wordpress.org/plugins/wp-super-cache/
https://wordpress.org/plugins/w3-total-cache/
Other option is trying to create indexes on the databse for faster searching. You could also look at using a small VPS (AmazonEC2 free tier or $5/month from digital ocean etc) if you know how to install Apache/mysql etc.
I would want to suggest you that rather then echoing HTML code from your php file you just return the main data(only raw information based on the click) as json response and then generate the html tags based on that and append it . Creating HTML from javascript is much faster than echoing HTML , specially during ajax call. I am sure if you do this you can get quite fast performance. Any big or large site they dont send HTML in ajax response. Majorly pure json response containing the key information is echoed. And on basis of that the divs are generated to load the section faster.
Can I make a suggestion?
Instead of defining your function like this:
(function($)
try something like this:
jQuery(document).ready(function($) {
$('selector').whatever();
})
I'm still learning Wordpress myself but I have found that defining the function as using jQuery can make a difference. I think this is because Wordpress is unsure of which library you want to use.

How to execute js(scrollLeft) from php?

i have a function to scroll a div like this:
function scrTo(id, to)
{
document.getElementById(id).scrollLeft = to;
}
and try to call it via php:
echo"<div id='movingtab' style='overflow-x:auto; width:765;'>";
echo"<table>...Some Table Content...</table>";
echo"</div>";
if(isset($_GET['scrl']))
{
echo"<script type='text/javascript'>";
echo"scrTo('movingtab', '".$_GET['scrl']."');";
echo"</script>";
}
The idea is to scroll to last position after the content of div changed via ajax, but when the script executed the scroll is back to begining and not back to last scroll position before div content loaded. I've try to call the function via <script onload="">, but still not working. Can anyone help solve my problem?
Probably Should use:
echo "<script type='text/javascript'>
$(document).ready(function() {
scrTo('movingtab', '".$_GET['scrl']."');
});
</script>";
<?php if(isset($_GET['scrl'])) { ?>
<script type='text/javascript'>
function scrTo(id, to){
document.getElementById(id).scrollLeft = to;
}
</script>
<?php } ?>
<div id='movingtab' style='overflow:auto; width:765px; border:1px solid blue;'>
<table><tr><td>...Some Table Content...</td></tr></table>
</div>
<button id="scroll" onclick="scrTo('movingtab', '<?php echo $_GET['scrl']; ?>')">scrollLeft()</button>
Your approach is wrong. You should call the function in the callback of your ajax request. This functionality should be done solely in JavaScript. If you are echoing JavaScript from PHP it is most probably the wrong approach.

Categories