I'm running a Wordpress Multisite Installation with two languages: Hebrew and English.
I have a plugin called Geo IP that helps me to redirect users based on their IP country.
But actually I need more.
I would like to save the last language the user choose.
Example :
if a user close the tab of my site on the english language, I would like that when he comes back, he'll get the english language. Vice versa for Hebrew.
I'm not a pro developer, but I think a cookie can be a solution, and I would like the solution to be in JS if possible.
Update: the code I made ! WDYT guys ?
function get_language {
var myLang = getcookie ('language');
if ( myLang == 'hebrew') {
window.location = "http://zeek.me/he/";
}
else if ( myLang == 'english') {
window.location = "http://zeek.me";
}
else {
window.location = "http://zeek.me";
}
}
function set_language(lang) {
var setLang = setcookie ('language', lang, 30);
var englishClick = document.getElementById('#english_lang');
var hebrewClick = document.getElementById('#hebrew_lang');
englishClick.addEventListener('click', function() {
set_language('english');
})
hebrewClick.addEventListener('click', function() {
set_language('hebrew');
})
}
What you guys think ?
Any solution ?
Thanks,
Simon
As you want a solution with Javascript, you should consider the localStorage. Cookies are nice if you want to know the selected language server-side, but if you just need it local, localStorage is better (reasons below).
To set a localStorage item, use
localStorage.setItem(key, value);
and afterwards to view the value, use
localStorage.getItem(key);
localStorage has a few advantages vs. cookies. Some of them are:
Cookies are included with every HTTP request, thereby slowing down your website by sometimes needlessly transmitting the same data over and over
Cookies are included with every HTTP request, thereby sending data unencrypted over the internet
Cookies are limited to about 4 KB of data
Sounds pretty basic, cookies are what you want. You can stick with javascript, or use php cookies. You opted for a javascript solution.
You'll need a few functions to make this work. Here are some examples below, but these are not working code. You'll need to edit them to do the language switching.
function init_language() {
// this function called when no language has been defined yet
var lang = getcookie( 'language' );
if ( lang == 'hebrew' ) hebrew_pls();
}
function switch_language() {
// When the user takes action to change language, ie, clicks a flag icon
if ( selected_language == 'hebrew' ) hebrew_pls();
}
function hebrew_pls() {
set_language('hebrew'); // aka, whatever you want to do
setcookie( 'language', 'hebrew', 30 ); // remember the language for 30 days
}
Here are the cookie functions I've been using for awhile. It's based on "How do I create and read a value from cookie?". I have modified these so they are a bit easier to use. If you don't like my modifications, there are plenty of alternatives online. Unfortunately JavaScript does not have an easy way to store cookies by default (without third party plugins/scripts).
/*
setCookie( name, value, days, [path = "/"] )
Sets a cookie, expires after "days" have passed
getCookie( name, default )
Gets the value of a cookie, or returns "default". Note: Does not set the cookie to default.
*/
function setCookie(c_name, value, exdays, path) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value = escape(value) + ((exdays == null) ? "" : ("; expires=" + exdate.toUTCString()));
document.cookie = c_name + "=" + c_value + ((path == null) ? "; path=/" : "; path=" + path);
}
function getCookie(c_name, c_default) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
if (typeof c_default != 'undefined') return c_default;
return false;
}
Related
I have a simple web application that calls the Spotify API, and, among other things, allows a user to download their "Liked Songs". The 'download' view writes a csv file of the 'Liked Songs' to a tmp directory and then downloads that file using flask.send_from_directory.
#bp.route('/download', methods=['GET'])
#login_required
def download():
...
# Edited with more details below
return send_from_directory(
temp_dir,
target[0],
as_attachment=True,
attachment_filename=file_name
)
It all works as intended but can take a while if a user has many thousands of Liked Songs. During that 20+ seconds I would like to give the user some feedback that the task is processing -- a message or loading animation. I have written a loading animation used elsewhere in my site, but in those cases the view ends with a redirect. I also can reveal a modal with javascript. However, a modal or animation will not automatically close when the "Open Liked Songs.csv" window pops up asking the user to "Open" or "Save", nor after one of those is selected (i.e., when the download view is completed).
Is there a way to trigger an event in the Browser Object Model using the window object for the "Open Liked Songs.csv" pop-up window? I do not know how to identify that specific window. Any other suggestions?
UPDATE:
Thanks to #v25 I realize more details are needed. Here is my code again:
#bp.route('/download', methods=['GET'])
#login_required
def download(backup=False):
...
if backup: # For download of 'Liked Songs'
playlist_id = '000library'
file_name = 'Liked Songs.csv'
url = get_endpoint("get-user-saved-tracks")
query_limit = 50
count = 0
tracks = []
# The Spotify endpoint is limited at maximum of 50
# so I need to iterate with offsets.
# I think this is what is causing the delay.
while not len(tracks) % query_limit:
params["limit"] = query_limit
params["offset"] = query_limit * count
section = sh.get_playlist_tracks(header, url, **params)
tracks += section["items"]
count += 1
if not tracks:
flash("Something went wrong. We couldn't get your playlist.")
return redirect(url_for('routes.profile'))
with NamedTemporaryFile(
mode='w+t',
encoding='utf8',
newline='',
prefix=playlist_id + '.',
dir=temp_dir,
delete=False,
) as csvfile:
...
# Writes csv file to temp directory
...
return send_from_directory(
temp_dir,
target[0],
as_attachment=True,
attachment_filename=file_name
)
When I monitor this process with my browser's (FireFox) dev tools 'Network' tab, I can see that it takes a while before status code 200 is returned for my '/download' request. At that point the 'Open Liked Songs.csv' window appears. I think I need some way to trigger my javascript closeModal() when status 200 is returned (polling?). As #v25 suggests below, I am pretty sure it is the iteration of 50-track chunks at the Spotify API that is slowing this down.
I was able to accomplish my goal by setting a client-side cookie when the download is complete. I used the flask.Response.set_cookie method:
def download():
# Code interacting with Spotify API
# Code writing API response to csv file
resp = make_response(send_from_directory(
temp_dir,
target_file,
as_attachment=True,
attachment_filename=file_name
))
resp.set_cookie(
'download',
value=cookie_val,
samesite='Strict'
)
return resp
I use javascript to check for the presence of that cookie at intervals, and to close the relevant modal when the cookie is found:
function closeModal(element) {
element.className += " hidden";
}
function showModalProc() {
showModal("processing");
document.getElementById("processing").scrollIntoView();
}
/* Borrowed getCookie(cname) from
https://www.w3schools.com/js/js_cookies.asp */
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
setInterval(checkCookie, 1000); // Checks for cookie every second.
function checkCookie() {
let cookie = getCookie("download");
element = document.getElementById("processing");
if (cookie != "" && cookie.startsWith("{{ session.user.id }}")) {
closeModal(element);
// Clear this cookie; set SameSite=Strict to avoid browser warning.
document.cookie = "download=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict;";
}
}
Basically i want to have an update content of the web,
https://www.investing.com/indices/indices-futures
In Dow 30, the last value is updating itself(real-time update from Investing.com server) and i would like to know is there any method to capture the change of values without requesting the website again, so that i can update on my code asynchronously. Since all i found online about being notified on change is based on their own html, but in my case it is external url, so i am asking here to gain some insight
You can add some code into the chrome console and track this value every second to notify you.
let last_value = -1
let class_selector = 'pid-8873-last'
setInterval(function() {
let v = document.getElementsByClassName(class_selector)[0].innerText
if (v != last_value) {
console.log("Value as been updated to " + v)
last_value = v
}
}, 1000)
> Value as been updated to 25,799.5
> Value as been updated to 25,798.5
But you must have a browser open, and create an ajax request when value is updated.
If you don't want any Browser, but be run into a server, you can check PhantomJS
EDIT WITH PHANTOMJS
They're some update to do to work with PhantomJS.
You need to replace let by var
document isn't accessible, so you need to use evaluate
https may require to add --ssl-protocol=any
./test.js
var page = require('webpage').create();
page.open('https://www.investing.com/indices/indices-futures', function(status) {
var last_value = -1
setInterval(function() {
var value = page.evaluate(function() {
return document.getElementsByClassName('pid-8873-last')[0].innerText
})
if (value != last_value) {
console.log("Value as been updated to " + value)
last_value = value
}
}, 1000)
// phantom.exit()
})
Then run it from the same directory:
# phantomjs test.js
Value as been updated to 25,799.0
I think you need to check what is websocket. this would be cool start; https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
How can I set the badge number on a specific tab only? So far I have a code that sets the badge number on all the tabs.. I've been reading around A LOT, but there doesn't seem to be a whole lot of information about this, so perhaps I will find a solution for this here.
I would like something like Adblock Plus, which sets the badge number for a specific tab. This is pretty easy in Chrome etc, but doesn't seem to be the case in Safari.
Does anyone know how extensions like Adblock plus shows the badge number on a specific tab?
So far I only have this code, but as mentioned, it sets the badge on all the tabs, which is not the result I want.
safari.extension.toolbarItems[0].badge = 2;
Edit:
I have been looking at the source code of Adblock plus, and a few other extensions that had this function. And it seems it is using some prototype.
Adblock plus background snippet:
BrowserAction.prototype = {
_set: function(name, value)
{
var toolbarItem = getToolbarItemForWindow(this._page._tab.browserWindow);
if (!toolbarItem)
{
return;
}
var property = toolbarItemProperties[name];
if (!property)
{
property = toolbarItemProperties[name] = {
pages: new ext.PageMap(),
global: toolbarItem[name]
};
}
property.pages.set(this._page, value);
if (isPageActive(this._page))
{
toolbarItem[name] = value;
}
},
setIcon: function(path)
{
this._set("image", safari.extension.baseURI + path.replace("$size", "16"));
},
setBadge: function(badge)
{
if (!badge)
{
this._set("badge", 0);
}
else if ("number" in badge)
{
this._set("badge", badge.number);
}
}
};
Content script (adblockplus.js)
FilterNotifier.on("filter.hitCount", function(filter, newValue, oldValue, page)
{
if (!(filter instanceof BlockingFilter) || !page)
{
return;
}
Prefs.blocked_total++;
var blocked = blockedPerPage.get(page) || 0;
blockedPerPage.set(page, ++blocked);
if (Prefs.show_statsinicon)
{
page.browserAction.setBadge(
{
color: badgeColor,
number: blocked
});
}
});
It seems this is how Adblock plus does it, but so far I haven't been able to replicate it. Still trying though..
Okay, so I finally found a solution for this, and thought I would share what I did, in case somebody else is in the same situation.
This morning I got the idea of storing the data in an array, when the user visits one of the websites I want to display the badge number on (doesn't store all websites the user visits), only if it matched one of the websites I wanted to target. I stored the following data in the array: root domain (example.com) and the badgeNumber.
For this to work, you need to make an array of the root domain of the websites you want to target, and then only execute the following when it matches, otherwise the array would fill up very quickly, and we don't want too much data in it.
In the global page, start by making an empty array to store the data
var badgeUpdateArray = [];
You then need to set up message handling in your global page as well.
safari.application.addEventListener('message', handleMessage, false);
function handleMessage(event) {
if(event.name === "setBadgeText"){
var id = badgeUpdateArray.length + 1;
var isFound = 0;
var found = badgeUpdateArray.some(function (el) {
if(el.identifier === event.message.identifier){
// Was found
isFound = 1;
}
});
if (isFound == 0) {
// Not found, add to the array
badgeUpdateArray.push({identifier:event.message.identifier,badgeNumber:event.message.badgeNumber});
}
// Set the badge number
safari.extension.toolbarItems[0].badge = event.message.badgeNumber;
}
}
Now we need to send the message from the content script to the global page. You need to get the root domain (example.com), I'm not getting into that here, as it's pretty easy. You will also need the badgeNumber value, this can be gathered from wherever (GET request, or elsewhere..)
Remember, only execute this code if the website matches your target domains.
var message = {
identifier: domain,
badgeNumber: rows.length
}
safari.self.tab.dispatchMessage("setBadgeText", message);
This will send the message, and store the data in the array, it will also set the badge number.
Now, for this to be working on different tabs, you will need to make an event handler for "activate" on the global page, this will run whenever a tab is active.
safari.application.addEventListener("activate", updateBadge, true);
function updateBadge(){
var cDomain = safari.application.activeBrowserWindow.activeTab.url;
cDomain = cDomain.replace("www3.","");
cDomain = cDomain.replace("www2.","");
cDomain = cDomain.replace("www1.","");
cDomain = cDomain.replace("www.","");
cDomain = new URL(cDomain);
cDomain = cDomain.hostname;
var id = badgeUpdateArray.length + 1;
var isFound = 0;
var badgeNumber = 0;
var found = badgeUpdateArray.some(function (el) {
badgeNumber = el.badgeNumber;
if(el.identifier === cDomain){
// Was found, set the badge number
isFound = 1;
safari.extension.toolbarItems[0].badge = el.badgeNumber;
}
});
if (isFound == 0) {
// Was not found
safari.extension.toolbarItems[0].badge = 0;
}
}
Hopefully I've got it all in here, and at least something that works, though I have to say that I would prefer an easier way of storing it.. like Chrome etc does it, with the tab API.
John Giotta kindly gave me this code earlier (on stack overflow) in order to implement a "turn off styles" button on my website (for a university assignment).
function nostyle() {
for (i=0; i<document.styleSheets.length; i++) {
void(document.styleSheets.item(i).disabled=true);
}
}
I was wondering how easy it would be to implement a cookie to remember that this javascript has been applied so that every page navigated after on the site has styles turned off (My knowledge is extremely basic, I am only a first year).
Regards
function SetCookie(cookieName,cookieValue,nDays) {
var today = new Date();
var expire = new Date();
if (nDays==null || nDays==0) nDays=1;
expire.setTime(today.getTime() + 3600000*24*nDays);
document.cookie = cookieName+"="+escape(cookieValue)
+ ";expires="+expire.toGMTString();
}
Set your css_disabled cookie
SetCookie('css_disabled', 'true', 100);
To read the cookie:
function ReadCookie(cookieName) {
var theCookie=""+document.cookie;
var ind=theCookie.indexOf(cookieName+"=");
if (ind==-1 || cookieName=="") return "";
var ind1=theCookie.indexOf(";",ind);
if (ind1==-1) ind1=theCookie.length;
return unescape(theCookie.substring(ind+cookieName.length+1,ind1));
}
if (ReadCookie('css_disabled') == 'true') {...
Example:
In the main page cliked on a button (NEW), the
page then will using Javascript to
open a new page in a new window by
calling redirectPage().
In the main page clicked on a button (EXIT),
then page then will call
confirmExit(), then
closeChildWindows() to closed all
popup new window before redirect to
another new page.
However, the JS variable
(childWindowHandles) will be always
reset if I refresh the main page,
and this cause the page unable to
close all other popup window before
relocated while EXIT button being
clicked
Does anyone know how can I solve this problem? By able to keep the JS variable (childWindowHandles) even the main page being refresh?
var childWindowHandles = new Array();
function redirectPage(url)
{
childWindowHandles[childWindowHandles.length] = window.open(url)
}
function confirmExit(url)
{
closeChildWindows()
window.location=url
}
function closeChildWindows()
{
for (var loop=0; loop<childWindowHandles.length; loop++)
{
if (!childWindowHandles[loop].closed)
{
childWindowHandles[loop].close();
}
}
}
You can use cookies to persist values...
Edit: You might find useful a simple object that I use:
Usage:
// Store a key/value for 1 day:
cookieManager.set('name', 'a value', 1);
// Retrieve a value associated to a key:
var value = cookieManager.get('name');
// Remove a key/value:
cookieManager.remove('name');
Implementation:
var cookieManager = {
set: function (name, value, expireDays) {
var expireDate = new Date();
expireDate.setDate(expireDate.getDate() + expireDays);
document.cookie = name + "=" + escape(value) +
((!expireDays) ? "" : ";expires="+expireDate.toGMTString());
},
get: function (key) {
var start,end;
if (document.cookie.length > 0) {
start = document.cookie.indexOf(key + "=");
if (start != -1) {
start = start + key.length + 1;
end = document.cookie.indexOf(";",start);
if (end == -1) {
end = document.cookie.length;
}
return unescape(document.cookie.substring(start,end));
}
}
return "";
},
remove: function (key) {
this.set(key, '', -1);
}
}
You can use cookies or window.name:) window.name to store session variables
Per this post here on SO, Firefox 3.5, Safari 4, and IE8 support HTML5 Storage.
Or use PersistJS which simplifies your access to whichever back-end storage mechanisms are available. (But cookie-less)
Use window.name
Positives:
it will live for the time of browser session - user closes window and it's gone
it won't put additional traffic on the wire like cookies do
it works even when cookies are disabled
at least 2MB space (Opera's limit is this low, other's have 32/64MB)
I also suggest you use javascript object for storing various values and serialize it using JSON and put that string into window.name.
Just make sure you don't persist any vulnerable data inside... For security reasons.
You can use sessionStorage.
Check this out:
html5_webstorage