How to close a facebook SDK dialog opened with FB.ui()? - javascript

I'm successfully displaying an invite friend dialog (code shown below). When user clicks skip the iframe/dialog shows a new page. However from this point I can't find a way how to close the iframe/dialog. FB.ui doesn't return any object, there doesn't seem to be a Javascript SDK method and traversing and manipulating with the DOM will be brittle to any FB code changes.
Any ideas?
function popupInviteForm(actionUrl) {
var fbmlString = '<fb:fbml>' +
' <fb:request-form type="POST" content="Play against me in game?" action="' + actionUrl + '" method="post" >' +
' <fb:multi-friend-selector target="_self" exclude_ids="" max="20" cols="4" rows="3" showborder="false" actiontext="Invite friends!" />' +
' </fb:request-form>' +
'</fb:fbml>';
FB.ui({
method: 'fbml.dialog',
fbml: fbmlString,
display: 'dialog',
size: {width:640,height:480}, width:640, height:480
});
$(".FB_UI_Dialog").css('width', $(window).width()*0.8);
}
(Note: I have posted the same question on the facebook forum with no response. I will update both, should there be an answer on either.)
The Javascript code was adapted from a stack overflow answer.

I have same trouble. Second day looking for a solution. And just found one way:
for closing active FB dialog you should perform followed code in parent window where FB JS is available and where FB.ui was called:
FB.Dialog.remove(FB.Dialog._active);
So, if you want your invite dialog auto closes and don't redirects to any other page, use these steps:
1) Set target attr of and as "_self":
target="_self"
2) create some callback url/page on your site, for example
https://mysite/close_dialog.html
3) Set action attr of as just created url:
action="http://mysite/close_dialog.html"
4) In your close_dialog.html put followed JS:
<script type="text/javascript">
if (document.location.protocol == 'https:') {
document.location = 'http://mysite/close_dialog.html';
} else {
top.window.FB.Dialog.remove(top.window.FB.Dialog._active);
};
</script>
UPDATE:
5) There is one issue else in this way:
FB iframe loaded by https, but if request-form 'action' attr uses 'http' - user will get browser warning. But if request-form 'action' has 'https' - iframe js cant access to parent loaded by 'http'.
So, its the reason why you should use action by 'https'
Hope this helps
If you has better solution or you can improve this way - please let all know this,
Thanks for any comments

That doesn't work (at least not for me).
What I did was simply call the javascript window.close(); function instead of top.window.FB.Dialog.remove(top.window.FB.Dialog._active); and it works.
<script type="text/javascript">
if (document.location.protocol == 'https:') {
document.location = 'http://mysite/close_dialog.html';
} else {
//alert('some message');
window.close();
};
</script>

The FB.ui provides an option for a callback function which will be executed after the FB.ui is completed.
FB.ui(
{
method: '..........',
..................
},
function(response) {
//write your code here
}
);
Will this help to solve your problem?

i found Igor Reshetnikov's answer did work, but only if i made sure to declare both pages - The one that opens the dialog and close_dialog.html - as part of the same domain using document.domain. so at the top of the script tags in both pages you'ld had to add this line
document.domain = 'mysite.com';
obviously replacing mysite.com with what ever your domain is

This closes all dialogs, but may not work with future releases due to access of internal variable _loadedNodes
if (FB && FB.UIServer && FB.UIServer._loadedNodes) {
var nodes = FB.UIServer._loadedNodes;
if (nodes) {
for (var item in nodes) {
if (nodes[item].type && nodes[item].node && nodes[item].node.close &&
nodes[item].type === "popup") {
nodes[item].node.close();
}
}
}
}

FWIW, my browser's privacy plugin was preventing FB from closing the dialog. I just switched off the privacy plugin and dialog closed itself as expected.

Related

Javascript behavior between 2 different functions that I don't understand

