How to prevent flash un-styled content when injected class to body - javascript

Greeting all wise man! I really need your help here as I'm new to JS/DOM stuff. I have this script that basically get and set cookie and when specific element is trigger, it will store new cookie value and refresh the browser. The value then inject to body class. However, I've counter a problem when in the process of add new class to body, it will read default style (FOUC) before read current style css injected into its body.
(function ($) {
var Cookies = {
init: function () {
themes = Cookies.getCookie('THEME');
if (themes != null && themes != '') {
document.getElementsByTagName('body')[0].className += ' custom-'+themes;
}
else {
return;
}
},
setCookie: function (name, value, expired) {
var expiredDate = new Date();
expiredDate.setDate(expiredDate.getDate() + expired);
document.cookie = name + '=' + escape(value);
(expired == null) ? '' : ';expires=' + expiredDate.toUTCString();
},
getCookie: function (name) {
if (document.cookie.length > 0) {
cookieStart = document.cookie.indexOf(name + '=');
if (cookieStart != -1) {
cookieStart = cookieStart + name.length + 1;
cookieEnd = document.cookie.indexOf(';', cookieStart);
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
return unescape(document.cookie.substring(cookieStart, cookieEnd));
}
}
return '';
}
};
$('.boxer').each(function () {
$(this).bind('click', function (e) {
e.preventDefault();
var element = $(this).attr('class').replace('boxer', '').replace(' ', '');
setTimeout(function () {
Cookies.setCookie('THEME', element, 1);
window.location.replace(window.location.href);
}, 100);
});
});
$(function () {
Cookies.init();
});
})(jQuery);
How can I prevent this problem? I've already tried put it as first head element before link element, however, it also failed.

Try setting the theme on the body tag without having to refresh the browser. One of the great things about jQuery is that you can inject the new body class without having to refresh the page. You should still set the cookie, though, because that is important for the rest of the website.
When you navigate from page to page you will need to employ some server-side scripting language to read the cookie and write the appropriate CSS class on the body tag prior to the page loading in the browser. In PHP this would look something like:
<body <?php if(isset($_COOKIE['THEME'])) { echo 'class="'.$_COOKIE['THEME'].'"'; } ?>>
I would not suggest trying this with JavaScript alone for the reason that you've stated, the page will load and not be styled until the JavaScript engine can run in the web browser and add the desired CSS classes.

Related

infinite scroll on squarespace get category filter

I am using this code to infinite load a page on squarespace. My problem is the reloading doesn't capture the filtering that I have set up in my url. It cannot seem to 'see' the variables or even the url or categoryFilter in my collection. I've tried to use a .var directive but the lazy loaded items cannot see the scope of things defined before it. I'm running out of ideas here please help!
edit: I've since found the answer but gained another question.
I was able to use window.location.href instead of window.location.pathname to eventually get the parameters that way. Except this doesn't work in IE11 so now I have to search for this.
<script>
function infiniteScroll(parent, post) {
// Set some variables. We'll use all these later.
var postIndex = 1,
execute = true,
stuffBottom = Y.one(parent).get('clientHeight') + Y.one(parent).getY(),
urlQuery = window.location.pathname,
postNumber = Static.SQUARESPACE_CONTEXT.collection.itemCount,
presentNumber = Y.all(post).size();
Y.on('scroll', function() {
if (presentNumber >= postNumber && execute === true) {
Y.one(parent).append('<h1>There are no more posts.</h1>')
execute = false;
} else {
// A few more variables.
var spaceHeight = document.documentElement.clientHeight + window.scrollY,
next = false;
/*
This if statement measures if the distance from
the top of the page to the bottom of the content
is less than the scrollY position. If it is,
it's sets next to true.
*/
if (stuffBottom < spaceHeight && execute === true) {
next = true;
}
if (next === true) {
/*
Immediately set execute back to false.
This prevents the scroll listener from
firing too often.
*/
execute = false;
// Increment the post index.
postIndex++;
// Make the Ajax request.
Y.io(urlQuery + '?page=' + postIndex, {
on: {
success: function (x, o) {
try {
d = Y.DOM.create(o.responseText);
} catch (e) {
console.log("JSON Parse failed!");
return;
}
// Append the contents of the next page to this page.
Y.one(parent).append(Y.Selector.query(parent, d, true).innerHTML);
// Reset some variables.
stuffBottom = Y.one(parent).get('clientHeight') + Y.one(parent).getY();
presentNumber = Y.all(post).size();
execute = true;
}
}
});
}
}
});
}
// Call the function on domready.
Y.use('node', function() {
Y.on('domready', function() {
infiniteScroll('#content','.lazy-post');
});
});
</script>
I was able to get this script working the way I wanted.
I thought I could use:
Static.SQUARESPACE_CONTEXT.collection.itemCount
to get {collection.categoryFilter} like with jsont, like this:
Static.SQUARESPACE_CONTEXT.collection.categoryFilter
or this:
Static.SQUARESPACE_CONTEXT.categoryFilter
It didn't work so I instead changed
urlQuery = window.location.pathname
to
urlQuery = window.location.href
which gave me the parameters I needed.
The IE11 problem I encountered was this script uses
window.scrollY
I changed it to the ie11 compatible
Window.pageYOffset
and we were good to go!

