Browser - Force reload deleting cookies? - javascript

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.

Related

Dark mode checkbox should be saved in local storage

I'm trying to implement a dark mode - light mode switcher on my website. I don't really know anything about JS but I played around with the code snippets I found online and put together something that kind of works.
What I have so far:
- I have two sets of colors in CSS that I can switch between with a checkbox in the navbar.
- I also found out how I can store a checkbox's state locally, so if I turn on the dark mode and then navigate to another page, the checkbox is still checked.
The problem is that every time I navigate to another page, the checkbox gets unchecked first and then it realises that it has to be checked and it checks itself automatically. But it takes time, there's even an animation which is kind of annoying because if I check it on a page, I want it to be checked by default on all the other pages until I turn it off.
Here's a video that explains it better: https://drive.google.com/file/d/1y48yh1h1bGM6abrthVmtUD8azVuDG4yE/view?usp=sharing
Any help would be appreciated since I really don't know what's going on here :D
// DARK MODE SWITCHER
var checkbox = document.querySelector('input[name=mode]');
checkbox.addEventListener('change', function() {
if(this.checked) {
trans()
document.documentElement.setAttribute('data-theme', 'dark')
} else {
trans()
document.documentElement.setAttribute('data-theme', 'light')
}
})
let trans = () => {
document.documentElement.classList.add('transition');
window.setTimeout(() => {
document.documentElement.classList.remove('transition');
}, 1000)
}
// SAVE DARK MODE CHECKBOX STATE IN LOCAL STORAGE
var checkboxValues = JSON.parse(localStorage.getItem('checkboxValues')) || {},
$checkboxes = $("#checkbox-container :checkbox");
$checkboxes.on("change", function(){
$checkboxes.each(function(){
checkboxValues[this.id] = this.checked;
});
localStorage.setItem("checkboxValues", JSON.stringify(checkboxValues));
});
// On page load
$.each(checkboxValues, function(key, value) {
$("#" + key).prop('checked', value);
});
the jsfiddle solution :
https://jsfiddle.net/zhbo40ma/
you need to set your theme at page load :
$.each(checkboxValues, function(key, value) {
$("#" + key).prop('checked', value);
if($('#'+key).attr('name') == 'mode') {
if(value) {
trans();
document.documentElement.setAttribute('data-theme', 'dark')
}
else {
trans();
document.documentElement.setAttribute('data-theme', 'light')
}
}
});
don't forget to write your trans() function before your page load function cause you declare it with a let

JQuery, .attr - Remember state using cookies after page reload

