Opening a new window/ document in PhoneGap - javascript

With the following code, I am able to open a new window on a Desktop browser:
var thisWin = window;
var oauthWin = thisWin.open(data, 'twitter-oauth-window', 'location=0,status=0,width=800,height=400');
var lastUrl = oauthWin.location.href;
var meh = true;
var oauthInt = thisWin.setInterval(
function()
{
if (meh)
{
alert(
'\noauthWin.closed: ' + oauthWin.closed +
'\noauthWin.location: ' + oauthWin.location +
'\nthisWin.closed: ' + thisWin.closed +
'\nthisWin.location: ' + thisWin.location +
'\noauthWin===thisWin: ' + (oauthWin === thisWin));
meh = false;
}
// do more stuff here
}
);
In the debug output within the alert:
oauthWin===thisWin: false
Which is what it should be. However, when the same code is run within PhoneGap, I get the following:
oauthWin===thisWin: true
Which indicates that PhoneGap has opened the new URL in the same window, replacing the current HTML document.
I wish to open the new URL separately, and to be able to close it upon a certain condition being met, and revert to the old one.
Can this be achieved in PhoneGap, and how?
Thanks!

Now with PhoneGap 2.3+, I was unable to get URLs to open in Mobile Safari in any way. Using _blank didn't work, and I tried window.open(url, '_blank'), but this now opens the URL using the InAppBrowser plugin (which pretty much sucks). I thought it was interesting that that one used a plugin though, so I decided to write a plugin to open URLs using the standard method of opening URLs in iOS apps. You can see/grab the code on this gist here: https://gist.github.com/typeoneerror/5097118.
It's simple enough. In my example, I wired up links that have a class called "_blank" with jQuery and opened those URLs with the plugin call:
// execute the plugin called OpenUrl, signature:
// exec(successCallback, errorCallback, pluginName, pluginMethod, params)
cordova.exec(success, error, "OpenUrl", "openUrl", [url]);
I'm sure you could rewrite the plugin easily for each platform you require it on. This one is iOS-specific.

Related

Intel XDK JavaScript gives out an error of 'alert is not defined (w117)

