Prevent onbeforeunload from being called when clicking on mailto link - mailto

Is there anyway to prevent onbeforeunload from being called when clicking on mailto link in chrome.
In FF, Safari, IE it is working fine.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
google.load("jquery", "1.3.2");
</script>
<script type="text/javascript">
$(document).ready(function(){
window.onbeforeunload = confirmExit;
});
function confirmExit() {
return "Are you sure?";
}
</script>
</head>
<body>
Mail Link
</body>
</html>

What about a workaround?
$(document).ready(function(){
mailtoClicked = false;
window.onbeforeunload = confirmExit;
//Test if browser is Chrome
if (/chrom(e|ium)/.test(navigator.userAgent.toLowerCase())) {
$('a[href^=mailto]').click(function() {mailtoClicked = true;});
}
});
function confirmExit() {
if (!mailtoClicked) {
return "Are you sure?";
} else {
mailtoClicked = false;
}
}
Demo.

Here is a proposed solutions that looks reasonable
http://www.ilovebonnie.net/2009/09/23/how-to-use-onbeforeunload-with-form-submit-buttons/
UPDATE (link is dead) - Copied contents from Google Cache
How to Use onbeforeunload with Form Submit Buttons
September 23rd, 2009 — Geekery
While doing some programming I came across an interesting predicament. While I understand it’s evil to make it hard for a user to leave a page, I’m not here to argue the merits (or lack thereof) of onbeforeunload.
On a particular form, we are forcing the browser to not cache the information to avoid potential AJAX/JavaScript problems if they should leave the form and come back as browsers don’t all act the same (eg IE leaves checkboxes checked but doesn’t remember changes that have occurred to the page due to JavaScript). As such, we warn our users when they’re about to leave the order form to let them know they’ll need to fill it in again.
The function was simple enough:
window.onbeforeunload = function () {
return "You are about to leave this order form. You will lose any information...";
}
Unfortunately, this would also be triggered if the user submitted the form which, is obviously not what we want. After searching around on the Internet I came across a simple solution that I thought I would share:
// Create a variable that can be set upon form submission
var submitFormOkay = false;
window.onbeforeunload = function () {
if (!submitFormOkay) {
return "You are about to leave this order form. You will lose any information...";
}
}
Since onclick appears to register before onsubmit when clicking a submit button, we can add a little variable declaration to our submit button so that submitFormOkay will be set to true before the form submission happens:
<input type="submit" id="submit_button" onclick="submitFormOkay = true;">

Related

Grails 3.3.9: Call controller action when checkbox is checked

I am fairly new to Grails and frameworks in general, so this is most likely a very basic problem. The only promising looking solutions I was able to find were working with the Tag, which is apparently deprecated in Grails 3. Similar questions do exist, but all from the time when was still a thing.
I am trying to program a way of displaying products that are grouped in subcategories which are then grouped in categories. When my page loads the subcategories and categories are requested from my database and selection options (Select-tag and checkboxes) are rendered in the view.
When one of the checkboxes representing the subcategories is checked i need to run a database query to get the product information and update an HTML-element by rendering a template for every row I get back. I have a controller action that does all that. My only problem is that I need a way to call the controller action whenever one of the checkboxes is checked.
I could maybe work around it by using actionSubmit and a hidden submit button that is clicked by javascript whenever a checkbox is checked, but that doesn’t seem like a proper solution.
I am probably missing some very basic functionality here but I did already thoroughly search and haven’t come across a proper solution by now, probably because I didn't use the right search terms. I would be so happy, if anyone could help me with this. Thanks a lot already!
The following example uses a javascript function activated in response to the checkbox being checked/unchecked, the value of which is passed to an action from which you can do whatever with the value of the checkbox, run your query etc. At present the action renders a template to update the view with the database results.
index.gsp
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<script type="text/javascript">
$(document).ready(function(){
$( '#cb' ).click( function() {
var checked = $(this).is(":checked");
$.ajax( {
url: "/yourController/yourAction?checked=" + checked,
type: "get",
success: function ( data ) {
$( '#resultDiv' ).html( data )
},
error: function(jqXHR, textStatus, errorThrown) {
console.log( 'Error rendering template ' + errorThrown )
}
} );
})
});
</script>
</head>
<body>
<div id="resultDiv"></div>
<g:form>
<g:checkBox name="cb" />
</g:form>
</body>
YourController
class YourController {
def yourAction() {
// you may want to do something with the value of params.checked here?
def dbResults = YourDomain.getStuff()
render ( template: 'theTemp', model: [dbResults: dbResults] )
}
}
_theTemp.gsp
<table>
<caption>Table of stuff</caption>
<g:each in="${dbResults}" var="aThing">
<tr>
<td>${aThing}</td>
</tr>
</g:each>
</table>