I'm a Java developer not well-versed in front-end technologies, so I hope this question isn't too dumb. I have 2 scripts inline on an html page.
<script type="text/javascript">
function printReceipt(orderId,email) {
var printWindowSettings;
var browserUserAgent = navigator.userAgent;
if (browserUserAgent.indexOf("Chrome") > -1) {
printWindowSettings = "status=0,toolbar=0,menubar=0,height=500,width=1000,scrollbars=1";
} else {
printWindowSettings = "status=0,toolbar=0,location=0,menubar=0,height=500,width=1000,scrollbars=1,noopener=1";
}
var path = "/shop/printReceipt?orderid="+orderId;
if (email!=null)
path+="&email=" + email;
var docPrint = window.open(path, '_blank', printWindowSettings);
if (docPrint == null) console.log("window open returned null");
}
</script>
<script type="text/javascript">
bajb_backdetect.OnBack = function()
{
window.history.back=function(){
console.log("Back Button Pressed.")
document.location='/shop/shoppingCart.seam';
}
}
</script>
printReceipt() is invoked in the onClick() handler of an anchor tag.
<div class="pull-left" style="padding-bottom:20px;"><i class="fa fa-print" aria-hidden="true" style="padding-right:6px;"></i>Print Receipt</div>
What I'm finding is that when printReceipt() is invoked, the following script (to manage the back button) gets invoked also. So when printReceipt() is called, my browser navigates to /shop/shoppingCart.seam.
Why would this be? How do I get around this?
I made a bit of research about your issue, and since you mention that you are using a third party script (which is not always the best for a developer), I found something that may help you get rid of it.
This method will need you to delete the third party script you already have (or comment it). Since we are going to handle the back button in a different way.
In the script tag where you had the following code:
bajb_backdetect.OnBack = function() {
window.history.back = function() {
console.log("Back Button Pressed.")
document.location = '/shop/shoppingCart.seam';
}
}
Replace it with this code:
(function(window, location) {
history.replaceState(null, document.title, location.pathname+"#!/history");
history.pushState(null, document.title, location.pathname);
window.addEventListener("popstate", function() {
if(location.hash === "#!/history") {
history.replaceState(null, document.title, location.pathname);
setTimeout(function(){
location.replace("/shop/shoppingCart.seam"); //Here goes your URL
},0);
}
}, false);
}(window, location));
And now, if you did remove the third party script (or commented it), you should be able to see the expected behavior.
If you want to see more about this, there is a question similar to this that has been already answered saying the best approach for handling the window back event is doing it by yourself.
I took this information from this answer, just complemented it with the explanation and code for your specific issue. Hope it helps.
Note: If it still not working, you will need to provide a more open context of your code, since there might be something else causing it to not work.
Probably the anchor being clicked causes the browser to follow the link.
Given this:
click me
Clicking that link will run the function and then the page will reload. Your back detection script will notice that the page is being unloaded and do stuff (apparently).
Change it to:
click me
To prevent the link from being followed.

How to get href value in selenium webdriver when javascript is called upon click of a link?

