I need to prevent a user from downloading a file (PDF) until they have entered some simple details into a form. We need to capture the details so that we can see who is downloading the file.
See a jsFiddle here http://jsfiddle.net/ctn7N/1/
The steps I need it to follow are:
User opens page. If they have already filled out the capture form, store that state in a variable.
They click a download link. Store the link so that it can be used later.
If they've already entered details, i.e. check the variable, open the link in a new tab as normal (default behaviour).
If they haven't entered details, show the capture form.
Once they click submit on the form, show the downloads section again, store the state and open the original download that they clicked on in a new tab.
On subsequent loads of the page they should not have to enter their details again and downloads should just open.
The current code I'm using fails at the last part of step 5, when it tries to open the download link in a new tab. Although it works in the fiddle, it breaks in Chrome v35.0 because the link is blocked by a popup blocker.
Is there any way around this that would allow it to open in all browsers?
Thanks for looking,
Adam
Code to accompany fiddle:
HTML Code
<div id="capture-section" class="hide">
<form id="capture-form">
<label for="name">Enter your name to download the file:</label>
<input id="name" name="name" type="text" />
<button id="submit-btn" type="submit">Submit</button>
</form>
</div>
<div id="download-section">
<!-- Download links replaced with placeholder links for jsFiddle, would normally be PDFs -->
<a target="_blank" class="js-download" href="http://example.com">Document 1</a>
<a target="_blank" class="js-download" href="http://www.google.com">Document 2</a>
<a target="_blank" class="js-download" href="http://www.bing.com">Document 3</a>
</div>
JavaScript
$(document).ready(function() {
var detailsEntered = '',
downloadLink = '';
// Would normally access localStorage on load of page to see if user has already entered details
// Removed to allow multiple jsFiddle runs for a user
//
// detailsEntered = accessStorage('retrieve', 'detailsEntered');
$('.js-download').click(function(event) {
var self = $(this);
downloadLink = self.attr('href'); // Store clicked download link
if (detailsEntered != 'true') {
// If the user hasn't entered details yet, show the form
$('#download-section').addClass('hide');
$('#capture-section').removeClass('hide');
event.preventDefault();
return false;
} // Otherwise allow standard link behviour
});
$("#submit-btn").click(function(event) {
var name = $('input[name=name]').val(),
proceed = true;
if(name==""){
$('input[name=name]').addClass("error");
proceed = false;
}
if(proceed) {
// If form validates, show downloads again and store value for return visits
$('#capture-form input').val('');
$('#capture-section').addClass('hide');
$('#download-section').removeClass('hide');
detailsEntered = 'true';
accessStorage('store', 'detailsEntered', 'true');
// Now open previously clicked download link in new tab
// DOES NOT WORK - Blocked by popup blocker
window.open(downloadLink, '_blank');
}
event.preventDefault();
return false;
});
//reset previously set border colors and hide all message on .keyup()
$("input, textarea").keyup(function() {
$(this).removeClass("error");
});
function accessStorage(action, dataKey, dataValue) {
if(typeof(Storage) === "undefined") {
// No support for localStorage/sessionStorage.
return false;
}
if (action == 'store') {
localStorage.setItem(dataKey, dataValue);
} else if (action == 'retrieve') {
return localStorage.getItem(dataKey);
}
}
});
A solution, if you don't need to open a new page, would be to simply change the location of the current page (means no popup issue) :
if(proceed) {
// If form validates, show downloads again and store value for return visits
$('#capture-form input').val('');
$('#capture-section').addClass('hide');
$('#download-section').removeClass('hide');
detailsEntered = 'true';
accessStorage('store', 'detailsEntered', 'true');
// Now open previously clicked download link in new tab
window.location.href = window.location.protocol + "//" + window.location.host + downloadLink; // if downloadLink is a relative URI
// window.location.href = downloadLink; // if downloadLink is an absolute URI
}
Related
Basically, on my 'notificationclick' event, I am trying to open the notifications URL. It works perfectly for normal URLs. But if the URL has an anchor tag (#), it will then just try to jump to the specified anchor (which doesn't exist yet.)
I can easily cut out the anchor part of the url, and that works for the base page, it will then refresh the page successfully, but it wont jump to the comment.
So i tried doing this:
if (cleanedClientUrl === cleanedUrl && 'focus' in client) {
//focus and reload the window that has this page open
client.focus();
//if the url had a # in it, first navigate to the cleaned url (otherwise it wont refresh)
if (url.indexOf('#'))
client.navigate(cleanedUrl);
client.navigate(url);
return;
}
Which I was hoping would first redirect it to the URL without the cleanedUrl (without the anchor), and then navigate to the original url, which include the anchor, to make it jump down. But it seems the second client.navigate cancels the first one.
Is there any way to wait until the first one is loaded, or tell the page to reload even if there's an anchor specified in the URL?
Here is my full code:
//user clicked / tapped a push notification
self.addEventListener('notificationclick', function(event) {
const clickedNotification = event.notification;
clickedNotification.close();
//exit if the url could not be found
if (!event.notification.data || !event.notification.data.url) return;
//get url from event
var url = event.notification.data.url;
//if the url contains a #, remove it and everything after it
var cleanedUrl = url.indexOf('#') ? url.substring(0, url.indexOf('#')) :url;
event.waitUntil(
self.clients.matchAll({type: 'window', includeUncontrolled: true}).then( windowClients => {
console.log('opening window', windowClients.length, 'windows')
// Check if there is already a window/tab open with the target URL
for (var i = 0; i < windowClients.length; i++) {
var client = windowClients[i];
//if the page url contains a #, remove it and everything after it
var cleanedClientUrl;
if (client.url.indexOf('#') !== -1)
cleanedClientUrl = client.url.substring(0, client.url.indexOf('#'));
else cleanedClientUrl = client.url;
// if the cleaned URLs match
if (cleanedClientUrl === cleanedUrl && 'focus' in client) {
//focus and reload the window that has this page open
client.focus();
//if the url had a # in it, first navigate to the cleaned url (otherwise it wont refresh)
if (url.indexOf('#'))
client.navigate(cleanedUrl);
client.navigate(url);
return;
}
}
// If not, then open the target URL in a new window/tab.
if (self.clients.openWindow) {
return self.clients.openWindow(url);
}
})
);
});
Could you quickly jump to the anchor and then immediately reload the page?
main JS thread
window.location = '#my-anchor-value';
window.location.reload();
ServiceWorker
if you need to chain navigation in a SW, you'll need to await the promise completion of the first navigate()
if (url.indexOf('#')) {
return client.navigate(cleanedUrl)
.then(() => client.navigate(url));
} else {
return client.navigate(url);
}
There goal is to prevent users from redirect on accidental clicks on external links, when user fills up the form.
Problem: the whole code has to be abstract. I don't know which links user clicks, I don't know whether the form is fully or partly filled.
If the form is empty, then redirect user without dialog/confirmation box.
Here's code:
function exit_confirm(event) {
let url;
if (event.target.nodeName === "a") {
url = event.target.getAttribute('href');
}
if (window.confirm('Do you want to leave the site?')) {
window.location.href = url;
}
}
function getAllElementsWithDataAttribute() {
return document.querySelectorAll('*[data-]');
}
function registerOnClickChangeKeydownEventsOfElementsWith() {
let elementsWithDataAttribute = getAllElementsWithDataAttribute();
['click', 'change', 'keydown'].forEach(evt => {
elementsWithDataAttribute.addEventListener(evt, exit_confirm, false);
});
}
The code is not a final version.
I have to get url from a clicked link and pass it to window.location.href
I also need to check a clicked link if it is an external link.
*[data-] - here has to be smthing that defines the link
I have used history.pushState() and now if the user refreshes the page then it is refreshing current URL which is not an original URL.
I tried detecting refresh page with a cookie, hidden filed but it is not working.
window.onload = function() {
document.cookie="PR=0";
var read_cookies = document.cookie;
var s = read_cookies;
s = s.substring(0, s.indexOf(';'));
if( s.includes("1"))
{
window.location.href = "https://www.google.com";
}
else{
document.cookie="PR=1";
}
loadURL();
};
function loadURL()
{
document.cookie="PR=1";
document.getElementById("visited").value="1";
var str="abc/b cd";
str=str.replace(/ /g, "-");
history.pushState({},"",str);
}
when user is refreshing the page I need original URL on that time.
This might be helpful. But you need control over the pushed url.
// this goes to your 'original' url
window.addEventListener('beforeunload', function (event) {
sessionStorage.setItem('lastPage', window.location.href)
}
// page with your pushed url
if (sessionStorage.getItem('lastPage') === 'PAGE_YOU_DONT_WANT_TO_BE_REACHABLE_DIRECTLY') {
window.location = 'PAGE_YOU_WANT'
}
I'm interested what the use case for this is. As far as my knowledge goes you can't suppress the refresh event completely.
So, I have an input in popup.html. If you enter data, popup.js sends the data to content.js and it already changes something on tab. But after updating tab changes on the tab is gone. How can you make it so that they would stay and change only if new data were entered into the input?
popup.html и popup.js
var input = document.querySelector('#inp');
var text = document.querySelector("#text");
var button = document.querySelector("#btn");
btn.addEventListener('click', function() {
var inp = input.value;
chrome.tabs.query({active: true, currentWindow: true}, function(foundTabs) {
const activeTab = foundTabs[0];
chrome.tabs.sendMessage(activeTab.id, {text: inp});//sending value of input
})
});
<input type="text" id="inp">
<button id="btn">Send</button>
content.js:
chrome.runtime.onMessage.addListener(function(request) {
const txt = request.text; //get input value
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
//insert in html
});
});
In order to keep the changes made, I would use localStorage (permanent) or sessionStorage (last as long as the window). With that, you can keep track of the changes made and re-make them when the webpage is updated.
For example:
content.js
//whenever the page is loaded/updated, check if there was a saved value
var my_text = sessionStorage.getItem("my_text");
if (my_text) { // if there was, update the page accordingly.
document.querySelector("input").value = my_text;
}
chrome.runtime.onMessage.addListener(function(message){ //when a message is received...
my_text = message.text;
document.querySelector("input").value = my_text; //...update the webpage ...
sessionStorage.setItem("my_text", my_text); // ... and save the value
});
This way your changes will persist upon page reloads, until the window is closed. To make them persist even if the window is closed, substitute sessionStorage by localStorage.
To save changes permanently you need to save the state somewhere.
For this purpose I recommend looking at the Chrome developer background page.
You can send a message from a background page to your content script, which is content.js.
I would like to redirect the user onclick to a certain page "user/logged_in1" if the user is not already on that page and after the redirect a certain button must be clicked. This button opens a modal.
Doesn't work with this function:
function redirect_to_logged_in_and_open_modal() {
if(window.location.href.indexOf("logged_in") > -1) {
return
} else {
location.href="user/logged_in1";
document.getElementsByClassName("zimmerbtn")[0].click();
}
}
It seems it searched already for the button before the redirect happens and therefore the list is empty. How to fix this?
EDIT
This is a little bit more complex. The modal should only open if the user uses the redirect. If I use onload on the body tag, the modal will always open if the page is loaded, I don't need that. I need that modal only to be opened if the redirect happens.
The whole thing is a Python flask application:
{% if current_user.zahlung_iban == None and have_this_user_a_room != None %}
<li><a class="btn mybtn" onclick="redirect_to_logged_in_and_open_modal()" data-toggle="modal" data-target="#premium-special-modal"> Zimmer anbieten </a></li>
{% else %}
<li><a class="btn mybtn" href="{{ url_for('zimmer_einstellen') }}"> Zimmer anbieten </a></li>
{% endif %}
As you see there is a certain trigger for the button to become the redirect button.
EDIT
Okay working with a cookie sounds like a possible solution. But I cant figure out how to delete the cookie after the button was clicked, none of the proposed code works, eventhough it looks simple:
function redirect_to_logged_in_and_open_modal() {
if(window.location.href.indexOf("logged_in") > -1) {
return
} else {
location.href="user/logged_in1";
document.cookie = "redirected_coz_of_click";
}
}
$( document ).ready(function() {
if ($(".logged-in-container")[0]) {
var delete_cookie = function(name) {
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
};
if (document.cookie.indexOf('redirected_coz_of_click') > -1 ) {
document.getElementsByClassName("zimmerbtn")[0].click();
delete_cookie('redirected_coz_of_click');
console.log(document.cookie);
} else {
console.log("cookie removed");
}
}
});
1: Append a parameter to the redirect url
user/logged_in1?click=btn_id
2: On landing on that page you can then check if the parameters is there. Found this method
var getUrlParameter = function getUrlParameter(sParam) {
var sPageURL = decodeURIComponent(window.location.search.substring(1)),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : sParameterName[1];
}
}
};
Found the method here: https://stackoverflow.com/a/21903119/3514785
So you could use it like this:
var btnToClickId = getUrlParameter("click");
3: With jquery (or javascript if you want) fire the click event on that btn:
$("#"+btnToClickId).click();
NB: You want to do the check after the page has loaded:
$(window).on("load",function() {
var btnToClickId = getUrlParameter("click")
if(btnToClickId) {
$("#"+btnToClickId).click();
}
});
So in summary
a: Edit your page and remove this line document.getElementsByClassName("zimmerbtn")[0].click(); because it is pointless
b: In the target page in the js copy and past the `getUrlParameter' method.
c: Then inside a on window load event listener do the url check as specified in 3.
ALTERNATIVE TO URL PARAMETER
You could instead use localStorage or some cookie to store the target id right before redirecting. Make sure you remember to clear it in the target page after grabbing it so that it is not always triggered even when you have not redirected from the page that triggers this whole process.
You can not access elements that have not even loaded yet.
By using location.href = '' you are simply directing a user to a page, any javascript after will fail because the page hasn't been loaded yet.
You tell us that you want to redirect a user to a page onclick. This sounds like the essential of an anchor tag:
Click Me
For step 2, just place the javascript on the page you are redirecting to. Bind to the load event of the page and then execute your javascript:
window.onload = function() {
document.getElementsByClassName("zimmerbtn")[0].click();
};
You can use cookie.
Set cookie when user click on the redirect button and when page is loaded, check if the cookie is set and open the modal. When you done with opening the modal clear the cookie. In that way you can easily achieve this.
Instead of triggering click. Call the onclick function in body onload method of user/logged_in1.
<body onload="openModal()">
You are trying to access a content on your initial page, but you have already redirected the user from that page, so this cannot be achieved by the current method.
I believe what you are trying to do is to open up a modal, after redirecting, do the following.
On your redirected page add the following, use jquery to achieve this
$( document ).ready(
// add the functionality to launch modal here
);
I created an onclick() function for this button:
onclick="redirect_to_logged_in_and_open_modal()"
In the function I check if I am not already on the logged_in site. If not I redirect but I add an additional parameter to the URL ?redirected.
In the next step if the logged_in is loaded and the parameter is in the URL the modal will also open, thats it.
Thanks #Zuks for the Idea adding a param to URL.
function redirect_to_logged_in_and_open_modal() {
if(window.location.href.indexOf("logged_in") > -1) {
return
} else {
window.location.assign("https://www.example.com/user/logged_in1?redirected");
}
}
$( document ).ready(function() {
if ($(".logged-in-container")[0]) {
if(window.location.href.indexOf("redirected") > -1) {
document.getElementsByClassName("zimmerbtn")[0].click();
}
}
});