Tracking url of external site launched in cordova-inappbrowser-plugin - ionic-framework

I'm currently building an ionic app which is to be a wrapper for an external web application. What I want to do is to be able to track the url being redirected to when the user changes location in the external web app.
In my main controller I have the following code.
app.controller('MainCtrl', function ($rootScope) {
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
// Now safe to use the Codova API
var url = "https://external-site/";
var target = "_self";
var options = "location=no";
var ref = cordova.InAppBrowser.open(url, target, options);
ref.addEventListener('loadstart', function () {
console.log("loadstart");
});
}
});
When the page loads I don't get the event listener to fire or when the user changes locations in the external site. I have tried pointing the target to _system and _blank which makes no difference for me.
Can anybody help me?
Thanks in advance.

It's my experience that all the events not always fires on all platforms. Try subscribing to all the events and print some debug info. Then test on different devices (iOS, android) and see what events are fired.
$rootScope.$on('$cordovaInAppBrowser:loadstart', function(e, event){console.log('start')};
$rootScope.$on('$cordovaInAppBrowser:loadstop', function(e, event){console.log('stop')});
$rootScope.$on('$cordovaInAppBrowser:loaderror', function(e, event){console.log('err')});
$rootScope.$on('$cordovaInAppBrowser:exit', function(e, event){console.log('exit')});
btw: I'm using ngCordova here...

very strange.. all I did was update ionic, run 'ionic start test blank' add the plugin modify app.js to this
angular.module('starter', ['ionic'])
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
if (window.cordova && window.cordova.plugins.Keyboard) {
var inAppBrowserRef;
var target = "_self";
var options = "location=no";
inAppBrowserRef = cordova.InAppBrowser.open('https://onesignal.com/', target, options);
inAppBrowserRef.addEventListener('loadstart', function () { console.log('start') });
inAppBrowserRef.addEventListener('loadstop', function () { console.log('stop') });
inAppBrowserRef.addEventListener('loaderror', function () { console.log('err') });
}
});
})
and then run 'ionic run android' and all events fires perf.

Related

Angular could not be found on the page with angular application while running test for angular app in iFrame

I have an angular application running inside iFrame. I must need to launch parent application URL as it provide some flag which makes angular app working as expected. Now I need to write protractor tests for angular app in iFrame.
Here is the code.
describe('French page', function() {
var IFRAME = "iframe",
TITLE_FR = 'Découverte automatique',
PAGE_URL = '/SAAS/admin/app/page',
pagePaths = browser.params.paths;;
beforeEach(function (done) {
LOGIN_PAGE.goToPageAndLogin().then(function (){
browser.driver.ignoreSynchronization = true;
browser.get(PAGE_URL); // application has angular app in iFrame
browser.sleep(5000);
browser.waitForAngular();
done();
});
});
afterEach(function (done) {
demoPause();
LOGIN_PAGE.logout().then(done);
});
it('should be able to launch with fr-FR locale', function (done) {
browser.driver.switchTo().frame(IFRAME); //Switch to angular app in iFrame
// Check if element text is in french
browser.driver.findElement(by.css('.app-menu li:nth-child(1) p')).then(function (elem) {
elem.getText().then(function (text) {
expect(text).toBe(TITLE_FR); // I can see that both texts are same here while debugging
browser.driver.ignoreSynchronization = true;
done();
});
});
});
});
The test condition passed but it exit with below error.
Message:
Failed: Angular could not be found on the page
https://host/abcd/admin/app/page
retries looking for angular exceeded
The issue got fixed by putting
browser.ignoreSynchronization = true;
before
browser.get(PAGE_URL);
Few things:
The parameter IFRAME passed into:
browser.driver.switchTo().frame(IFRAME); needs to be the ID
property of the element, not the tag name of the element, example:
your iframe element
<iframe id="myIframeId" name="frame3">...</iframe>
you would in this case do
browser.diver.switchTo().frame("myIframeId");
Don't call browser.waitForAngular(); on a non-angular page. Since only your iframe element is Angular, I suggest doing the following to make sure a specific element is present before continuing:
browser.driver.wait(function() {
return browser.driver.isElementPresent(by.css("your_selector")).then(function(present) {
return present;
});
}, 20000);
This will wait for an element to be present for 20 seconds, regardless of the page being Angular or not and then continue.
After you switch to the iframe element, you should call browser.driver.ignoreSynchronization = false; to turn on Angular synchronization back on. Since your code inside your iframe is Angular.