PJax not working with MVC project

I've followed the samples. I added a _PjaxLayout:
<title>#ViewBag.Title</title>
#RenderBody()
Modified my _Layout:
<div id="shell">
#RenderBody()
</div>
<script type="text/javascript">
$(function () {
// pjax
$.pjax.defaults.timeout = 5000;
$('a').pjax('#shell');
})
</script>
Updated ViewStart:
#{
if (Request.Headers["X-PJAX"] != null) {
Layout = "~/Views/Shared/_PjaxLayout.cshtml";
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
Yet every time I click on an 'a' tag, the pjax code doesn't get called. It's as if the selector isn't working when I set up pjax. What am I doing wrong?
UPDATE:
If I do this:
$('document').ready(function () {
$('a').pjax({
container: '#shell',
timeout: 5000
});
});
I see the pjax code getting hit and the Request headers get updated, and the new content loads on the page, but the styling and layout get really messed up and duplicated...
UPDATE:
Inspecting the DOM after this craziness happens reveals that the new page content is getting loaded directly into the anchor that I click, instead of into the element with id #shell. WTF?
You are using a legacy syntax, the new pjax uses the following:
$(document).pjax('a', '#shell', { fragment: '#shell' });
Also I am not familiar with the language you use, but in order to make pjax happen there has to be an HTML element with the id shell in your ViewStart.
As I am not sure about the syntax in that language, try something similar to this for testing:
#{
if (Request.Headers["X-PJAX"] != null) {
echo "<ul id="shell"> pjaaxxx </ul>"; // Would work in php, update syntax
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
I am not seeing that syntax as valid in the PJax documentation.
Are you sure you didn't mean $(document).pjax('a',{});?
$.pjax immediately executes from what I can tell.

How to bind an event to an element in a chrome extension popup window

I've searched quite a bit, and none of the answers I've found have worked 100%.
Basically, I want the popup to show a handful of buttons, then call the same function with different parameters. Concept:
<button onclick="foo(1,2);">Button 1</button>
<button onclick="foo(2,3);">Button 2</button>
I've tried a few simple and direct methods, none of which work. If I take the code out of the function, and have popup.js contain the code, it works (my function is fine).
I've tried:
$('#btn1').click(function(e) {
alert('btn1');
});
as well as
document.getElementById('btn1').addEventListener('click',doSomething(1,2));
Also, i've tried adding the button addEventListener inside of a document.addEventListener('DOMContentLoaded', function() {....});
The curious part is that if my popup.js contains button.addEventListener, the first one is fired upon clicking the browser action, and then nothing works. This happens regardless of whether the click event listner is inside of a DOMContentLoaded listener or not.
I have a feeling this is a CSP issue, but I can't seem to get it to work.
For those scanning for a question mark:
From within a popup.html/popup.js, how can I call a single function with different parameters based on an onclick event?
Issues
I'm not sure if it was just through your abbreviation when copying to SO but none of the code you have given would work "as pasted":
You have no id's on the buttons so binding to the id (I assume this is just because they weren't relevant in the first paste!)
The second paste uses the jQuery library and so you would need to make sure jQuery is included and allowed: https://stackoverflow.com/a/10928761/969807
In the third paste, the second parameter of addEventListener should be a function accepting the event as the first and only parameter (if wanted). (Read On)
Solution
The most common way to bind an event in the scenario you describe would be like so:
document.getElementById('btn1').addEventListener('click', function (){
foo(1, 2);
}, false);
However if there were a lot (or a variable amount) of buttons, I would probably do it like so:
popup.html:
<div id="buttons">
<button data-param1="1" data-param2="2">Button 1</button>
<button data-param1="2" data-param2="3">Button 2</button>
</div>
popup.js:
var els = document.querySelectorAll('#buttons button'),
i, total, param1, param2;
for (i = 0, total = els.length; i < total; i++) {
el = els[i];
param1 = parseInt(el.getAttribute('data-param1'));
param2 = parseInt(el.getAttribute('data-param2'));
el.addEventListener('click', function (){ foo(param1, param2) }, false);
}

SharePoint: commonModalDialogClose does not close cross-domain dialog

I have a page hosted in 'virtualcasa1' domain opening a modal dialog:
var options = {
title: "Repro",
width: 400,
height: 600,
url: http://domain2:999/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx //[1]
//url: http://virtualcasa1/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx [2]
};
SP.UI.ModalDialog.showModalDialog(options);
And I have this code to close it:
alert(document.domain);
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked');
If both are in the same domain (case [2] above), the dialog closes well, no issues.
But - if target page hosted in the dialog (case [1] above), dialog does NOT close :-(
document.domain above shows the correct domain where page exists.
I suspect I'm facing a cross-domain issue here (duh), but how to fix it? Or am I wrong and issue is not XDomain-related?
Thanks much!
HTML5's postMessage is your answer.
https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage
Your parent window that initiates the dialog must have the following javascript:
function listener(event) {
//alert(event.data);
if (event.data == 'Cancel') {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancel clicked');
}
else {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, event.data);
}
}
if (window.addEventListener) {
addEventListener("message", listener, false)
} else {
attachEvent("onmessage", listener)
}
Javascript for OK and Cancel buttons in your popup:
<input type="button" value="OK" onclick="parent.postMessage('Message to be displayed by the parent', '*');" class="ms-ButtonHeightWidth" />
<input type="button" value="Cancel" onclick="parent.postMessage('Cancel', '*');" class="ms-ButtonHeightWidth" />
Ajay's answer from the 1st of August 2014 is good, but it needs a bit more explanation. The reason for the failure to close the dialog is simple. Cross site scripting security features of modern browsers disallow a few things, one of which is the use of window.frameElement from within the framed window. This is a read-only property on the window object and it becomes set to null (or with IE, it actually throws an exception when you try to access it). The ordinary Cancel event handlers in the modal dialog conclude with a call to window.frameElement.cancelPopup(). This will fail of course. The ordinary Save handler where the Save worked on the server side results in SharePoint sending back a single line as the replacement document, which is a scriptlet to call window.frameElement.commitPopup(). This also will not work, and it's a real pain to overcome because the page has been reloaded and there is no script available to handle anything. XSS won't give us access to the framed DOM from the calling page.
In order to make a cross domain hosted form work seamlessly, you need to add script to both the page that opens the dialog and the framed page. In the page that opens the dialog, you set the message listener as suggested by Ajay. In the framed form page, you need something like below:
(function() {
$(document).ready(function() {
var frameElement = null;
// Try/catch to overcome IE Access Denied exception on window.frameElement
try {
frameElement = window.frameElement;
} catch (Exception) {}
// Determine that the page is hosted in a dialog from a different domain
if (window.parent && !frameElement) {
// Set the correct height for #s4-workspace
var frameHeight = $(window).height();
var ribbonHeight = $('#s4-ribbonrow').height();
$('#s4-workspace').height(frameHeight - ribbonHeight);
// Finds the Save and Cancel buttons and hijacks the onclick
function applyClickHandlers(theDocument) {
$(theDocument).find('input[value="Cancel"]').removeAttr('onclick').on('click', doTheClose);
$(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Cancel-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheClose);
$(theDocument).find('input[value="Save"]').removeAttr('onclick').on('click', doTheCommit);
$(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Publish-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheCommit);
}
// Function to perform onclick for Cancel
function doTheClose(evt) {
evt.preventDefault();
parent.postMessage('Cancel', '*');
}
// Function to perform onclick for Save
function doTheCommit(evt) {
evt.preventDefault();
if (!PreSaveItem()) return false;
var targetName = $('input[value="Save"]').attr('name');
var oldOnSubmit = WebForm_OnSubmit;
WebForm_OnSubmit = function() {
var retVal = oldOnSubmit.call(this);
if (retVal) {
var theForm = $('#aspnetForm');
// not sure whether following line is needed,
// but doesn't hurt
$('#__EVENTTARGET').val(targetName);
var formData = new FormData(theForm[0]);
$.ajax(
{
url: theForm.attr('action'),
data: formData,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data, status, transport) {
console.log(arguments);
// hijack the response if it's just script to
// commit the popup (which will break)
if (data.startsWith('<script') &&
data.indexOf('.commitPopup()') > -1)
{
parent.postMessage('OK', '*');
return;
}
// popup not being committed, so actually
// submit the form and replace the page.
theForm.submit();
}
}).fail(function() {
console.log('Ajax post failed.');
console.log(arguments);
});
}
return false;
}
WebForm_DoPostBackWithOptions(
new WebForm_PostBackOptions(targetName,
"",
true,
"",
"",
false,
true)
);
WebForm_OnSubmit = oldOnSubmit;
}
applyClickHandlers(document);
}
});
})();
This solution makes use of the jQuery library, which our organization uses extensively. It is our preferred framework (chosen by me). I'm sure someone very clever could rewrite this without that dependency, but this is a good starting point. I hope someone finds it useful, as it represents a good two days work. Some things to note:
SharePoint does a postback on all sorts of events on the page, including putting the page into edit mode. Because of this, it makes more sense to trap the specific button clicks, both on the form and in the ribbon, rather than wholesale redefinition of, for example, the global WebForm_OnSubmit function. We briefly override that on a Save click and then set it back.
On any Save click event, we defeat the normal posting of the form and replace that with an identical POST request using AJAX. This allows us to discard the returned scriptlet when the form was successfully posted. When the form submission was not successful, perhaps because of blank required values, we just post the form properly to allow the page to be updated. This is fine, since the form will not have been processed. An earlier version of this solution took the resulting HTML document and replaced all of the page contents, but Internet Explorer doesn't like this.
The FormData api allows us to post the form as multipart-mime. This api has at least basic support in all modern browsers, and there are workarounds for older ones.
Another thing that seems to fail in the cross domain hosted dialog is the scrolling of the content window. For whatever reason, the height is not set correctly on the div with id s4-workspace, so we also set that in the solution.
EDIT:
Almost forgot. You may also need to add this control to your framed ASPX page, which can be done with SharePoint Designer:
<WebPartPages:AllowFraming runat="server"/>
I have exactly the same issue - a dialog opening a view page for an item works fine when opened from a site collection on the same web app/domain, but the Close button fails to work when opening the same item from a site collection hosted in a separate web application. I'm assuming it is a cross-domain thing so I've altered the solution to accomodate this restriction, however, I'm not 100% happy about it as it does make the overall solution a little awkward to use from a user-perspective. I've put the issue to one side for now due to project timescales, but I'm still curious as to why. The only things I can think of is the whole cross-domain thing causing it and that maybe it is there by design to prevent XSS security holes.

