window.addeventlistener in firefox does not fire event on http status 302 - angularjs

I am trying to get an authentication script working. It has been supplied by my company, as it is what they are using in other systems. I am having an odd inconsistent behavior between chrome and firefox v19 (what is standard in our desktop environments currently).
The process is pretty simple: we create an iframe, which is pointed to a SAML service. I have an angularJS SPA that is waiting for that SAML service to respond with a JSON object that will tell my app if the user is authenticated or not. Then we either run our app (using angular.bootstrap(document, ['mySPA']); or do something else if unauthorized.
The code in question is this:
(function createIframe() {
var iframe = document.createElement("iframe");
setAttributes(iframe, {
"name": "auth",
"id": "myFrame",
"src": "https://api.SAML2AuthService",
"height": "0",
"width": "0",
"border": "0"
});
document.body.appendChild(iframe);
// Create IE + others compatible event handler
authEventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
authEvent = window[authEventMethod];
authMessageEvent = authEventMethod == "attachEvent" ? "onmessage" : "message";
})();
// Listen to auth iframe message
authEvent(authMessageEvent, function (e) {
var authorized = false;
for (var i = 0; i < 2; i++) {
Authentication = Auth.getInstance();
if (e.data !== null) {
data = e.data;
if (data.isAuthorized === "true" && data.authorizationToken !== null) {
Authentication.isAuthorized = e.data.isAuthorized;
Authentication.principal = e.data.principal;
Authentication.description = e.data.description;
Authentication.authorizationToken = e.data.authorizationToken;
authorized = true;
break;
}
}
}
if (!authorized) {
console.log("Unauthorized");
}
}, false);
Then, we call:
angular.element(document).ready(function() {
angular.module( 'mySPA', []
...
});
angular.bootstrap(document, ['associateDesktop']);
});
However, for reasons beyond my control, the SAML service performs a redirect to get the actual credentials. My browser's debug console shows these as HTTP Status 302, then (I assume) redirected and returned to me as HTTP Status 200.
Specifically, my question is that the AuthEvent event that I attach to window is not always getting fired off. In chrome, if I clear all browsing data (cookies, etc) the authEvent fires, and I get authenticated (or not) as I would expect. In Firefox, if I clear all cached data, the authEvent never gets fired. Am I attaching the event wrong? Does Firefox not call an event like this for a 302? Does angular's ready() function do something I'm not expecting (being impatient)?
Thanks in advance!

This same code now works in FF 19. I changed nothing, and I ended up finding out after-the-fact that the service was returning some slightly malformed data that apparently chrome was able to handle gracefully but firefox wasn't. That malformed data has been fixed, so now the code works. I no longer have access to the original (allegedly bad) content that was being sent to the browser, so I can't post it here to show a helpful bug and solution.
However, I wanted to at least record that the above code works fine, and post a simpler version here so anyone looking for code that can be used has something to go if. Sorry I can't give a better answer of what the actual issue was.
Parent html
<html>
<script>
var authEvent = function(event) {
// debugger;
var div = document.getElementById("response");
div.innerHTML = event.data.message;
};
if (window.addEventListener) {
window.addEventListener("message", authEvent, false);
}
else {
window.attachEvent("onmessage", authEvent);
}
</script>
<body>
<iframe src="frame.html"></iframe>
<br /><br /><br />
<div id="response">No response...</div>
</body>
iFrame html
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script>
var authResponse = {
"message": "Iframe called parent successfully!"
};
window.onload = function() {
parent.postMessage(authResponse,"*");
};
</script>
</head>
<body>
Child iFrame....
</body>
</html>

Related

Shaka Player Start Video in full screen