Waiting for Ionic Loading dialogs with Protractor

There are similar questions (linked below) but none solves this problem. I'm writing Protractor tests for an Ionic Project. I need to execute tests at times when an Ionic Loading dialog appears and disappears.
I've created a repo with the bare bones of the app and the tests that need to be made. Solve this and you solve the problem (I describe the problem below): https://github.com/TmanTman/StackoverflowQ. Just adapt the path to your Chrome for your system in conf.js.
To simulate an asynchronous Ionic Loading dialog I just add this to the controller in a blank Ionic project:
$interval( function() {
$ionicLoading.show({
template: 'Async ionicLoading',
duration: 5000
});
}, 5000 , 1);
})
I need to get protractor to wait for the dialog to appear, do some tests, wait for the dialog to disappear, and then do some more tests. My latest attempt in my test file is:
it('should only test when ionicLoading appears', function() {
browser.wait(function(){
return element(by.css('.loading-container.visible.active')).isPresent();
}, 10000);
var ionicLoadingText = element(by.css('.loading-container.visible.active')).getText();
expect(ionicLoadingText).toEqual('Async IonicLoading');
})
it('should only test once ionicLoading disappears', function() {
browser.wait(function() {
var deferred = protractor.promise.defer();
var q = element(by.css('.loading-container.visible.active')).isPresent()
q.then( function (isPresent) {
deferred.fulfill(!isPresent);
});
return deferred.promise;
});
expect(1).toEqual(1);
})
I'm trying to avoid using synchronous sleep function, as my code is highly asynchronous. I've tried countless variations but I can't get it to work. Links I've used for info includes:
Protractor blocking wait
Asynchronous Testing with Protractor's ControlFlow
Protractor wait for isElementPresent and click on waited element fails
The problem is two-fold:
1) From what I can deduce, the duration property of the $ionicLoading method is implemented with a timeout function. Protractor does not work well with $timeout. So instead of using the duration property, the $ionicLoading dialog can be hidden with a $interval call (adapting the code from the question):
$interval( function() {
$ionicLoading.show({
template: 'Async IonicLoading'
});
$interval( function() {
$ionicLoading.hide();
}, 5000, 1)
}, 5000 , 1);
2) The code to detect the asynchronous change is the following:
it('should only test when ionicLoading appears', function() {
browser.wait(function() {
var deferred = protractor.promise.defer();
var q = element(by.css('.loading-container.visible.active')).isPresent()
q.then( function (isPresent) {
deferred.fulfill(isPresent);
});
return deferred.promise;
}, 10000);
var ionicLoadingText = element(by.css('.loading-container.visible.active')).getText();
expect(ionicLoadingText).toEqual('Async IonicLoading');
})
it('should only test once ionicLoading disappears', function() {
browser.wait(function() {
var deferred = protractor.promise.defer();
var q = element(by.css('.loading-container.visible.active')).isPresent()
q.then( function (isPresent) {
deferred.fulfill(!isPresent);
});
return deferred.promise;
}, 10000);
expect(1).toEqual(1);
})
Then both tests pass.

SAPUI5 mixing mobile (sap.m) and desktop (sap.ui.commons)

I am working on a desktop SAPUI5 application and need to use TileContainer/Tiles in one of the page but noticed that press event is not working for this. Tried other mobile controls e.g. sap.m.Button press events but they are also not working.
Any idea?
Mobile controls will be work fine with touch events only. You need to set onclick events. You have 3 options to do this:
1) Attach onclick to target control:
var oButton = new sap.m.Button({
text : "Hello",
press : function() { alert('You've pressed me!') }
}).attachBrowserEvent('click',
function(event){
sap.ui.getCore().byId(event.target.id).firePress()
});
2) Extend standart mobile controls:
sap.m.Button.extend('my.Button');
my.Button.prototype.onclick = function(){
this.ontap.apply(this, arguments);
};
my.Button.prototype.onmousedown = function(){
this.ontouchstart.apply(this, arguments);
};
my.Button.prototype.onmousemove = function(){
this.ontouchmove.apply(this, arguments);
};
my.Button.prototype.onmouseup = function(){
this.ontouchend.apply(this, arguments);
};
3) Modify standart controls(not really good idea):
sap.m.Button.prototype.onclick = function(){
this.ontap.apply(this, arguments);
};
...
I was not adding sap.m in sap-ui-bootstrap, adding this made moible ui controls working.
data-sap-ui-libs="sap.ui.commons, sap.m"
thanks any way qmacro and Nikolay...

