We use an internal system (with FF as default browser)
We need to avoid that the user open the same URL in different tabs.
As the tabs share the same PHP session we get a mess.
So actually I'm looking to the way to check programmatically if certain URL is already opened in one of the opened tabs.
Client side (JS) or server side (PHP).
We use now the FF extension "Duplicate Tabs Closer" that helps.
But I'd prefer to keep full control (give warning, choose for which URL it works).
You can write cookie after your page loaded in the first tab, check it on the server side and show the user warning instead of actual page content if this cookie is set and the second tab is opened. To handle the case when a user closes the only opened tab you can remove that cookie in onbeforeunload handler.
Working off of Oleksandr's answer, you can store a map of number of times a url is opened, in a cookie. When a page is opened, increment the number or set it to 0. When a page is closed, decrement it or delete it.
function incrementTabsOpen() {
let tabsOpen = readObjCookie('tabsOpen') || {};
if (tabsOpen[window.location.href]) tabsOpen[window.location.href]++;
else tabsOpen[window.location.href] = 0;
writeObjCookie('tabsOpen', tabsOpen);
}
function decrementTabsOpen() {
let tabsOpen = readObjCookie('tabsOpen') || {};
if (tabsOpen[window.location.href]) tabsOpen[window.location.href]--;
if (tabsOpen[window.location.href] === 0) delete tabsOpen[window.location.href];
writeObjCookie('tabsOpen', tabsOpen);
}
// https://stackoverflow.com/a/11344672/3783155
function readObjCookie(name) {
let result = document.cookie.match(new RegExp(name + '=([^;]+)'));
if (result) result = JSON.parse(result[1]);
return result;
}
function writeObjCookie(name, value) {
document.cookie = name + '=' + JSON.stringify(value);
}
and
window.addEventListener('load', function() {
incrementTabsOpen();
};
window.addEventListener('unload', function() {
decrementTabsOpen();
};
Related
So I am trying to make a back button using onclick="history.back()". But the thing is when I enter my website using an external link, and press the back button, it takes me back to the previous page which is external. I know that it has been programmed to do so. But is there any way to prevent it from taking users back to the external website?
One way would be to store in the sessionStorage the history.length value that you received when first visiting the page.
Then you will store the current index in the history.state. Once you reach back the initial index, you'd prevent the history to go back.
// To be executed on all the pages of your domain
// check if we already saved it
let min_index = sessionStorage.getItem("minHistoryIndex");
// otherwise
if (min_index === null) {
// store it
min_index = history.length;
sessionStorage.setItem("minHistoryIndex", min_index);
}
// first time we come to this history status
if (!history.state ) {
history.replaceState({ index: history.length }, "");
}
const button = document.querySelector("button");
// if we reached the limit saved in sessionStorage
if (history.state.index === +min_index) {
button.disabled = true;
button.title = "Going back once more would take you out of our website";
}
else {
button.onclick = (evt) => history.back();
}
Live demo - source
One problem with this is that if your user decides to go to an other origin from your page and then go back to it manually, you could go back to that external domain, but I guess it's such a corner case that it can be accepted in most cases.
I am trying to track Facebook ad results using the Facebook Pixel during appropriate events (page views, lead generation, order form view, purchase). I can do all of this for GA using GTM with no problem, but on Facebook I only have partial success.
The main issue is I have a cross domain setup as shown below:
domain1.com/offer - landing page (FB Page View Pixel should fire)
domain1.com/ordergate - request email before showing order form page (FB Page View Pixel should fire)
crm.com/formsubmission - the actual form submits to my crm (FB Lead Pixel should fire)
crm.com/orderform - order form (FB order form view pixel should fire)
domain1.com/thankyou - the thank you page (FB order pixel should fire)
So my trigger on GTM to fire FB pixel was the "referrer" containing "facebook". However, because of the multi-step process, the referrer is lost by the time the order form or sale is completed.
I have since then learned I need to do the following:
User lands from facebook, write cookie with an appropriately short expiration time that stores this information on domaiin1.com.
When the user clicks a link and is redirected to crm.com, check if the user has the cookie, and if they do, add something like ?reffacebook=true to the redirect URL.
On crm.com, if the URL has ?reffacebook=true write the same cookie you wrote on (1) with an equally short expiration time.
UPDATE
So I have figured out step 2 using the following script on page view when the Facebook cookie is set:
function updateLinks(parameter, value)
{
var links = document.getElementsByTagName('a');
var includeDomains = self.location.host;
for (var i=0;i<links.length;i++)
{
if(links[i].href != "#" && links[i].href != "/" && links[i].href != "" && links[i].href != window.location) //Ignore links with empty src attribute, linking to site root, or anchor tags (#)
{
var updateLink = true;
if(links[i].href.toLowerCase().indexOf(includeDomains.toLowerCase()) != -1) //Domain of current link is included i the includeDomains array. Update Required...
{
updateLink = false;
}
if(!updateLink)
{
//Do nothing - link is internal
}
else
{
var queryStringComplete = "";
var paramCount = 0;
var linkParts = links[i].href.split("?");
if(linkParts.length > 1) // Has Query String Params
{
queryStringComplete = "?";
var fullQString = linkParts[1];
var paramArray = fullQString.split("&");
var found = false;
for (j=0;j<paramArray.length;j++)
{
var currentParameter = paramArray[j].split("=");
if(paramCount > 0)
queryStringComplete = queryStringComplete + "&";
if(currentParameter[0] == parameter) //Parameter exists in url, refresh value
{
queryStringComplete = queryStringComplete + parameter + "=" + value;
found = true;
}
else
{
queryStringComplete = queryStringComplete + paramArray[j]; //Not related parameter - re-include in url
}
paramCount++;
}
if(!found) //Add new param to end of query string
queryStringComplete = queryStringComplete + "&" + parameter + "=" + value;
}
else
{
queryStringComplete = "?" + parameter + "=" + value;
}
links[i].href = links[i].href.split("?")[0] + queryStringComplete;
}
}
else
{
//Do nothing
}
}
}
So with this code I can now properly attribute people with the facebook referral across domains...
...but I still have a problem with form submits.
So when the contact gets to step 4, it is a redirect from the form submission. It does not carry any cookie or query string, so neither of the FB pixels (order form view or order) is being fired.
I'm not sure how I would handle this. My first thought is to pass a hidden field into the form submission (say reffacebook=true). Then somehow expose that in the url in a form of a query string so that it can be detected by GTM.
This seems to be somewhat complicated though, as I would have to edit all my forms to have this variable, edit my CRM so it knows to receive it, and then edit the form landing page to expose that variable in the url.
Hey I hope that I understood what is this all about. Here you want to track traffic between cross domains right? I am not into any coding or anything like that to achieve such a tracking. Because I don't know any coding seriously (I apologies my self for not even trying to learn. I realize my self is that knowing Java script have a lot of benefits in advanced marketing). Ok Here is my point. If we want to track traffic between domains and retarget them later, wouldn't it be done by Facebook itself just by using the same pixel in both domains? This is what I used to believe in the case of multiple domains while doing Facebook ads. Here the important Thing is the audience should be the same from domain A to domain B (In your case it looks like yes the audience is same there for there is no issue for doing that I think). But not sure whether Facebook will track the traffic between domains successfully or not just by placing same FB Pixel in both domains.
Thank you.
#SalihKp, I think you have a point however the issue is that i believe facebook does cross domain with third party cookies which are not working optimally now adays
#David Avellan actually since the user returns to the landing domain for the thank you page, then the final conversion should work using 1st party cookies, but what you want in between might be an issue.
i am looking at now a case where they user lands on a.com and convert
There is a popup window that submits its form to a third party url on load.
The user selects his address using the third party service.
When the user clicks on the finish button of the third party service, the third party service redirects the user back to my original popup url.
The source code of the popup.jsp looks like this.
<%
String inputYn = request.getParameter("inputYn");
String roadFullAddr = request.getParameter("roadFullAddr");
String roadAddrPart1 = request.getParameter("roadAddrPart1");
String roadAddrPart2 = request.getParameter("roadAddrPart2");
String engAddr = request.getParameter("engAddr");
String jibunAddr = request.getParameter("jibunAddr");
String zipNo = request.getParameter("zipNo");
String addrDetail = request.getParameter("addrDetail");
String admCd = request.getParameter("admCd");
String rnMgtSn = request.getParameter("rnMgtSn");
String bdMgtSn = request.getParameter("bdMgtSn");
%>
function init(){
var url = location.href;
var confmKey = "serviceKeyIssuedBytheThirdParty";
var inputYn= "<%=inputYn%>";
if(inputYn != "Y"){
document.form.confmKey.value = confmKey;
document.form.returnUrl.value = url;
document.form.action="http://www.somethirdpartyservice.do";
document.form.submit();
}else{
try {
opener.jusoCallBack("<%=roadFullAddr%>","<%=roadAddrPart1%>","<%=addrDetail%>","<%=roadAddrPart2%>","<%=engAddr%>","<%=jibunAddr%>","<%=zipNo%>", "<%=admCd%>", "<%=rnMgtSn%>", "<%=bdMgtSn%>");
} catch (err) {
alert(err.description || err) //or console.log or however you debug
}
window.close();
}
}
The javascript jusoCallBack function on the parent page.
function jusoCallBack(roadFullAddr,roadAddrPart1,addrDetail,roadAddrPart2,engAddr, jibunAddr, zipNo, admCd, rnMgtSn, bdMgtSn){
console.log("jusoCallBack");
document.form.newAddress.value += roadFullAddr;
}
The problem is that it works just fine on Google Chrome but I get an error that says Unable to get property 'jusoCallBack' of undefiend or null reference.
I experimented so that the function jusoCallBack will be fired on the first popup window load, before it submits the form to the third party URL.
The popup window finds its opener just fine and the function jusoCallBack is fired.
It seems to me that, for some reason, the popup window loses the opener information after it had navigated to a third party URL.
But it works just fine on Google Chrome though. So I'm not so sure.
Is the popup window supposed to remember who the opener is even after the popup windows had navigated out to a different URL or is it normal for the popup window to lose its opener?
I want to prevent users to navigate to URLĀ“s that are not accessed through html element. Example:
Actually navigating on: myweb.com/news
And I want to navigate to myweb.com/news?article_id=10 by writing this in the browser navigation bar to avoid pressing any element (like <a>).
When the user writes myweb.com/news?article_id=10 in the browser url, at the moment he presses enter, the browser should not allow him to navigate to the url.
I have tried:
//This wont work since jquery does not support it
$(window.location.href).on('change', function() {
//Here check if href contains '?'
alert("Not allowed");
});
//Neither works, doesnt do anything
$(window).on('change', function() {
alert("Not allowed");
});
References:
there is something similar asked here On - window.location.hash - Change?, but im interested in the 'parameter' version of that question.
There are some known solutions :
) Each time a user click a link - you save the page value to a cookie.
Later , at the server- you check that interval ( value-1 ... value+1).
) You can also save to a hidden field and check that value in the server.
So let's say a user is on page 3. ( the server serve that page - so a cookie/hidden value with value 3 is exists)
now he tries to go to page 10 :
you - in the server side - reads the cookie + requested Page number. if the interval is bigger than 1 - then you deny that request.
Try adding an event listener:
window.addEventListener('popstate', function(event)
{
var location = document.location;
var state = JSON.stringify(event.state);
});
To check the URL, The best thing would be to match it against a regex like:
if (url.match(/\?./)) {
// do not allow access
}
You might need to extend this, depending on other URL's that you need to forbid access to.
I would like to detect if user has open more than one window or tab on the same session and if he did it - I would like to print an special information on screen.
This limte should oblige only in one special URL, so if user has open two tabs/windows with urls: http://page.com/limite.htm - I would like to print special information. When user has open two windows/tabs with urls: http://page.com/limite.htm and http://page.com/index.htm - everything is OK and I wouldn't show any informations.
Is it possible?
Thanks.
I think the best way to do it is with localStorage. http://www.gwtproject.org/doc/latest/DevGuideHtml5Storage.html
From the link, about localStorage:
Availability to other Windows/tabs: Shared across every window and tab of one browser running same web app
So, you could set an entry when the tab/window is open, and change it when it's closed. When another tab/window is open, you first check this entry value.
Obviously you need to be careful: browser crashes, for example, might not trigger the "on close" part, so the user wouldn't be able to open a new tab, even with none open (localStorage persists!). If you have server sessions, you can ask the user to login again (or run your auth process again), and reset this value. You can also try to use a sessionStorage entry to keep track of this kind of problem. From the link, about sessionStorage:
Persistence: Survives only as long as its originating window or tab.
Also, there is something called "Cross window messaging", that allow you communicate between tabs, but check if it's supported on the browsers you want to support.
http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage
I have done something very similar today. I hope this helps.
// helper function to set cookies
function setCookie(cname, cvalue, seconds) {
var d = new Date();
d.setTime(d.getTime() + (seconds * 1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
// helper function to get a cookie
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
// Do not allow multiple call center tabs
if (~window.location.hash.indexOf('#admin/callcenter')) {
$(window).on('beforeunload onbeforeunload', function(){
document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
});
function validateCallCenterTab() {
var win_id_cookie_duration = 10; // in seconds
if (!window.name) {
window.name = Math.random().toString();
}
if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) {
// This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity.
setCookie('ic_window_id', window.name, win_id_cookie_duration);
} else if (getCookie('ic_window_id') !== window.name) {
// this means another browser tab is open, alert them to close the tabs until there is only one remaining
var message = 'You cannot have this website open in multiple tabs. ' +
'Please close them until there is only one remaining. Thanks!';
$('html').html(message);
clearInterval(callCenterInterval);
throw 'Multiple call center tabs error. Program terminating.';
}
}
callCenterInterval = setInterval(validateCallCenterTab, 3000);
}
LocalStorage won't work across protocols - so if the user has your site open in one tab using http, and another tab using https, both those tabs will see separate localStorage objects. Cookies don't have the same issue (they have other issues, e.g. inflating the size of every http request back to your website)
The sample code below maintains a map where the key is a unique browser tab identifier and the value is a timestamp indicating when that tab last confirmed it was still open. The map is stored in a cookie. Its not a perfect approach - each tab updates itself every 3 seconds rather than instantly, and there are race conditions (multiple tabs updating the same cookie) but depending what you're after this may do the trick.
If you ran this code on just a specific page you'd (more or less) know when that page was open more than once in the same browser. Or run it on every page of your website and know when your website was open in multiple tabs.
Cookie reading/writing code is omitted for brevity (but taken from https://stackoverflow.com/a/24103596/4486628), and the encoding of the data in the cookie is done with json for simplicity, but you get the idea.
If you run this code and watch the cookies using FireBug's cookie tab you can see the cookie updating as tabs are opened and closed. Actually doing something like alerting the user when multiple tabs are open is left as an exercise for the reader.
var timePeriod = 3000; // 3 seconds
function tabHandler() {
// ensure the current window has an identifier set
if (!window.name.match(/^MySite[0-9]{3}/)) {
window.name = 'MySite' + Math.round(Math.random() * 1000);
}
// read in the state of all the tabs
var tabCookie = readCookie('tabs') || null;
var tabs = JSON.parse(tabCookie) || {};
// update the timestamp for the current tab
var now = (new Date()).getTime();
tabs[window.name] = now;
// remove tab details that haven't had their timestamp updated
var tooOld = timePeriod * 2;
for (var tabKey in tabs) {
if ((now - tabs[tabKey]) > tooOld) {
delete tabs[tabKey];
}
}
// write back the current state of tabs
createCookie('tabs', JSON.stringify(tabs), 1);
setTimeout(tabHandler, timePeriod);
}
setTimeout(tabHandler, timePeriod);