I have the basic shaka player code. I want to start the video on full screen. Please tell me if it is possible.
HTML
<!DOCTYPE html>
<html style="height:100%">
<head>
<!-- Shaka Player compiled library: -->
<script src="dist/shaka-player.compiled.js"></script>
<!-- Your application source: -->
<script src="myapp.js"></script>
</head>
<body style="height:100%">
<video id="video"
width="100%"
height="100%"
poster="//shaka-player-demo.appspot.com/assets/poster.jpg"
controls autoplay></video>
</body>
</html>
myapp.js
// myapp.js
var manifestUri =
'./asd.mp4';
function initApp() {
// Install built-in polyfills to patch browser incompatibilities.
shaka.polyfill.installAll();
// Check to see if the browser supports the basic APIs Shaka needs.
if (shaka.Player.isBrowserSupported()) {
// Everything looks good!
initPlayer();
} else {
// This browser does not have the minimum set of APIs we need.
console.error('Browser not supported!');
}
}
function initPlayer() {
// Create a Player instance.
var video = document.getElementById('video');
var player = new shaka.Player(video);
// Attach player to the window to make it easy to access in the JS console.
window.player = player;
// Listen for error events.
player.addEventListener('error', onErrorEvent);
// Try to load a manifest.
// This is an asynchronous process.
player.load(manifestUri).then(function() {
// This runs if the asynchronous load is successful.
console.log('The video has now been loaded!');
}).catch(onError); // onError is executed if the asynchronous load fails.
}
function onErrorEvent(event) {
// Extract the shaka.util.Error object from the event.
onError(event.detail);
}
function onError(error) {
// Log the error.
console.error('Error code', error.code, 'object', error);
}
document.addEventListener('DOMContentLoaded', initApp);
I did this using the below code
player.load(manifestUri).then(function() {
// This runs if the asynchronous load is successful.
console.log('The video has now been loaded!');
video.requestFullscreen().catch(err => {
console.log(err)
});
}).catch(onError); // onError is executed if the asynchronous load fails.
Please let me know if there is a better solution

ng-show and/or ng-if do not function 100% of the time