backbutton event not working on Intel XDK Crosswalk app

I put code below in my XDK project. I use onsenUI and Angular. Everything works great in the emulator but the Crosswalk app doesn't trigger this during backbutton event.
Is there anything else that needs to be done? I can't find anything specific about this in the documentation. Thanks.
<script src="cordova.js" type="text/javascript"></script>
<script>
document.addEventListener ("backbutton", onBackKeyDown, false);
function onBackKeyDown () {
// Handle the back button
console.log("back");
//other codes here
}
</script>
It turns out you need to have this complete triggers for it to work:
// Wait for device API libraries to load
//
function onLoad() {
document.addEventListener("deviceready", onDeviceReady, false);
}
// device APIs are available
//
function onDeviceReady() {
// Register the event listener
document.addEventListener("backbutton", onBackKeyDown, false);
}
// Handle the back button
//
function onBackKeyDown() {
// Handle the back button
}
You can use this function directly to intercept back button
document.addEventListener("intel.xdk.device.hardware.back", function() {
// write your code
}, false);

iPhone Safari Web App opens links in new window

I have problem with web after adding icon to Home Screen. If the web is launched from Home Screen, all links will open in new window in Safari (and lose full screen functionality). How can I prevent it? I couldn't find any help, only the same unanswered question.
I found JavaScript solution in iWebKit framework:
var a=document.getElementsByTagName("a");
for(var i=0;i<a.length;i++)
{
a[i].onclick=function()
{
window.location=this.getAttribute("href");
return false
}
}
The other solutions here either don't account for external links (that you probably want to open externally in Safari) or don't account for relative links (without the domain in them).
The html5 mobile-boilerplate project links to this gist which has a good discussion on the topic: https://gist.github.com/1042026
Here's the final code they came up with:
<script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(d.href.indexOf("http")||~d.href.indexOf(e.host))&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone")</script>
If you are using jQuery, you can do:
$("a").click(function (event) {
event.preventDefault();
window.location = $(this).attr("href");
});
This is working for me on iOS 6.1 and with Bootstrap JS links (i.e dropdown menus etc)
$(document).ready(function(){
if (("standalone" in window.navigator) && window.navigator.standalone) {
    // For iOS Apps
    $('a').on('click', function(e){
      e.preventDefault();
      var new_location = $(this).attr('href');
      if (new_location != undefined && new_location.substr(0, 1) != '#' && $(this).attr('data-method') == undefined){
        window.location = new_location;
      }
    });
    }
});
This is an old question and many of the solutions here are using javascript. Since then, iOS 11.3 has been released and you can now use the scope member. The scope member is a URL like "/" where all paths under that scope will not open a new page.
The scope member is a string that represents the navigation scope of
this web application's application context.
Here is my example:
{
"name": "Test",
"short_name": "Test",
"lang": "en-US",
"start_url": "/",
"scope": "/",
...
}
You can also read more about it here. I also recommend using the generator which will provide this functionality.
If you specify the scope, everything works as expected similar to
Android, destinations out of the scope will open in Safari — with a
back button (the small one in the status bar) to your PWA.
Based on Davids answer and Richards comment, you should perform a domain check. Otherwise links to other websites will also opened in your web app.
$('a').live('click', function (event)
{
var href = $(this).attr("href");
if (href.indexOf(location.hostname) > -1)
{
event.preventDefault();
window.location = href;
}
});
If using jQuery Mobile you will experience the new window when using the data-ajax='false' attribute. In fact, this will happen whenever ajaxEnabled is turned off, being by and external link, by a $.mobile.ajaxEnabled setting or by having a target='' attribute.
You may fix it using this:
$("a[data-ajax='false']").live("click", function(event){
if (this.href) {
event.preventDefault();
location.href=this.href;
return false;
}
});
(Thanks to Richard Poole for the live() method - wasn't working with bind())
If you've turned ajaxEnabled off globally, you will need to drop the [data-ajax='false'].
This took me rather long to figure out as I was expecting it to be a jQuery Mobile specific problem where in fact it was the Ajax linking that actually prohibited the new window.
This code works for iOS 5 (it worked for me):
In the head tag:
<script type="text/javascript">
function OpenLink(theLink){
window.location.href = theLink.href;
}
</script>
In the link that you want to be opened in the same window:
Link
I got this code from this comment: iphone web app meta tags
Maybe you should allow to open links in new window when target is explicitly set to "_blank" as well :
$('a').live('click', function (event)
{
var href = $(this).attr("href");
// prevent internal links (href.indexOf...) to open in safari if target
// is not explicitly set_blank, doesn't break href="#" links
if (href.indexOf(location.hostname) > -1 && href != "#" && $(this).attr("target") != "_blank")
{
event.preventDefault();
window.location = href;
}
});
I've found one that is very complete and efficient because it checks to be running only under standalone WebApp, works without jQuery and is also straightforward, just tested under iOS 8.2 :
Stay Standalone: Prevent links in standalone web apps opening Mobile Safari
You can also do linking almost normally:
TEXT OF THE LINK
And you can remove the hash tag and href, everything it does it affects appearance..
This is what worked for me on iOS 6 (very slight adaptation of rmarscher's answer):
<script>
(function(document,navigator,standalone) {
if (standalone in navigator && navigator[standalone]) {
var curnode,location=document.location,stop=/^(a|html)$/i;
document.addEventListener("click", function(e) {
curnode=e.target;
while (!stop.test(curnode.nodeName)) {
curnode=curnode.parentNode;
}
if ("href" in curnode && (curnode.href.indexOf("http") || ~curnode.href.indexOf(location.host)) && curnode.target == false) {
e.preventDefault();
location.href=curnode.href
}
},false);
}
})(document,window.navigator,"standalone")
</script>
This is slightly adapted version of Sean's which was preventing back button
// this function makes anchor tags work properly on an iphone
$(document).ready(function(){
if (("standalone" in window.navigator) && window.navigator.standalone) {
// For iOS Apps
$("a").on("click", function(e){
var new_location = $(this).attr("href");
if (new_location != undefined && new_location.substr(0, 1) != "#" && new_location!='' && $(this).attr("data-method") == undefined){
e.preventDefault();
window.location = new_location;
}
});
}
});
For those with Twitter Bootstrap and Rails 3
$('a').live('click', function (event) {
if(!($(this).attr('data-method')=='delete')){
var href = $(this).attr("href");
event.preventDefault();
window.location = href;
}
});
Delete links are still working this way.
I prefer to open all links inside the standalone web app mode except ones that have target="_blank". Using jQuery, of course.
$(document).on('click', 'a', function(e) {
if ($(this).attr('target') !== '_blank') {
e.preventDefault();
window.location = $(this).attr('href');
}
});
One workaround i used for an iOS web app was that I made all links (which were buttons by CSS) form submit buttons. So I opened a form which posted to the destination link, then input type="submit"
Not the best way, but it's what I figured out before I found this page.
I created a bower installable package out of #rmarscher's answer which can be found here:
http://github.com/stylr/iosweblinks
You can easily install the snippet with bower using bower install --save iosweblinks
For those using JQuery Mobile, the above solutions break popup dialog. This will keep links within webapp and allow for popups.
$(document).on('click','a', function (event) {
if($(this).attr('href').indexOf('#') == 0) {
return true;
}
event.preventDefault();
window.location = $(this).attr('href');
});
Could also do it by:
$(document).on('click','a', function (event){
if($(this).attr('data-rel') == 'popup'){
return true;
}
event.preventDefault();
window.location = $(this).attr('href');
});
Here is what I'd use for all links on a page...
document.body.addEventListener(function(event) {
if (event.target.href && event.target.target != "_blank") {
event.preventDefault();
window.location = this.href;
}
});
If you're using jQuery or Zepto...
$("body").on("click", "a", function(event) {
event.target.target != "_blank" && (window.location = event.target.href);
});
You can simply remove this meta tag.
<meta name="apple-mobile-web-app-capable" content="yes">