How to properly implement a custom ajax

In order to keep 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, I am trying to implement this solution made by #Buzinas (special thanks). In a few more words:
In header.php we have this script:
<head>
...
<script>
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();
}
}
// CUSTOM AJAX CONTENT LOADING FUNCTION
function ajaxRevslider(obj) {
// obj.type : Post Type
// obj.id : ID of Content to Load
// obj.aspectratio : The Aspect Ratio of the Container / Media
// obj.selector : The Container Selector where the Content of Ajax will be injected. It is done via the Essential Grid on Return of Content
var content = "";
data = {};
data.action = 'revslider_ajax_call_front';
data.client_action = 'get_slider_html';
data.token = '<?php echo wp_create_nonce("RevSlider_Front"); ?>';
data.type = obj.type;
data.id = obj.id;
data.aspectratio = obj.aspectratio;
// SYNC AJAX REQUEST
jQuery.ajax({
type:"post",
url:"<?php echo admin_url('admin-ajax.php'); ?>",
dataType: 'json',
data:data,
async:false,
success: function(ret, textStatus, XMLHttpRequest) {
if(ret.success == true)
content = ret.data;
},
error: function(e) {
console.log(e);
}
});
// FIRST RETURN THE CONTENT WHEN IT IS LOADED !!
return content;
};
// CUSTOM AJAX FUNCTION TO REMOVE THE SLIDER
function ajaxRemoveRevslider(obj) {
return jQuery(obj.selector+" .rev_slider").revkill();
}
document.addEventListener('DOMContentLoaded', function() {
var main = document.querySelector('div[role=main]'),
spinner = document.querySelector('div.sk-spinner'),
pages = {};
window.addEventListener('load', function() {
toggleSpinner(false);
});
function toggleSpinner(b) {
spinner.classList[b ? 'remove' : 'add']('hidden');
document.getElementById('wrapper').style.opacity = b ? 0 : 1;
}
function changePage(url, title) {
setTimeout(function() {
window.SITE.init();
window.vc_js();
}, 0);
history.pushState({
html: main.innerHTML,
title: title
}, '', url);
toggleSpinner(false);
}
document.getElementById('menu-menu-2').addEventListener('click', function(e) {
var el = e.target;
if (el.tagName === 'A') {
e.preventDefault();
toggleSpinner(true);
if (pages[el.href]) {
main.innerHTML = '';
main.appendChild(pages[el.href]);
changePage(el.href);
}
else {
ajax(el.href, function(xhr) {
var frag = document.createRange().createContextualFragment(xhr.responseText);
main.innerHTML = '<div>' + frag.querySelector('div[role=main]').innerHTML + '</div>';
//pages[el.href] = main.firstElementChild;
var _currentScripts = [].slice.call(document.querySelectorAll('script'));
[].forEach.call(frag.querySelectorAll('script'), function(el, i) {
if ((el.src === '' && el.parentNode)
|| el.src.indexOf('slider') >= 0
|| el.src.indexOf('Scroll') >= 0
|| el.src.indexOf('vendor') >= 0
|| el.src.indexOf('composer') >= 0
) {
var s = _currentScripts.filter(function(x) {
return x.src === el.src;
});
while (s.length) {
if (s[0].parentNode)
s[0].parentNode.removeChild(s[0]);
s.shift();
}
document.body.appendChild(el);
}
});
[].forEach.call(frag.querySelectorAll('style'), function(el, i) {
document.querySelector('head').appendChild(el);
});
changePage(el.href, frag.querySelector('title').textContent);
});
}
}
});
window.addEventListener('popstate', function(e) {
if (e.state) {
main.innerHTML = e.state.html;
document.title = e.state.title;
}
});
});
</script>
...
</head>
The following jquery-ready.js is registered/enqueued in script-calls.php:
(function($){
var readyList = [];
// Store a reference to the original ready method.
var originalReadyMethod = jQuery.fn.ready;
// Override jQuery.fn.ready
jQuery.fn.ready = function(){
var args = [].slice.call(arguments);
if(args.length && args.length > 0 && typeof args[0] === 'function') {
readyList.push(args[0]);
}
// Execute the original method.
originalReadyMethod.apply( this, args );
};
// Used to trigger all ready events
$.triggerReady = function() {
$(readyList).each(function(i, el) {
try {
el.apply(el);
} catch(e) {
console.log(e);
}
});
};
})(jQuery);
Also, in page.php I replaced get_header() and get_footer() functions as follows:
<?php
if(!isset($_REQUEST['ajax'])){
get_header();
}
?>
<?php
if (is_page()) {
$id = $wp_query->get_queried_object_id();
$sidebar = get_post_meta($id, 'sidebar_set', true);
$sidebar_pos = get_post_meta($id, 'sidebar_position', true);
}
?>
...
<?php
if(!isset($_REQUEST['ajax'])){
get_footer();
}
?>
There are still some issues trying to load a page with Revolution slider or Visual Composer Parallax content, like we have on Parallax or About us pages for example.
You can use this link and navigate to the above mentioned pages; Tests are made only in Chrome 45.0.2454.101 m 64-bit/ Win7, not yet prepared for IE, Firefox, mobile etc .
About the behaviour:
Rev slider parallax content, will become scrambled from the second link visit (Home or Parallax pages); The Visual Composer parallax content (the guy at the desk picture, About us page for example) is fixed on the first link visit - after F5 will be fine;
The menu mynewmenu.js will remember the state on session, so u'll have to close the browser in oder to visit multiple direct links properly.
I've received an answer from Rev slider support team telling me:
The best option for Ajax is to just add the slider's shortcode to a regular page/post, and then the slider's "init" script is will automatically be included with the slider's HTML. Then when the slider's HTML is removed from the DOM, all jQuery events are also removed. So all you really need to do is pull in the slider as page/post content, and then you won't need any custom script for the slider specifically.
Unfortunately I have no idea how can I approach this, implementing the above sugestion into my already received solution.
Could be something related to API(?) I've found these infos on Revolution slider / Visual Composer pages. Any thoughts?
You should probably read:
https://codex.wordpress.org/AJAX_in_Plugins#Ajax_on_the_Viewer-Facing_Side
http://wptheming.com/2013/07/simple-ajax-example/
You should pass PHP variables to your javascript files using wp_localize_script.
Even if you don't do it that way, you shouldn't need to hack the main page templates just to serve specific content -- create a one-off page, then make a specific template for it. Then you can use that page's URL as your ajax endpoint.
But if what you really need to do is run Rev Slider's shortcode (and the Parallax thing if it has one too) somewhere other than a page:
In code (page template, functions.php, etc) - https://developer.wordpress.org/reference/functions/do_shortcode/
In a widget (which links to the next) -- https://digwp.com/2010/03/shortcodes-in-widgets/
Basically everywhere -- http://stephanieleary.com/2010/02/using-shortcodes-everywhere/
Do you need help with this still? I think the revolution slider's support team nailed it with the statements
just add the slider's shortcode to a regular page/post
and
all you really need to do is pull in the slider as page/post content
So, use the slider on your WordPress page/post through the shortcode, [shortcode]. Then reference the $_GET[] and/or $_POST[] array elements in php (or javascript, however you're doing it) as needed.

to show alert message when user closes particular page for first time

I have jquery which shows alert message when page loads for first time and not again but now i want jquery which shows alert message when page is closed for first time only Please can anyone help me what changes can be made in give jquery which is for page load?
<script type="text/javascript">
// First Time Visit Processing
// copyright 10th January 2006, Stephen Chapman
// permission to use this Javascript on your web page is granted
// provided that all of the below code in this script (including this
// comment) is used without any alteration
function rC(nam)
{
var tC = document.cookie.split('; ');
for (var i = tC.length - 1; i >= 0; i--)
{
var x = tC[i].split('=');
if (nam == x[0])
return unescape(x[1]);
}
return '~';
}
function wC(nam,val)
{
document.cookie = nam + '=' + escape(val);
}
function lC(nam,pg)
{
var val = rC(nam);
if (val.indexOf('~'+pg+'~') != -1)
return false;
val += pg + '~';
wC(nam,val);
return true;
}
function firstTime(cN)
{
return lC('pWrD4jBo',cN);
}
function thisPage()
{
var page = location.href.substring(location.href.lastIndexOf('\/')+1);
pos = page.indexOf('.');
if (pos > -1)
{
page = page.substr(0,pos);
}
return page;
}
// example code to call it - you may modify this as required
function start() {
if (firstTime(thisPage())) {
// this code only runs for first visit
alert('welcome');
}
// other code to run every time once page is loaded goes here
}
onload = start;
</script>
That's really overcomplicating things?
To alert a message the first time any page loads, you'd do:
if ( ! localStorage.getItem(window.location) ) {
localStorage.setItem(window.location, true);
alert('Welcome');
}
You can't really alert anything on beforeunload, but you can pop up a confirm dialog:
window.onbeforeunload = function(e) {
if ( ! localStorage.getItem('unload_' + window.location) ) {
localStorage.setItem('unload_' + window.location, true);
return 'Dialog text here.';
}
}
Support for older browsers can be added with the localStorage shim from MDN.

Browser - Force reload deleting cookies?

I have created a page with a select input to change the jQuery UI theme in use. When the theme is changed, it is stored in a cookie. When the page loads, if the cookie exists, the theme is restored, else a default theme is loaded.
My code does work when i refresh the page using F5, but if i force a complete reload using ctrl + F5, it doesn't. Is it a problem in my code or is it a normal effect ?
Here is my code if needed :
(function($) {
$(function() {
var $themeSelect = $('#themeSelect');
var initialTheme = $.cookie('theme');
$themeSelect.on('change', function() {
var dir = 'jQueryUI/css/' + $themeSelect.val();
$('#uiThemeA').attr('href', dir + '/jquery-ui.min.css');
$('#uiThemeB').attr('href', dir + '/jquery.ui.theme.css');
$.cookie('theme', $themeSelect.val());
});
if(initialTheme !== undefined) {
$themeSelect.children().each(function(index, element) {
var $element = $(element);
if($element.attr('selected')) {
$element.removeAttr('selected');
}
if($element.attr('value') === initialTheme) {
$element.attr('selected');
}
}).trigger('change');
} else {
$.cookie('theme', $themeSelect.val());
}
});
})(jQuery);
Thanks for your help !
I found the problem :
There was a mistake in my code :
if($element.attr('value') === initialTheme) {
$element.attr('selected');
}
Should be :
if($element.attr('value') === initialTheme) {
$element.attr('selected', 'selected');
}
And no, a forced reload doesn't delete cookies.

javascript html5 history, variable initialization and popState

main question
Is there a javascript way to identify if we are accessing a page for the first time or it is a cause of a back?
My problem
I'm implementing html5 navigation in my ajax driven webpage.
On the main script, I initialize a variable with some values.
<script>
var awnsers=[];
process(awnsers);
<script>
Process(awnsers) will update the view according to the given awnsers, using ajax.
In the funciton that calls ajax, and replaces the view, I store the history
history.pushState(state, "", "");
I defined the popstate also, where I restore the view according to the back. Moreover, I modify the global variable awnsers for the old value.
function popState(event) {
if (event.state) {
state = event.state;
awnsers=state.awnsers;
updateView(state.view);
}
}
Navigation (back and forth) goes corectly except when I go to an external page, and press back (arrving to my page again).
As we are accessing the page, first, the main script is called,the valiable awnsers is updated, and the ajax starts. Meanwile, the pop state event is called, and updates the view. After that the main ajax ends, and updates the view according to empty values.
So I need the code:
<script>
var awnsers=[];
process(awnsers);
<script>
only be called when the user enters the page but NOT when it is a back. Any way to do this?
THanks!
Possible solution
After the first awnser I have thought of a possible solution. Tested and works, whoever, I don't know if there is any cleaner solution. I add the changes that I've done.
First I add:
$(function() {
justLoaded=true;
});
then I modify the popState function, so that is in charge to initialize the variables
function popState(event) {
if (event.state) {
state = event.state;
awnsers=state.awnsers;
updateView(state.view);
} else if(justLoaded){
awnsers=[];
process(awnsers);
}
justLoaded=false;
}
Thats all.
what about using a global variable?
var hasLoaded = false;
// this function can be called by dom ready or window load
function onPageLoad() {
hasLoaded = true;
}
// this function is called when you user presses browser back button and they are still on your page
function onBack() {
if (hasLoaded) {
// came by back button and page was loaded
}
else {
// page wasn't loaded. this is first visit of the page
}
}
Use cookie to store the current state.
yeah! This is what I have:
var popped = (($.browser.msie && parseInt($.browser.version, 10) < 9) ? 'state' in window.history : window.history.hasOwnProperty('state')), initialURL = location.href;
$(window).on('popstate', function (event) {
var initialPop = !popped && location.href === initialURL, state;
popped = true;
if (initialPop) { return; }
state = event.originalEvent.state;
if (state && state.reset) {
if (history.state === state) {
$.ajax({url: state.loc,
success: function (response) {
$(".fragment").fadeOut(100, function () {
$(".fragment").html($(".fragment", response).html()).fadeIn(100);
);
document.title = response.match(/<title>(.*)<\/title>/)[1];
}
});
} else { history.go(0); }
else {window.location = window.location.href; }
});
And:
$.ajax({url:link,
success: function (response) {
var replace = args.replace.split(",");
$.each(replace, function (i) {
replace[i] += ($(replace[i]).find("#video-content").length > 0) ? " #video-content" : "";
var selector = ".fragment "+replace[i];
$(selector).fadeOut(100, function () {
$(selector).html($(selector,response).html()).fadeIn(100, function () {
if (base.children("span[data-video]")[0]) {
if ($.browser.msie && parseInt($.browser.version, 10) === 7) {
$("#theVideo").html("");
_.videoPlayer();
} else {
_.player.cueVideoById(base.children("span[data-video]").attr("data-video"));
}
}
});
});
});
document.title = response.match(/<title>(.*)<\/title>/)[1];
window.history.ready = true;
if (history && history.pushState) { history.pushState({reset:true, loc:link}, null, link); }
}
});

Categories

Resources