I have a Chrome extension uses an ng-show expression that checks a variable of Chrome storage, and displays a big blue button if the value is at zero. When opening the extension, however, the button could show up on the first click, or you may have to close and reopen the extension several times before it shows up (simply showing a blank body). This has been incredibly frustrating and is obviously a UX problem that I would like to fix before I publish the extension to the public.
Here is the div code from within the main view of the extension:
<div id="no_vseeks" ng-show="vseeks.length === 0">
<div class="big-button-container"><h1>CREATE</h1></div>
</div>
The expression is referring to an array called 'vseeks' in the Chrome local storage.
And here is what the extension is supposed to output:
But this is what the extension will show (seemingly) at random.
Please inform me if I need to include more code or images.
EDIT: Here's the main controller where the vSeeks array is being retrieved from Chrome storage. The console logs show that after the chrome.storage.get function is called, the array is present, but yet I still get a blank view.
app.controller('mainController', function($scope, $window) {
$scope.toggleAcc = function($event) {
var currentAcc = $event.currentTarget;
currentAcc.classList.toggle("active");
var panel = currentAcc.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
$scope.sendID = function(id) {
currentVID = id;
$window.location.href = "#!delete";
}
var noVseeks;
var home_button;
var newV_button;
console.log('controller reached', $scope.vseeks);
chrome.storage.sync.get('userData', function(items){
$scope.vseeks = items.userData.vSeeks;
console.log('inside chrome storage get', $scope.vseeks);
home_button = document.getElementById('home_button');
newV_button = document.getElementById('newV_button');
console.log('variables: ', home_button, newV_button);
if ($scope.vseeks.length < 1) {
home_button.style.visibility = "hidden";
newV_button.style.visibility = "hidden";
}
else {
newV_button.style.visibility = "visible";
if (home_button.style.visibility == "visible") {
home_button.style.visibility = "hidden";
}
}
});
});
I am unfamiliar with Chrome.storage.sync but it must be returning a non-angularjs promise (i.e. not $q). In that scenario, the function you are running upon resolve is executing outside of the angular digest cycle -- angular doesn't know it should be doing anything. The way to force angular to run its cycle is to use $scope.$apply. This will synchronize the model to the view and vice versa.

How to add a custom error page in Cordova InAppBrowser or hide the error url?

pleas check this attached image I'm building an Ionic Android app with the InAppBrowser plugin. When the internet connection is not available, the plugin shows web page not available and requesting url.
Please help me customise the InAppBrowser error page (404 page). Or help me hide the requesting url.
Thank you.
I think I misunderstood your problem, first time, sorry about that. I'm reading again your problem and I'm figuring out what's happening. You need to add a custom configuration at config.xml to redirect to an error page when Cordova detect it. I hope this solve your problem.
<preference name="ErrorUrl" value="myErrorPage.html"/>
The original response works when you want to open a link through Cordova inAppBrowser plugin. If this doesn't sort out your problem, please reformulate your question.
Original response
You could be listening inAppBrowser events to figure what's happening.
Here, you can see how listen browser events, such as loaderror and manage the 404 error as you want. You must save a reference to inAppBrowser when open method is called, and then you could listen for error event.
function loadErrorCallBack(params) {
// Do stuff
}
inAppBrowserRef = cordova.InAppBrowser.open(url, target, options);
inAppBrowserRef.addEventListener('loaderror', loadErrorCallBack);
I am using Ionic 4 and I couldn’t manage to make the solution based on config.xml editing to work :
preference name="ErrorUrl" value="myErrorPage.html"/
Placing an addEventListener on loaderror didn’t work neither. It looks like it is not triggered by http errors and the plugin need a fix.
But we found a hack that is much simpler.
On loadstop we wait 500 milliseconds and then we get the loaded url by triggering executeScript with and window.location.href
If the loaded url is of the custom error page, in Cordova (not in IAB) we display a custom message with a back button.
It's a hack but that cover the requirement for now
I just came across the same problem and here's what I did. The code is for Android and works on IOS as well. But you would want to remove navigator.app.exitApp(); for IOS as Apple does not allow apps to take exit without pressing the home button.
Let me know if this works for you. It will hide default error page and open your custom error page. Write your own error code in myerrorpage.html
document.getElementById("openBrowser").addEventListener("click", openBrowser);
document.addEventListener("offline", onOffline, false);
function onOffline(e) {
e.preventDefault();
var src = 'myErrorPage.html';
var target = '_blank';
var option = "loaction=no, toolbar=no, zoom=no, hidden=yes, hardwareback=no";
var ref = cordova.InAppBrowser.open(src, target, option);
alert('Your device is Offline. Please check your connection and try again.');
navigator.app.exitApp();
}
function openBrowser() {
var url = 'https://www.yourlink.com';
var target = '_self';
var options = "location=no,toolbar=no,zoom=no, hardwareback=no, hidden=yes" ;
var ref = cordova.InAppBrowser.open(url, target, options);
}
When the components do not work, I perform the following procedure
ionic state reset
ionic platform remove android
ionic platform remove ios
ionic platform add android
ionic platform add ios
and try with ionicPlatform ready
<button class="button button-balanced" ng-click="OpenBrowser()">Test</button>
In controller
$scope.OpenBrowser = undefined;
$ionicPlatform.ready(function () {
$scope.OpenBrowser = function () {
$cordovaInAppBrowser.open('http://ngcordova.com', '_blank', options)
.then(function (event) {
})
.catch(function (event) {
$scope.Error = event;
});
};
});
I couldn't manage solution with setting ErrorUrl in Ionic 4 on Android to work.
Finally I came up with another solution - hide default error page and redirect user to any page (I use last page from event.url).
constructor(private iab: InAppBrowser) {
}
private openUrl(url: string)
{
this.platform.ready().then(() => {
if (this.platform.is('cordova')) {
this.openBrowser(url);
}
});
}
private openBrowser(url: string): InAppBrowserObject
{
const options: InAppBrowserOptions = {
location: 'no',
zoom: 'no',
hidden: 'no'
};
const browser = this.iab.create(url, '_blank', options);
browser.on('loaderror').subscribe(
event => this.onLoadError(event, browser)
);
return browser;
}
private onLoadError(event: InAppBrowserEvent, browser: InAppBrowserObject): void
{
browser.executeScript({
code: `
window.addEventListener('DOMContentLoaded', function () {
document.querySelector('body').style.background = 'black';
document.querySelector('body').innerHTML = '';
}, true);
window.addEventListener('load', function () {
window.location.replace('${event.url}');
}, true);
`,
}
).then();
}
Changing background and redirecting is tricky - from my experiments using injectCss won't work, because body is generated in the meantime. Using DOMContentLoader makes it black and clears text on screen.
But redirecting won't work in DOMContentLoader (don't ask me why), so you need to use load event.
It works great when user is using hardware back and returns to POST request - this way he will be redirected to GET of the same url (but you can use any url you want).