Thank you for reviewing my query. On a webpage, there are more than 200 links & I've ensure all are working. This is easy after fetching href value but the problem is, the 'href' value doesn't contain a link rather a 'javaScript function' Here is a source
<a tabindex="8" title="Internal Crossload" target="_self" href="javascript:fnnHomePage('3' , 'WTMS_EXPRESS')"> - Internal Crossload </a>
JavaScript function:
<Script>
/*********************************************************************
Function Name : fnnHomePage
Input Parameter(s) : transferTypeId
Output Parameter(s) : None
**********************************************************************/
function fnnHomePage(transferTypeId ,moduleName) {
if (moduleName == "XXX_EXPRESS")
{
document.getElementById("transferTypeId").value=transferTypeId;
document.getElementById("gadgetType").value="XXX_EXPRESS";
document.getElementById("moduleName").value="XXX_EXPRESS";
document.forms[0].action="/XXX/getProposalHomePage.do?transferTypeId="+transferTypeId;
document.forms[0].submit();
}
if (moduleName == "CROSSLOAD")
{
document.getElementById("transferTypeId").value=transferTypeId;
document.getElementById("gadgetType").value="CROSSLOAD";
document.getElementById("moduleName").value="CROSSLOAD";
document.forms[0].action="/XXX/getCrossLoadHomePage.do?transferTypeId="+transferTypeId;
document.forms[0].submit();
}
}
</Script>
From the above code, how to I get a 'Link' and check if it is working fine in selenium webdriver? There are several links & each one calls a different 'JavaScript function'.Any suggestions will be appreciated. Thank you.
You may use a simple trick- click on the link. It will redirect you to the new link generated by javascript function. Then, get the link using driver.getCurrentUrl(); and go back to your original page and do your stuff as usual.
I hope, this makes sense.
Here is the working code,using this code you can see all the links on your console and further you can navigate to all the links:
driver.get("https://www.facebook.com");
List<WebElement> all_links_webpage = driver.findElements(By.tagName("xyz"));
System.out.println("Total no of links Available: " + all_links_webpage.size());
int links = all_links_webpage.size();
System.out.println("List of links Available: ");
for(int i=0;i<links;i++)
{
if(all_links_webpage.get(i).getAttribute("href").contains("google"))
{
String link = all_links_webpage.get(i).getAttribute("href");
System.out.println(link);
}
}
Hope this will solve your problem.

If user came from previous page on site then this, else do this

What would be a viable way to accomplish the following:
A website has two pages; Parent page and Inside page. If user came to the Inside page directly by typing in the address or by following a link from a page other than Parent page, then show "foo". If user came to the Inside page from the parent page, then show "bar".
I would need this done in JS if possible. If not, PHP is a secondary choice.
You can get the page the user came from with document.referrer.
So you could implement your solution like this:
if (document.referrer === 'yoursite.com/parentpage') {
// do bar
} else {
// do foo
}
Please try this
This code in second page
jQuery(window).load(function() {
if (sessionStorage.getItem('dontLoad') == null) {
//show bar
}
else{
//show foo
}
});
This code in parent page
jQuery(window).load(function() {
sessionStorage.setItem('dontLoad','true')
});
with php:
There is a simple way is to create a mediator page which redirect to inner page after make a session / cookie.. then if you'll get session / cookie, you show foo & unset session.
if someone directly come from url, no session / cookie found & it show bar..
You can use the document.referrer but this is not always set. You could add a parameter to the URL on the parent page and then check for its existance in the child page
Link on the parent page:
<a href='myChildPage.html?fromParent=1'>My Child Page</a>
JS code on your child page:
var fromParent=false;
var Qs = location.search.substring(1);
var pairs = Qs.split("&");
for(var i = 0; i < pairs.length; i++){
var pos = pairs[i].indexOf('=');
if(pos!==-1){
var paramName = pairs[i].substring(0,pos);
if(paramName==='fromParent'){
fromParent=true;
break;
}
}
}
if(fromParent){
alert("From Parent");
}else{
alert("NOT From Parent");
}
This method isnt 100% foolproof either as users could type in the same URL as your parent page link. For better accuracy check the document.referrer first and if not set use the method i've outlined above
intelligent rendering with jQuery
After using #Rino Raj answer, i noticed it needed improvement.
In javascript, the load() or onload() event is most times much slower,
since it waits for all content and images to load before executing your attached functions.
While an event attached to jQuery’s ready() event is executed as soon as the DOM is fully loaded, or all markup content, JavaScript and CSS, but not images.
Let me explain this basing, on code.
When i used #Rino Raj's code, with load() event, it works but on the second/called page, the content appears before class="hide fade" is added (which I don't really want).
Then i refactored the code, using the ready() event, and yes,
the content that i intended to hide/fade doesn't appear at all.
Follow the code, below, to grasp the concept.
<!-- Parent/caller page -->
<script type="text/javascript">
$(document).ready(function() {
sessionStorage.setItem('dontLoad', 'true');
});
</script>
<!-- Second/called page -->
<script type="text/javascript">
$(document).ready(function() {
if(sessionStorage.getItem('dontLoad') == null) {
$("#more--content").removeClass("hide fade");
} else {
$("#more--content").addClass("hide fade");
}
});
</script>