yahoo autocomplete

I'm kind of like stuck trying to implement YUI autocomplete textbox. here's the code:
<div id="myAutoComplete">
<input id="myInput" type="text" />
<div id="myContainer"></div>
</div>
<script type="text/javascript">
YAHOO.example.BasicRemote = function() {
oDS = new YAHOO.util.XHRDataSource("../User/Home2.aspx");
// Set the responseType
oDS.responseType = YAHOO.util.XHRDataSource.TYPE_TEXT;
// Define the schema of the delimited results
oDS.responseSchema = {
recordDelim: "\n",
fieldDelim: "\t"
};
// Enable caching
oDS.maxCacheEntries = 5;
// Instantiate the AutoComplete
var oAC = new YAHOO.widget.AutoComplete("myInput", "myContainer", oDS);
oDS.generateRequest = function(sQuery) {
return "../User/Home2.aspx?method=" + "SA&Id="+document.getElementById("lbAttributes")[document.getElementById("lbAttributes").selectedIndex].value +"&query="+sQuery;
};
oAC.queryQuestionMark =false;
oAC.allowBrowserAutoComplete=false;
return {
oDS: oDS,
oAC: oAC
};
}
</script>
I've added all the yahoo javascript references and the style sheets but it never seems to make the ajax call when I change the text in the myInput box and neither does it show anything... I guess I'm missing something imp...
#Kriss -- Could you post a link to the page where you're having trouble? It's hard to debug XHR autocomplete without seeing what's coming back from the server and seeing the whole context of the page.
#Adam -- jQuery is excellent, yes, but YUI's widgets are all uniformly well-documented and uniformly licensed. That's a compelling source of differentiation today.
To be honest, and I know this isn't the most helpful answer... you should look into using jQuery these days as it has totally blown YUI out of the water in terms of ease-of-use, syntax and community following.
Then you could toddle onto http://plugins.jquery.com and find a whole bunch of cool autocomplete plugins with example code etc.
Hope this helps.

Resources