How to call Google Cloud Endpoints with AngularJs when the page Loads, to get user information(PICTURE, NAME..)

I am trying to make a post request using Google Cloud Endpoints and AngularJS when the page loads so I can get the user information and fill the profile picture, profile description and so on...
I am able to run requests when pressing a button or something like that but can't call the google endpoints automatically when the page loads and that is whats I am trying to achieve.
Below is the HTML part where the {{userPicture}} should've been loaded in the angular script:
(HTML)
<div class="form-group">
<label class="col-sm-3 control-label">Profile image</label>
<div class="col-sm-9" ng-controller='initController'>
<img src="{{userPicture}}" class="user-image-profile" alt="User Image">
</div>
</div>
(ANGULAR)
controllers.initController = function($scope, $http){
$scope.userForm = {
"userEmail" : $.cookie('auth')
};
gapi.client.igardenendpoints.getProfile($scope.userForm).execute(function(resp) {
$scope.$apply(function () {
if (resp.error) {
$scope.backmessage.messagetext = "GetProfile Error!"
console.log("error");
} else {
if (resp.userEmail == "TEMPLATE"){
$scope.backmessage.messagetext = "Error please try again!"
}else{
$scope.userPicture = 'https://filiperebollo1986.appspot.com/serve?blob-key=' + resp.profilePicKey;
}
}
});
});
}
error
I also tried to use the following:
$scope.initData = function () {
gapi.client.igardenendpoints.getProfile($scope.userForm)...........
}
and run the function at the end of the controller, like:
$scope.initData();
But both does not work, any help on that?
I will not be able to help you in 100% as I'm not using Google Cloud, but will try to do my best.
First of all, to get the data it's usually better to use services rather than do it in the controller.
But anyway, your problem seems to be different. In your HTML did you include your script and client API?
I was able to fix my problem and bellow is the solution:
The problem was that at the moment of my call, the script may not have been loaded once I was using the "ng-app" directive directly on the body TAG.
Now I am injecting the angular module dinamicaly just after my API loading:
function googleOnLoadCallback(){
var apisToLoad = 1; // must match number of calls to gapi.client.load()
var gCallback = function() {
if (--apisToLoad == 0) {
//Manual bootstraping of the application
var $injector = angular.bootstrap(document, ['authModule']);
console.log('Angular bootstrap complete ' + gapi);
};
};
gapi.client.load('igardenendpoints', 'v12', gCallback, '//' + window.location.host + '/_ah/api');
}
</script>
<script src="https://apis.google.com/js/client.js?onload=googleOnLoadCallback"></script>
And now It is working!!!!
The only problem now is that when the page loads it appears the {{example}} in the page, is it possible to avoid the {{}} to appear?

Cannot get YouTube video to play inside a Windows.Forms.WebBrowser control

I tried to simpliy assign the following getting started HTML code to the DocumentText property of the WebBrowser control.
<!DOCTYPE html>
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
</body>
</html>
This gives me the following script error at runtime:
It turns out that even the following simplified code produces the same error:
webBrowser1.DocumentText = "<!DOCTYPE html><html><body><script src='https://www.youtube.com/iframe_api'></script></body></html>";
So it looks like the WebBrowser control is not able to load the iframe-API. What could be the problem here? Or how could I investigate this error further?
I found the solution for WebBrowser. First we have to force WebBrowser running with the latest IE which we have on our machine like this.
Second I have to stream HTML through ASP.NET Web API and Katana like this, using WebBrowser to navigate to http://localhost:xxxx/api/xxxx
Setting DocumentText won't work because WebBrowser has many security limitations when loading html locally.
The other simple solution is just use other browser engine like Gecko or CefSharp.

Resources