There was a task to make each web page of the project not repetitive. Those. the user should not, as a consequence of inattention within the same browser, open multiple duplicates of the same web page. Please suggest a specific solution.
The task can be solved very simply, if one condition is met — each page has its own unique identifier. I have this $(‘body’).attr (‘id’).
Let’s call the function noDuplicateTabs and call it every time the page starts.
We use localStorage:
let noDuplicateTabs = function (pageName) {
localStorage.getItem(pageName)
? window.close()
: localStorage.setItem(pageName, 'open');
window.onbeforeunload = function () {
localStorage.setItem(pageName, '');
};
}
Thus, we pass the name of the page in the function, check for the presence of a value using the localStorage key corresponding to the page name.
If a key with a non-empty value is found, then we close the page, if not, then write the value to it ‘open’.
We also use the onbeforeunload property of the window, which works before reloading or closing the page. In this case, we will erase the value.
Now there will be no duplicates within the same browser.
Related
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
I use a few state variables to determine which sites should be opened in new tabs (or maybe a new window if tabs aren't possible) with a single button click. However, window.open() only opens the first link.
In this code I tried pushing the target sites to an array and running .forEach and .map on the array items.
open_selected_websites() {
const sites_to_open = [];
// check each property for true and array.push if so
this.final_social_media_site_selections.facebook && sites_to_open.push('http://facebook.com');
this.final_social_media_site_selections.twitter && sites_to_open.push('http://twitter.com');
this.final_social_media_site_selections.linkedin && sites_to_open.push('http://linkedin.com');
this.final_social_media_site_selections.instagram && sites_to_open.push('http://instagram.com');
this.final_social_media_site_selections.pinterest && sites_to_open.push('http://pinterest.com');
console.log(sites_to_open); // all observables are true and all sites appear in the array.
sites_to_open.forEach((social_media_site) => {
// setTimeout(() => {
window.open(social_media_site);
// }, 500)
})
In both cases, facebook loaded in a new tab. It is the first array item.
Then I tried adding a setTimeout to see if some time space might affect things. No, still only Facebook.
Then I tried testing only one site in each function:
<Button
size='huge'
color='orange'
onClick={ () => {
// final_edits_store.open_selected_websites();
final_edits_store.test_to_open_twitter();
final_edits_store.test_to_open_facebook();
} }
>
Copy Text and Open Social Media Sites in New Tabs
</Button>
In this case Twitter opened. The twitter function was listed first.
Does anyone know what is causing window.open() not to fire multiple times? And how to overcome this limit?
You can't.
Browsers only allow a single window to be triggered from a given user interaction.
This is a security feature to prevent websites bombing the user with vast numbers of new windows.
jsFiddle here - https://jsfiddle.net/523bLxf4/12/
Try the name parameter that window.open takes. I was able to open multiple windows.
Instead of window.open(social_media_site); try window.open(social_media_site, social_media_site);
In the name parameter use some tag that uniquely identifies the window.
I have a function named back() which will be used for ajax calls. Actually I have an array stack contains last 5 search results and that back function will switch to the previous result set (according to that array stack) and it even changes the URL using window.history.pushState() when you click on the back button.
That back button I was talking about, is an element inside the browser which revokes back() function. Now I want to revoke back() function also when user click on the back button of the browser. Something like this:
window.onhashchange = function() {
back(); // this function also changes the url
}
But sadly window.onhashchange will be revokes twice when I click on the back of the browser. Because window.onhashchange will be revoked when you change the URL using window.history.pushState().
Anyway, how can I detect what things changes the URL? Either my JS code or the back button of the browser?
You can use performance.navigation.type
At any given point, for example on document.onload, you can read the value of type and, if it's:
0 The page was accessed by following a link, a bookmark, a form submission, a script, or typing the URL in the address bar.
1 The page was accessed by clicking the Reload button or via the Location.reload() method.
2 The page was accessed by navigating into the history.
255 any other way.
Just beware that support is limited according to the compatibilty table.
However, from the looks of it, it seems the table is outdated. It says it is not supported on chrome and I just tested it and works as expected on my chrome version (67.0)
One of solution is to implement onunload event with localstorage option.
This is from my head maybe you will need correction but this is base !
var history = [];
window.onload = function(){
var handler;
if ( localStorage.getItem('history') == null ) {
// FIRST TIME
history[0] = window.location.href;
localStorage.setItem("history", JSON.stringify(history));
}
else {
handler = localStorage.getItem('history');
handler = JSON.parse(handler);
history = handler;
// Just compare now
if (history[history.length-1] == window.location.href) {
// no change
} else {
history.push(window.location.href);
}
}
}
window.onunload = function(){
localStorage.setItem('history', JSON.stringify(history));
}
Note :
Since 25 May 2011, the HTML5 specification states that calls to
window.alert(), window.confirm(), and window.prompt() methods may be
ignored during this event. See the HTML5 specification for more
details.
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
I have a website where each pages need to check if user close the browser, in this case I run some code (releaseLocking).
So on these pages I have implemented this code:
$(window).on('beforeunload', function () {
return "Are you sure you wanna quit ?";
});
$(window).unload(function () {
releaseLocking();
});
It works but I noticed that if I navigate to multiple pages where this code is implemented, when closing the browser, I'll have multiple call to releaseLocking (for each previously visited pages).
I would prefer only run this code for the last page really active. Do you see what I mean?
Do you have any idea how to proceed?
Thanks.
I suggest using localStorage for this. Since localStorage stores variables per domain, it will allow you to check if the code was already executed. Localstorage is also bound to the session, so after the browser is fully closed, your session is gone, causing the localStorage to be cleared so it wont interfere with the next session.
$(window).on('beforeunload', function () {
return "Are you sure you wanna quit ?";
});
$(window).unload(function () {
if ( !localStorage.getItem('lockReleased') ) {
releaseLocking();
localStorage.setItem('lockReleased', true)
}
});
The code above will set localStorage variable lockReleased to true for the first window that closes. The other windows will see the value, and won't call releaseLocking.
In my knowledge it is impossible to detect a browser close separately
from a browser navigation. the browser does not provide the
window with that information.
SEE HERE ALSO
I am not sure this is the only way to do it(neither the best), anyway you should be able to save a sort of session of the user and ask everytime to the server if the page is the last opened.
//the var declaration goes at the beginning of the script
var isLastPage = false;
$(window).on('beforeunload', function () {
//ajax request, the callback will set isLastPage to true if it is the last page opened by the user with that session.
});
$(window).unload(function () {
if(isLastPage) releaseLocking();
});
Server side you should create a session wich stores all the pages of the user(remember to update it via JS when the user closes a page or opens a new one). I think that only via JS is not possible to do it, you need to be helped by the server.