I m a newbie to programming in JS, i though of giving a try in intel XDk.
I browsed some videos and according to one tutorial, i followed the exact same steps as he did,
But unfortunately, he got the script in emulator working while mine got stuck with a problem of `alert is not defined (W117)' but he didn't got that error,.
My JS code as follows:
/*jshint browser:true */
/*global $ */(function()
{
"use strict";
/*
hook up event handlers
*/
function register_event_handlers()
{
/* button #submit */
$(document).on("click", "#submit", function(evt)
{
/* your code goes here */
var name = document.getElementById('name').value;
var place = document.getElementById('place').value;
var job = document.getElementById('job').value;
var gender = document.getElementById('gender').value;
var reason = document.getElementById('reason').value;
var text = name + place + job + gender + reason ;
alert(text);
return false;
});
}
document.addEventListener("app.Ready", register_event_handlers, false);
})();
Any help is appreciated..
I don't have your full JS code and cannot find an 'app.Ready' event (which is being run on load looks like). To perform check based on jQuery 'ready' event just use below code:
$(document).on("click", "#submit", function(evt) {
var name = document.getElementById('name').value;
var place = document.getElementById('place').value;
var job = document.getElementById('job').value;
var gender = document.getElementById('gender').value;
var reason = document.getElementById('reason').value;
var text = name + place + job + gender + reason;
alert(text);
return false;
});
With the 3900 (and later) releases of the XDK there is a known issue where the alert() (and related) functions no longer work inside the Simulate tab. This was due to an upgrade of the version of Chromium that is built into the node-webkit image that underlies the XDK. At this time there is no workaround, other than to use the Cordova dialogs plugin as an alternative.
Note that in some WebViews (the runtime that your Cordova app runs in when it runs on a real device) the alert() function does not exist, since it is an optional feature and not required. Keep in mind that your Cordova app does not actually run in a browser, it runs in an embedded runtime that feels a bit like a browser, but it's not. Just like Node.js apps have a JavaScript runtime engine, so do WebViews, but neither runtime is hosted within a browser.
In general, using the alert() function is not a good option for a real app.

Can't capture "document.(...).tagName" in phonegap inside inAppBrowser

I open and execute this function inside the opened browser via injected javascript (aka inappbrowser callbacks).
The function works because I see the alerts. The inappbrowser is opened via window.open(...):
var f_el_tname = document.body.getElementsByTagName("the_tag")[0];
//the above alerted "undefined" in android browser and the correct value in the desktop
//rewriting variable for debug purposes
f_el_tname = document.body.getElementsByTagName("the_tag");
alert(f_el_tname.length); //this gives "0" in phonegap android browser and "1" in desktop (correct)
for(var i = 0; i < f_el_tname.size; i++){
alert(f_el_tname); //this does not even run
}
Why exactly is this happening? With "desktop" and "android" I'm referring to accessing the phonegap instance in the desktop or in android, so the code and context are virtually the same. Any idea on why?
EDIT :
I think this might be happening because document in document.body.getElementsByTagName("the_tag"); is referring to the app document and not the document inside the inappbrowser. How can I get the document inside the browser inside the loadstop callback?
The windows is opened by var ref = window.open(...);
EDIT 2: as requested, here is the code
var ref = window.open(url,'_blank','location=yes,toolbar=no,hidden=yes','closebuttoncaption=Return');
ref.addEventListener('loadstop', function(){
var f_el_tname = ref.document.body.getElementById("l_fdb");
//the above gives an error
});
Try to do it using inappbrowser.executeScript:
var ref = cordova.InAppBrowser.open(url,'_blank','location=yes,toolbar=no,hidden=yes');
ref.addEventListener('loadstop', function() {
var code = '(function(){ return document.getElementById("l_fdb"); })()';
ref.executeScript({code: code}, function(results) {
console.log('l_fdb: ' + results);
});
});
Examples of executeScript usage can be found in the plugin tests.

ReportViewer Web Form causes page to hang

I was asked to take a look at what should be a simple problem with one of our web pages for a small dashboard web app. This app just shows some basic state info for underlying backend apps which I work heavily on. The issues is as follows:
On a page where a user can input parameters and request to view a report with the given user input, a button invokes a JS function which opens a new page in the browser to show the rendered report. The code looks like this:
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}
});
The page that is then opened has the following code which is called from Page_Load:
rptViewer.ProcessingMode = ProcessingMode.Remote
rptViewer.AsyncRendering = True
rptViewer.ServerReport.Timeout = CInt(WebConfigurationManager.AppSettings("ReportTimeout")) * 60000
rptViewer.ServerReport.ReportServerUrl = New Uri(My.Settings.ReportURL)
rptViewer.ServerReport.ReportPath = "/" & My.Settings.ReportPath & "/" & Request("Report")
'Set the report to use the credentials from web.config
rptViewer.ServerReport.ReportServerCredentials = New SQLReportCredentials(My.Settings.ReportServerUser, My.Settings.ReportServerPassword, My.Settings.ReportServerDomain)
Dim myCredentials As New Microsoft.Reporting.WebForms.DataSourceCredentials
myCredentials.Name = My.Settings.ReportDataSource
myCredentials.UserId = My.Settings.DatabaseUser
myCredentials.Password = My.Settings.DatabasePassword
rptViewer.ServerReport.SetDataSourceCredentials(New Microsoft.Reporting.WebForms.DataSourceCredentials(0) {myCredentials})
rptViewer.ServerReport.SetParameters(parameters)
rptViewer.ServerReport.Refresh()
I have omitted some code which builds up the parameters for the report, but I doubt any of that is relevant.
The problem is that, when the user clicks the show report button, and this new page opens up, depending on the types of parameters they use the report could take quite some time to render, and in the mean time, the original page becomes completely unresponsive. The moment the report page actually renders, the main page begins functioning again. Where should I start (google keywords, ReportViewer properties, etc) if I want to fix this behavior such that the other page can load asynchronously without affecting the main page?
Edit -
I tried doing the follow, which was in a linked answer in a comment here:
$.ajax({
context: document.body,
async: true, //NOTE THIS
success: function () {
window.open(Address);
}
});
this replaced the window.open call. This seems to work, but when I check out the documentation, trying to understand what this is doing I found this:
The .context property was deprecated in jQuery 1.10 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.
I removed the context property entirely and it didnt seem to affect the code at all... Is it ok to use this ajax call in this way to open up the other window, or is there a better approach?
Using a timeout should open the window without blocking your main page
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
setTimeout(function() {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}, 0);
}
});
This is a long shot, but have you tried opening the window with a blank URL first, and subsequently changing the location?
$("#btnShowReport").click(function(){
If (CheckSession()) {
var pop = window.open ('', 'showReport');
pop = window.open ('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>', 'showReport');
}
})
use
`$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.location.href='<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>';
}
});`
it will work.

Is it possible to control Firefox's DNS requests in an addon?

I was wondering if it was possible to intercept and control/redirect DNS requests made by Firefox?
The intention is to set an independent DNS server in Firefox (not the system's DNS server)
No, not really. The DNS resolver is made available via the nsIDNSService interface. That interface is not fully scriptable, so you cannot just replace the built-in implementation with your own Javascript implementation.
But could you perhaps just override the DNS server?
The built-in implementation goes from nsDNSService to nsHostResolver to PR_GetAddrByName (nspr) and ends up in getaddrinfo/gethostbyname. And that uses whatever the the system (or the library implementing it) has configured.
Any other alternatives?
Not really. You could install a proxy and let it resolve domain names (requires some kind of proxy server of course). But that is a very much a hack and nothing I'd recommend (and what if the user already has a real, non-resolving proxy configured; would need to handle that as well).
You can detect the "problem loading page" and then probably use redirectTo method on it.
Basically they all load about:neterror url with a bunch of info after it. IE:
about:neterror?e=dnsNotFound&u=http%3A//www.cu.reporterror%28%27afew/&c=UTF-8&d=Firefox%20can%27t%20find%20the%20server%20at%20www.cu.reporterror%28%27afew.
about:neterror?e=malformedURI&u=about%3Abalk&c=&d=The%20URL%20is%20not%20valid%20and%20cannot%
But this info is held in the docuri. So you have to do that. Here's example code that will detect problem loading pages:
var listenToPageLoad_IfProblemLoadingPage = function(event) {
var win = event.originalTarget.defaultView;
var docuri = window.gBrowser.webNavigation.document.documentURI; //this is bad practice, it returns the documentUri of the currently focused tab, need to make it get the linkedBrowser for the tab by going through the event. so use like event.originalTarget.linkedBrowser.webNavigation.document.documentURI <<i didnt test this linkedBrowser theory but its gotta be something like that
var location = win.location + ''; //I add a " + ''" at the end so it makes it a string so we can use string functions like location.indexOf etc
if (win.frameElement) {
// Frame within a tab was loaded. win should be the top window of
// the frameset. If you don't want do anything when frames/iframes
// are loaded in this web page, uncomment the following line:
// return;
// Find the root document:
//win = win.top;
if (docuri.indexOf('about:neterror') == 0) {
Components.utils.reportError('IN FRAME - PROBLEM LOADING PAGE LOADED docuri = "' + docuri + '"');
}
} else {
if (docuri.indexOf('about:neterror') == 0) {
Components.utils.reportError('IN TAB - PROBLEM LOADING PAGE LOADED docuri = "' + docuri + '"');
}
}
}
window.gBrowser.addEventListener('DOMContentLoaded', listenToPageLoad_IfProblemLoadingPage, true);

Resizing Iframe issue in Chrome only

Okay, here goes. Stack Overflow virgin here but hopefully you guys will be able to help me.
I have been playing around with resizing the height of an iframe based on it's content. The content varies as a user will progress through a series of forms, this means that each submit will result in a new form of which there are 3 forms.
The code below is called when the iframe loads,
function checkHeight() {
var frame=document.getElementById('frame');
var doc=frame.contentWindow.document;
var data=doc.getElementById('data');
alert(data);
var data_height=data.offsetHeight;
if(data_height) {
frame.style.height=data_height + 'px';
alert('height has been set');
}
}
This is working fine on both mac and pc versions of Mozilla, IE and Safari but I am having a massive issue with chrome. It is not returning a document within the frame. Is this a permissions error or what?!
I have also tried contentDocument but to no avail.
All the documents reside on my server and are all within the same folder.
Thanks in advance.
Edit:
I've re-read your question - would it be simpler to just calculate the height inside the iframe's document and call the parent resizing function since they are in the same security sandbox (i.e. on the same domain)?
Original:
Since a somewhat similar thing happens when the iframes are embedded from a different domain (cannot access iframe..document) I'd speculate this approach would work:
First: calculate the document height in the document itself (i.e. inside the iframe).
Pass the values to the parent using window.postMessage/hash polling for older browsers. There is a neat library that takes care of compatibility for you.
Receive the value in the parent and resize the iframe accordingly.
Again, this may be overkill, but given that the solution has been tested to do exactly what you're after between different security sandboxes, this should also be the case for a simpler scenario if iframes are on the same domain.
That being said, if they are on the same domain (as opposed to widgets/non-mashable third party content) is there really need for an iframe? Sounds like it's just a matter of setting up jQuery to make ajax requests and populate container(s) with new data.
this seems like a fairly straight forward question so i'm not sure why such strange answers, so maybe i missed the boat entirely on this one, but here are my solutions, one is x-domain and the other isn't (note: the open/write/close, is just there to simulate server interaction to make it more obvious what's going on...)
first x-domain style:
// METHOD #1: postMessage() x-domain (chrome, ff, ie8+, safari, etc)
var d = document,
iframe = d.createElement('iframe');
iframe.height = 0;
d.getElementsByTagName('body')[0].appendChild(iframe);
window.onmessage = function(msg) {
iframe.height = parseInt(msg.data, 10);
};
var fd = iframe.contentDocument || iframe.contentWindow.document;
fd.open();
fd.write('<!DOCTYPE ht' + 'ml><ht' + 'ml><he' +
'ad><scri' + 'pt>' +
'window.onload = function(){' +
'var db = document.body,' +
'de = document.documentElement;' +
'window.parent.postMessage(' +
'Math.max(db.scrollHeight, de.scrollHeight, db.offsetHeight, de.offsetHeight, db.clientHeight, de.clientHeight),' +
'"*"' +
');' +
'};</scr' + 'ipt></he' + 'ad><bo' +
'dy style="background:#afa"><div style="border:s' +
'olid 1px black;padding:50px;line-height:50px">method #1: x-domain<b' +
'r />test<br />test</div></bo' + 'dy></ht' +
'ml>');
fd.close();
next more compatible same domain version:
// METHOD #2: manually same-domain (all browsers? [with tweaks] )
var iframe2 = d.createElement('iframe');
iframe2.height = 0;
iframe2.onload = function() {
var xfd = iframe2.contentDocument || iframe2.contentWindow.document,
db = xfd.body,
de = xfd.documentElement;
iframe2.height = Math.max(db.scrollHeight, de.scrollHeight, db.offsetHeight, de.offsetHeight, db.clientHeight, de.clientHeight);
};
d.getElementsByTagName('body')[0].appendChild(iframe2);
fd = iframe2.contentDocument || iframe2.contentWindow.document;
fd.open();
fd.write('<!DOCTYPE ht' + 'ml><ht' + 'ml><he' +
'ad></he' + 'ad><bo' +
'dy style="background:#aaf"><div style="padding:50px;line-height:50px;border:s' +
'olid 1px black;">method #2: same domain<b' +
'r />test2<br />test2</div></bo' + 'dy></ht' +
'ml>');
fd.close();
you can see it in action here: http://jsbin.com/ifevad
i hope this helps -ck
This very same example worked for me, in Chrome 17, on Windows, with the given html files:
index.html:
<html>
<head>
</head>
<body>
<iframe src="index2.html" id="test">
</iframe>
</body>
</html>
index2.html
<html>
<head>
</head>
<body>
<div id="test_div">
Ohai
</div>
</body>
</html>
Then I used this in the chrome developer window:
i = document.getElementById('test')
doc = i.contentWindow.document
data=doc.getElementById('test_div');
i.style.height = data.offsetHeight + 'px'
The only catch was that it didn't work when opening the .html files directly - I had to start a web server.
I used this (it's the default Python server):
server.py
import SimpleHTTPServer
import SocketServer
PORT = 8080
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()

Categories

Resources