I wrote a function that changes logo to minimised version of it when I click on a button by changing attribute of an image. Also, after another click on the same button, logo switches back to original.
Everything is as I expected but I have a problem when I refresh the page. When I refresh the page, the browser just switches the logo back to original. So, I want the browser to remember if logo is switched and remember that state after reload of page. Please see my code below. I've seen similar solutions here but I don't know how to implement it in my code.
How can I set and use cookies for this?
$('#changeLogo').click(function() {
if ($(".logo").attr('src') === "files/img/logo-min.png") {
$(".logo").attr('src', "files/img/logo.png");
}
else {
$(".logo").attr('src', "files/img/logo-min.png");
}
});
Localstorage is a better option for this:
$(function(){
$('#changeLogo').click(function() {
var logoSrc;
if ($(".logo").attr('src') === "files/img/logo-min.png") {
logoSrc = "files/img/logo.png";
}
else {
logoSrc = "files/img/logo-min.png";
}
$(".logo").attr('src', logoSrc);
localStorage.setItem("logoSrc", logoSrc);
});
if ( typeof localStorage.logoSrc !== "undefined" )
$(".logo").attr('src', localStorage.logoSrc);
});
$(document).ready(function(){
var logo = localStorage.getItem('logo');
if(logo != null){
$(".logo").attr('src', logo);
}
$('#changeLogo').click(function() {
if ($(".logo").attr('src') === "files/img/logo-min.png") {
$(".logo").attr('src', "files/img/logo.png");
}
else {
$(".logo").attr('src', "files/img/logo-min.png");
}
localStorage.setItem('logo',$(".logo").attr('src'));
});
});
Set src in localStorage and on page load get the value and set the src again to logo.
You can set cookies using javascript api: https://www.w3schools.com/js/js_cookies.asp
Or use an easier api like this:
https://github.com/js-cookie/js-cookie
So in the if/else you can save the currently used link of the logo to a cookie:
//set
Cookies.set('logo-path', 'files/img/logo-min.png');
//get
Cookies.get('logo-path');
You could also utilize local storage (https://www.w3schools.com/html/html5_webstorage.asp) but it is not guaranteed that it will work on older browsers.
If you want to use cookies, you can use the JQuery plugin http://plugins.jquery.com/cookie/
Then :
$(document).ready(function(){
if (typeof $.cookie('logo') === 'undefined')
$.cookie('logo', "files/img/logo-min.png");
$('#changeLogo').click(function() {
if ($.cookie('logo') === "files/img/logo-min.png") {
$.cookie('logo', "files/img/logo.png");
} else {
$.cookie('logo', "files/img/logo-min.png");
}
$(".logo").attr('src', $.cookie('logo'));
});
});

load history.js via ajax conditionally when browser does not support the HTML5 history API

Hi I'm trying to use modernizer load (yepnope.js) to conditionally load history.js (via AJAX) only when the browser does not natively support the HTML5 history API....
However in my tests on IE9/IE8 modernizer appears to load the history.js file successfully (at least I can see the HTTP request in the IE9 developer tools) However i still get an error (unrecognised method) when I try to use history.pushState or History.pushState.... can anyone suggest why this might be?
Modernizr.load([{
//test
test : Modernizr.history,
//if yes then do nothing as nothing extra needs loading....
//if no then we need to load the history API via AJAX
nope : ['/js/asm/vendor/history.js'],
complete : function() {
Tabs.init();
}
}])
var Tabs = {
init: function() {
this.bindUIfunctions();
this.pageLoadCorrectTab();
},
bindUIfunctions: function() {
.......
},
changeTab: function(hash) {
var anchor = $("[href='" + hash + "']");
var div = $(hash);
function displayTab(anchortab) {
// activate correct anchor (visually)
........
}
displayTab(anchor);
// update history stack adding additional history entries.
if (typeof history.pushState !== "undefined") {
// pushState is supported!
window.history.pushState(null, null, hash);
} else {
//use history API instead
History.pushState(null, null, hash);
}
//We also need to handle the backstate by telling the brower to trigger the tab behaviour!
window.addEventListener("popstate", function(e) {
anchor = $('[href="' + document.location.hash + '"]');
if (anchor.length) {
displayTab(anchor);
} else {
defaultAnchor = $('.transformer-tabs li.active a');
displayTab(defaultAnchor);
}
});
// Close menu, in case mobile
},
// If the page has a hash on load, go to that tab
pageLoadCorrectTab: function() {
......
},
toggleMobileMenu: function(event, el) {
......
}
}
I found I got on much better with the following lib (although IE8 still does not allow me to use the back and forward browser button to go between tabs).... at least there are no JS errors and it works for me in IE9 https://github.com/devote/HTML5-History-API
Modernizr.load([{
//test
test : Modernizr.history,
//if yes then do nothing as nothing extra needs loading....
//if no then we need to load the history API via AJAX
nope : ['/js/asm/vendor/history.min.js'],
complete : function() {
var location = window.history.location || window.location;
Tabs.init();
}
}])
//responsive tabs API code.
var Tabs = {
init: function() {
this.bindUIfunctions();
this.pageLoadCorrectTab();
},
bindUIfunctions: function() {
// Delegation
$(document)
.on("click", ".transformer-tabs a[href^='#']:not('.active')", function(event) {
Tabs.changeTab(this.hash);
event.preventDefault();
})
.on("click", ".transformer-tabs a.active", function(event) {
Tabs.toggleMobileMenu(event, this);
event.preventDefault();
});
},
changeTab: function(hash) {
var anchor = $("[href='" + hash + "']");
function displayTab(anchortab) {
var url = anchortab.attr("href");
console.log("url" + url);
var div = $(url);
// activate correct anchor (visually)
anchortab.addClass("active").parent().siblings().find("a").removeClass("active");
// activate correct div (visually)
div.addClass("active").siblings().removeClass("active");
anchortab.closest("ul").removeClass("open");
}
displayTab(anchor);
// update history stack adding additional history entries.
// pushState is supported!
history.pushState(null, null, hash);
//We also need to handle the backstate by telling the brower to trigger the tab behaviour!
$(window).on('popstate', function(e) {
anchor = $('[href="' + document.location.hash + '"]');
if (anchor.length) {
displayTab(anchor);
} else {
defaultAnchor = $('.transformer-tabs li.active a');
displayTab(defaultAnchor);
}
});
// Close menu, in case mobile
},
// If the page has a hash on load, go to that tab
pageLoadCorrectTab: function() {
this.changeTab(document.location.hash);
},
toggleMobileMenu: function(event, el) {
$(el).closest("ul").toggleClass("open");
}
}

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); }
}
});

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

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.

Categories

Resources