Advanced jQuery Popout Window

Several problems:
1) I am trying to make this script run more efficiently.
2) When the user clicks either pop out button it opens a windows and hides the element. (Currently I am using .detach() to remove the embedded video player because in Firefox .toggle() just hides the player but keeps the audio playing. Is there a better way to do this?
3) In theory by clicking the button again or closing the window manually it should un hide or .toggle() the element but does not for the video player due to detach().
4) If a user pops out the window manually closes it and then pops it out again to only close it once more the element does not .toggle() back.
See it in action here, http://www.mst3k.tv/.
$(document).ready(function() {
$('#lights').click(function(){$('#darkness').fadeToggle(500);});
$("#lights").toggle(function(){$("#lights").attr('id','lightsoff');},function(){$("#lightsoff").attr('id','lights');});
/**VIDEO**/
var videoWin;
$('#video-toggle').click(function(){
$('#video').fadeToggle(500);
$('#video').detach();
});
$('#video-toggle').click(function(){
if (videoWin && !videoWin.closed) {
videoWin.close();
return false;
}
videoWin = window.open(
$(this).attr('rel'),
'videoWin',
'width=600,height=480,toolbar=0,top=0,left=0,menubar=0,location=0,status=0,scrollbars=0,resizable=1');
return false;
}
);
var watchVideo = setInterval(function() {
if (videoWin.closed) {clearTimeout(watchVideo);$('#video').show(500)}
return false;
}, 1);
/**CHAT**/
var chatWin;
$('#chat-toggle').click(function(){
$('#chat').fadeToggle(500);
/*$('#chat').detach();*/
});
$('#chat-toggle').click(function(){
if (chatWin && !chatWin.closed) {
chatWin.close();
return false;
}
chatWin = window.open(
$(this).attr('rel'),
'chatWin',
'width=320,height=480,toolbar=0,top=0,left=601,menubar=0,location=0,status=0,scrollbars=0,resizable=1');
return false;
}
);
var watchChat = setInterval(function() {
if (chatWin.closed) {clearTimeout(watchChat);$('#chat').show(500)}
return false;
}, 1);
/*$("a.btn").fitText(1.2, { minFontSize: "6px", maxFontSize: "14px" });*/
});
It would be better if you created a jQuery plugin for your code so you can re-use it and avoid DRY. Here are a couple of options:
Plugin 1: jQuery popupWindow
Plugin 2: jQuery winPop
Also note that the closed property is not part of any W3C specification, however it might be supported across Browsers.
You could also write a JS function that could be reused. According to the w3cschools website the window.closed property is supported in most major browsers and you can check for it prior to triggering the event.
instead of
if(videoWin && !videoWin.closed)
you could use
if (typeof videoWin!='undefined'){ /* it has been created */}
elseif(typeof videoWin='undefined') { /*it's okay to open the new window*/}
Make sure you're not creating the variable if you're using this as a check though until the window open event has been fired. Since you're creating the var a couple of lines above your function declaration it will always return as defined.
You'll need to specify a target object in your function to have it throw multiple windows correctly... meaning you can't declare one var for multiple windows. Maybe a class would be better.
Something I thought was odd earlier but forgot to mention before FB posted my response prematurely was that you're adding your href in the rel attribute and specifying the href as a js:void(0) which is also non-standard. The rel attribute is for specifying the relationship between the link and the page... (eg. rel=nofollow). That might also be why it's not firing and misfiring some of the time as well, and the differences between browser response.

Django Admin - RelatedObjectLookups - How Does it refresh and set the select on the parent window?

I want one of my forms to work just like the admin page does so I figured I'd look in the code and see how it works.
Specifically I want the user to be able to click a "+" icon next to a select list and be taken to the admin page's popup form to add a new item.
When they enter a new item there, I want that new item to appear in the select box, and be selected (Just like how this feature works on the admin pages).
I copied the admin js libraries into my own template, and I made my link call the same JS function and the popup windows does open correctly, but after I save a new object the popup window goes blank instead of closing, and nothing happens on the parent page.
Here's what I put in my page:
...
<td>
<div class="fieldWrapper">
<select name="form-0-plasmid" id="id_form-0-plasmid">
...
</select>
<img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/>
</div>
</td>
...
I tried stepping through the javascript on the admin form to see how it's working, but I'm not seeing anything that would close the window or populate the parent window's select.
Thanks in advance for any help.
Update 3
I'm getting this javascript error when dismissAddAnotherPopup is run
"SelectBox is not defined"
Which is pointing to this line in dismissAddAnotherPopup
SelectBox.add_to_cache(toId, o);
I thought I knew Javascript, but I don't see where that variable is supposed to come from :-(
Update 2
Everything seems to be firing properly. After I click save on the popup window I get a blank page. This is the source of that page:
<script type="text/javascript">opener.dismissAddAnotherPopup(window, "9", "CMV_flex_myr_GENE1_._._WPRE_BGH");</script>
So it would seem that this javascript isn't being executed or is failing.
Update
Here is the relevant code that Daniel mentioned. So the only problem is that this code either isn't firing, or is firing incorrectly.
django/contrib/admin/options.py:
...
if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(pk_value), escapejs(obj)))
...
/media/admin/js/admin/RelatedObjectLookups.js:
function dismissAddAnotherPopup(win, newId, newRepr) {
// newId and newRepr are expected to have previously been escaped by
// django.utils.html.escape.
newId = html_unescape(newId);
newRepr = html_unescape(newRepr);
var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
if (elem) {
if (elem.nodeName == 'SELECT') {
var o = new Option(newRepr, newId);
elem.options[elem.options.length] = o;
o.selected = true;
} else if (elem.nodeName == 'INPUT') {
if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
elem.value += ',' + newId;
} else {
elem.value = newId;
}
}
} else {
var toId = name + "_to";
elem = document.getElementById(toId);
var o = new Option(newRepr, newId);
SelectBox.add_to_cache(toId, o);
SelectBox.redisplay(toId);
}
win.close();
}
Ok, the javascript simply uses the id attribute of the launching element to identify the select field to update. (after removing 'add_' from the beginig).
So I simply changed the link's id attribute to match the select element's id in my template:
<img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/>
Wow I wish this had been documented somewhere! I lost a few hours on this.
(See my updates to the question for more technical details on how it all works.)
The trick - and it's a bit of a hack, actually - is what happens when you click save on the popup in the admin.
If you look at the code of response_add in django.contrib.options.ModelAdmin, you'll see that when you save an item in the popup, the admin returns an HttpResponse consisting solely of a piece of Javascript. This JS calls the dismissAddAnotherPopup function in the parent window, which closes the popup and sets the form value appropriately.
It's fairly simple to copy this functionality into your own app.
Edited after updates If admin javascript doesn't work, it's usually because it has a dependency on the jsi18n code - which you include via a URL (not a static path):
<script type="text/javascript" src="/admin/jsi18n/"></script>
I was having the same problem refreshing the select in the parent window, and I solved following this doc
Everything is working fine now
Edit 1:
I was trying to use Select2 to make the select pretty, the single select works fine, the multiple select is giving me headaches for some reason is not updating the info in the parent form.
Anyone tried this before?

Categories

Resources