reCAPTCHA not loading properly in XHTML document - xhtml

I am writing an SHTML CSS & JS document into an XML document which uses an XHTML parser.
When I try to load the captcha into it, it briefly shows up as a white box then disappears, never to be seen again inside the renderer.
I understand that this might be caused by the scripts being loaded in the wrong order but I don't have the luxury of the async defer keywords that are recommended by google simply because the parser won't accept them.
<script src="https://www.google.com/recaptcha/api.js" type="text/javascript"></script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance;
this.getStatus();
this.setOnConfirm();
this.setAdditionalProps();
}
setAdditionalProps() {
this.props.claimed = false;
this.props.claimTokensMessage = "Claim free DAI, DeFi & ETH tokens";
this.props.claimedMessage = "You have already claimed DAI, DeFi & ETH tokens, stay posted for new freebies!";
this.props.serverError = "Server Error, please try again later";
this.props.success = "ETH, DeFi & DAI tokens will be sent to your address shortly!";
this.props.fillCaptchaMessage = "Please click the captcha below to receive the tokens";
}
getBaseURL() {
return "http://192.168.26.189:8080/api/"
}
getStatus() {
let suffix = "claimed?userAddress=" + this.props.ownerAddress;
fetch(this.getBaseURL() + suffix).then((res) => {
if(parseInt(res.status) === 200) {
document.getElementById("message").innerHTML = this.props.claimTokensMessage;
} else if(parseInt(res.status) === 412) {
this.props.claimed = true;
document.getElementById("message").innerHTML = this.props.claimedMessage;
} else {
document.getElementById("message").innerHTML = this.props.serverError;
}
}).catch((err) => {
document.getElementById("message").innerHTML = err;
window.onConfirm = function() { window.close() };
});
}
setOnConfirm() {
window.onConfirm = () => {
if(this.props.claimed) {
window.close();
} else {
web3.personal.sign({ data: "To receive free tokens, you must reveal your public address to a smart contract. Is that ok?" }, (err, val) => {
if(err) { throw err; }
//user completes the request by filling the captcha
document.getElementById("message").innerHTML = this.props.success;
document.getElementById("captcha").submit();
window.onConfirm = function () { window.close(); };
});
}
};
}
render() {
let suffix = "discover?userAddress=" + this.props.ownerAddress;
return`
<div class="ui container">
<div class="ui segment">
<img src="data:image/png;base64,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">
<h3 id="message"></h3>
<form action=${this.getBaseURL() + suffix} id="captcha" method="post">
<button class="g-recaptcha" data-sitekey="6LeK070UAAAAAHuzSEGgoqbuLGuJq-GRDd-LA4kH" data-callback="onSubmit" hidden>fill captcha</button>
</form>
</div>
</div>
`;
}
}
web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>

Related

Simple pug html form, make it send immediately on change of value rather than wait for submit button

I have a very simple pug file:
for item in itemList
form(method='post', action='/change')
table
tr
td(width=100)
td(width=200)
| #{item.name}
input(type='hidden', name='field' value=item.name)
input(type='hidden', name='style' value='doublevalue')
td(width=100)
input(type='number', name='value' min=-20.0 max=80.00 step=0.01 value=+item.value)
td(width=100)
input(type='submit', value='Update')
p end
As you can see it produces a few trivial forms like this:
(Each form is one 'line' which is a simple table.)
(On the script side, it just reads each 'line' from a MySQL table, there are 10 or so of them.)
So on the www page, the user either
types in new number (say "8")
or clicks the small arrows (say Up, changing it to 7.2 in the example)
then the user must
click submit
and it sends the post.
Quite simply, I would like it to be that when the user
clicks a small arrows (say Up, changing it to 7.2 in the example)
it immediately sends a submit-post.
How do I achieve this?
(It would be fine if the send happens, any time the user types something in the field, and/or, when the user clicks the Small Up And Down Buttons. Either/both is fine.)
May be relevant:
My pug file (and all my pug files) have this sophisticated line of code as line 1:
include TOP.pug
And I have a marvellous file called TOP.pug:
html
head
style.
html {
font-family: sans-serif
}
td {
font-family: monospace
}
body
I have a solution with javascript.
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add event for each of them
document.querySelectorAll('input[type="number"]').forEach(function(el) {
el.addEventListener('change', function (e) {
// on change submit the parent (closest) form
e.currentTarget.closest('form').submit()
});
});
}
Actually it is short but if you want to support Internet Explorer you have to add the polyfill script too. Internet Explorer does not support closest() with this snippet below we teach it.
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
Ajax form submit to node.js
If you are interested in an ajax solution I put some code below just to blow your mind ;-) It should work instantly, I use it on one of my sites. You could use jQuery and save lines of code but I like it pure. (The ajax function and polyfills are utils so paste it anywhere)
HTML (example)
<form>
<input type="hidden" name="field" value="field1">
<input type="hidden" name="style" value="style1">
<input type="number" name="value">
<input type="submit" value="update">
</form>
<form>
<input type="hidden" name="field" value="field2">
<input type="hidden" name="style" value="style2">
<input type="number" name="value">
<input type="submit" value="update">
</form>
Javascript: event listener and prepare ajax call (note the callbacks).
// check if there are forms to prevent errors
if (document.querySelector('form')) {
// add submit event for each form
document.querySelectorAll('form').forEach(function (el) {
el.addEventListener('submit', function (e) {
e.currentTarget.preventDefault();
submitData(e.currentTarget);
});
});
}
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add change event for each of them
document.querySelectorAll('input[type="number"]').forEach(function (el) {
el.addEventListener('change', function (e) {
submitData(e.currentTarget.closest('form'));
});
});
}
// collect form data and send it
function submitData(form) {
// send data through (global) ajax function
ajax({
url: '/change',
method: 'POST',
data: {
field: form.querySelector('input[name="field"]').value,
style: form.querySelector('input[name="style"]').value,
value: form.querySelector('input[name="value"]').value,
},
// callback on success
success: function (response) {
// HERE COMES THE RESPONSE
console.log(response);
// error is defined in (node.js res.json({error: ...}))
if (response.error) {
// make something red
form.style.border = '1px solid red';
}
if (!response.error) {
// everything ok, make it green
form.style.border = '1px solid green';
}
// remove above styling
setTimeout(function () {
form.style.border = 'none';
}, 1000);
},
// callback on error
error: function (error) {
console.log('server error occurred: ' + error)
}
});
}
As told javascript utils (paste it anywhere like a library)
// reusable ajax function
function ajax(obj) {
let a = {};
a.url = '';
a.method = 'GET';
a.data = null;
a.dataString = '';
a.async = true;
a.postHeaders = [
['Content-type', 'application/x-www-form-urlencoded'],
['X-Requested-With', 'XMLHttpRequest']
];
a.getHeaders = [
['X-Requested-With', 'XMLHttpRequest']
];
a = Object.assign(a, obj);
a.method = a.method.toUpperCase();
if (typeof a.data === 'string')
a.dataString = encodeURIComponent(a.data);
else
for (let item in a.data) a.dataString += item + '=' + encodeURIComponent(a.data[item]) + '&';
let xhReq = new XMLHttpRequest();
if (window.ActiveXObject) xhReq = new ActiveXObject('Microsoft.XMLHTTP');
if (a.method == 'GET') {
if (typeof a.data !== 'undefined' && a.data !== null) a.url = a.url + '?' + a.dataString;
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.getHeaders.length; x++) xhReq.setRequestHeader(a.getHeaders[x][0], a.getHeaders[x][1]);
xhReq.send(null);
}
else {
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.postHeaders.length; x++) xhReq.setRequestHeader(a.postHeaders[x][0], a.postHeaders[x][1]);
xhReq.send(a.dataString);
}
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
let response;
try {
response = JSON.parse(xhReq.responseText)
} catch (e) {
response = xhReq.responseText;
}
//console.log(response);
if (xhReq.status == 200) {
obj.success(response);
}
else {
obj.error(response);
}
}
}
}
// (one more) polyfill for Object.assign
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
// .length of function is 2
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
In node.js (e.g. express route)
// the route in node.js
app.post('/change', (req, res) => {
// your logic here
let field = req.body.field;
let style = req.body.style;
let value = req.body.value;
// ...
// response result
res.json({
databaseError: false, // or true
additionalStuff: 'message, markup and other things ...',
});
});

Integrate Firebase authentication in an AngularDart app

I can not find a clear and complete explanation on how to integrate Firebase authentication (Google, e-mail, phone, ...) into an AngularDart (version 5) app.
Can you give it to me? Or, can you tell me where to find it?
Thank you!
firebase_dart_ui works for me. The repository contains an example, too.
Likewise. I spent a long time trying to find something...anything. While new to Angular Dart these examples that actually worked where a good find. The repo has examples for simple auth + phone and storage etc.
The md talks a little about what you need to setup in the Firebase console, you'll need to allow your host access for the Firebase generated keys in cloud console as well.
As Gazihan mentioned, the firebase_dart_ui package will do signing in with Google etc if you want to use Firebase UI, agreed, it's hard to follow in terms of finding steps. I had to change dev dependencies to get it to working but it did:
dev_dependencies:
build_runner: ^1.7.0
build_test: ^0.10.8
build_web_compilers: ^2.4.0
The following user/pwd signin example from the FirebaseDart repo is more straight forward and could help.
First, get your App details from your projects Firebase settings page.
index.dart
import 'dart:convert';
import 'dart:html';
import 'package:firebase/firebase.dart' as fb;
main() async {
try {
fb.initializeApp(
apiKey: "your api key",
authDomain: "your auth domain",
databaseURL: "your database url",
storageBucket: "your storage bucket");
AuthApp();
} on fb.FirebaseJsNotLoadedException catch (e) {
print(e);
}
}
class AuthApp {
final fb.Auth auth;
final FormElement registerForm;
final InputElement email, password;
final AnchorElement logout;
final TableElement authInfo;
final ParagraphElement error;
final SelectElement persistenceState, verifyEmailLanguage;
final ButtonElement verifyEmail;
final DivElement registeredUser, verifyEmailContainer;
AuthApp()
: this.auth = fb.auth(),
this.email = querySelector("#email"),
this.password = querySelector("#password"),
this.authInfo = querySelector("#auth_info"),
this.error = querySelector("#register_form p"),
this.logout = querySelector("#logout_btn"),
this.registerForm = querySelector("#register_form"),
this.persistenceState = querySelector("#persistent_state"),
this.verifyEmail = querySelector('#verify_email'),
this.verifyEmailLanguage = querySelector('#verify_email_language'),
this.registeredUser = querySelector("#registered_user"),
this.verifyEmailContainer = querySelector("#verify_email_container") {
logout.onClick.listen((e) {
e.preventDefault();
auth.signOut();
});
this.registerForm.onSubmit.listen((e) {
e.preventDefault();
var emailValue = email.value.trim();
var passwordvalue = password.value.trim();
_registerUser(emailValue, passwordvalue);
});
// After opening
if (auth.currentUser != null) {
_setLayout(auth.currentUser);
}
// When auth state changes
auth.onAuthStateChanged.listen(_setLayout);
verifyEmail.onClick.listen((e) async {
verifyEmail.disabled = true;
verifyEmail.text = 'Sending verification email...';
try {
// you will get the verification email in selected language
auth.languageCode = _getSelectedValue(verifyEmailLanguage);
// url should be any authorized domain in your console - we use here,
// for this example, authDomain because it is whitelisted by default
// More info: https://firebase.google.com/docs/auth/web/passing-state-in-email-actions
await auth.currentUser.sendEmailVerification(
fb.ActionCodeSettings(url: "followmyvoyage.firebaseapp.com"));
verifyEmail.text = 'Verification email sent!';
} catch (e) {
verifyEmail
..text = e.toString()
..style.color = 'red';
}
});
}
_registerUser(String email, String password) async {
if (email.isNotEmpty && password.isNotEmpty) {
var trySignin = false;
try {
// Modifies persistence state. More info: https://firebase.google.com/docs/auth/web/auth-state-persistence
var selectedPersistence = _getSelectedValue(persistenceState);
await auth.setPersistence(selectedPersistence);
await auth.createUserWithEmailAndPassword(email, password);
} on fb.FirebaseError catch (e) {
if (e.code == "auth/email-already-in-use") {
trySignin = true;
}
} catch (e) {
error.text = e.toString();
}
if (trySignin) {
try {
await auth.signInWithEmailAndPassword(email, password);
} catch (e) {
error.text = e.toString();
}
}
} else {
error.text = "Please fill correct e-mail and password.";
}
}
String _getSelectedValue(SelectElement element) =>
element.options[element.selectedIndex].value;
void _setLayout(fb.User user) {
if (user != null) {
registerForm.style.display = "none";
registeredUser.style.display = "block";
email.value = "";
password.value = "";
error.text = "";
var data = <String, dynamic>{
'email': user.email,
'emailVerified': user.emailVerified,
'isAnonymous': user.isAnonymous,
'metadata.creationTime': user.metadata.creationTime,
'metadata.lastSignInTime': user.metadata.lastSignInTime
};
data.forEach((k, v) {
if (v != null) {
var row = authInfo.addRow();
row.addCell()
..text = k
..classes.add('header');
row.addCell().text = "$v";
}
});
print('User.toJson:');
print(const JsonEncoder.withIndent(' ').convert(user));
verifyEmailContainer.style.display =
user.emailVerified ? "none" : "block";
} else {
registerForm.style.display = "block";
registeredUser.style.display = "none";
authInfo.children.clear();
}
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Auth demo</title>
<style type="text/css">
#register_form p {
color: red;
}
#auth_info td {
padding: 1px;
}
#auth_info td.header {
font-weight: bold;
text-align: right;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Auth demo</h1>
<form id="register_form" style="display: none">
<h2>Register</h2>
<p></p>
<label for="persistent_state">State persistence type</label>
<select id="persistent_state">
<option value="local">LOCAL</option>
<option value="session">SESSION</option>
<option value="none">NONE</option>
</select>
<br>
<input type="email" placeholder="Your E-mail" id="email">
<input type="password" placeholder="Your Password" id="password">
<input type="submit" value="Register me">
</form>
<div id="registered_user" style="display: none">
<table id="auth_info">
</table>
<div id="verify_email_container">
<h2>Send verify email</h2>
<label for="verify_email_language">Email language</label>
<select id="verify_email_language">
<option value="en">English</option>
<option value="cs">Czech</option>
<option value="de">German</option>
<option value="fr">French</option>
</select>
<button id="verify_email">Verify email</button>
</div>
Log out
</div>
</div>
<script src="https://www.gstatic.com/firebasejs/6.6.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js"></script>
<script defer src="index.dart.js" type="application/javascript"></script>
</body>
</html>
pubspec.yaml
dependencies:
firebase: ^5.0.0
http: '>=0.11.3 <0.13.0'
js: ^0.6.0
This answer is a bit all over the place, between the two examples talked about hopefully it's useful.

Youtube-Js-Api / How can I include the request’s response in my actual webpage?

I'm working on an app with both Firebase (web app) and the youtube API. The idea is to let users share their playlists and interact.
1) First, the user must identify himself. This part works very well (firebase part)
2) Then, the user must accept some conditions (the scopes) from the youtube API.
3) The Youtube API return the result of the request.
The issue is that youtube API recreate for every item of the array the HTML structure : HTML > HEAD > BODY. Plus, the response skips my header and display the all thing in a blank page instead of reacting like an include PHP (i know this is javascript but still.. ).
I know the solution rest in the function executerequest but i can't figurate how to do it.
The code of the request is in the middle of the body but for the purpose of my post, i did separate it.
var GoogleAuth;
var SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl';
function handleClientLoad() {
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
}
function initClient() {
// Retrieve the discovery document for version 3 of YouTube Data API.
// In practice, your app can retrieve one or more discovery documents.
var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest';
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client.init({
'apiKey': '...',
'discoveryDocs': [discoveryUrl],
'clientId': '....',
'scope': SCOPE
}).then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
var user = GoogleAuth.currentUser.get();
setSigninStatus();
// Call handleAuthClick function when user clicks on
// "Sign In/Authorize" button.
$('#sign-in-or-out-button').click(function() {
handleAuthClick();
});
$('#revoke-access-button').click(function() {
revokeAccess();
});
});
}
function handleAuthClick() {
if (GoogleAuth.isSignedIn.get()) {
// User is authorized and has clicked 'Sign out' button.
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
GoogleAuth.signOut();
} else {
// User is not signed in. Start Google auth flow.
GoogleAuth.signIn();
}
}
function revokeAccess() {
GoogleAuth.disconnect();
}
function setSigninStatus(isSignedIn) {
var user = GoogleAuth.currentUser.get();
var isAuthorized = user.hasGrantedScopes(SCOPE);
if (isAuthorized) {
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
$('#auth-status').html('Connecté ' +
' Granted');
defineRequest();
console.log('connecté');
} else {
$('#roomRed').html('display', 'block');
$('#sign-in-or-out-button').html('Sign In/Authorize');
$('#revoke-access-button').css('display', 'none');
$('#auth-status').html('Déconnecté' +
' Denied');
console.log('déconnecté');
}
// This helper method displays a message on the page.
}
function updateSigninStatus(isSignedIn) {
setSigninStatus();
}
function createResource(properties) {
var resource = {};
var normalizedProps = properties;
for (var p in properties) {
var value = properties[p];
if (p && p.substr(-2, 2) == '[]') {
var adjustedName = p.replace('[]', '');
if (value) {
normalizedProps[adjustedName] = value.split(',');
}
delete normalizedProps[p];
}
}
for (var p in normalizedProps) {
// Leave properties that don't have values out of inserted resource.
if (normalizedProps.hasOwnProperty(p) && normalizedProps[p]) {
var propArray = p.split('.');
var ref = resource;
for (var pa = 0; pa < propArray.length; pa++) {
var key = propArray[pa];
if (pa == propArray.length - 1) {
ref[key] = normalizedProps[p];
} else {
ref = ref[key] = ref[key] || {};
}
}
};
}
return resource;
}
function removeEmptyParams(params) {
for (var p in params) {
if (!params[p] || params[p] == 'undefined') {
delete params[p];
}
}
return params;
}
function executeRequest(request) {
request.execute(function(response) {
console.log(response);
for(var i = 0; i< response.items.length; i++){
console.log(response.items[i].player.embedHtml);
document.write(response.items[i].player.embedHtml);
}
});
}
function buildApiRequest(requestMethod, path, params, properties) {
params = removeEmptyParams(params);
var request;
if (properties) {
var resource = createResource(properties);
request = gapi.client.request({
'body': resource,
'method': requestMethod,
'path': path,
'params': params
});
} else {
request = gapi.client.request({
'method': requestMethod,
'path': path,
'params': params
});
}
executeRequest(request);
}
/***** END BOILERPLATE CODE *****/
function defineRequest() {
// See full sample for buildApiRequest() code, which is not
// specific to a particular youtube or youtube method.
buildApiRequest('GET',
'/youtube/v3/playlists',
{
'mine': 'true',
'maxResults': '25',
'part': 'snippet,contentDetails,player',
'onBehalfOfContentOwner': '',
'onBehalfOfContentOwnerChannel': ''
});
/*
buildApiRequest('GET',
'/youtube/v3/playlistItems',
{
'playlistId': "PLsvlo6Soc2pc2ZlereiehdPRhm0eKjSxI",
'maxResults': '25',
'part': 'snippet,contentDetails'
});
*/
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mes vidéo </title>
<style>
</style>
</head>
<body>
<button id="sign-in-or-out-button"
style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
style="display: none; margin-left: 25px">Revoke access</button>
<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>
<div id="video-container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body>
</html>
Thank you by advance

<a onclick"sth" .. cause IE11 warn and prompt for adding about:blank as Trusted Site

I have jqgrid on asp .NET web page.
When page is loaded and grid loads its data, after it receives json, before data is shown on grid, I get error message from IE:
Internet Explorer 11.0.9600.17728
It wants me to add about:blank to Trusted Sites.
When i click "close" rows appear.
Row`s html is as follows:
<a onclick="
OpenWindow('/13_1/Workflow.TasksWebPresUnit/TaskDetails/Index/?
taskDn=WFL///70000/.321360&isModal=True&
returnUrl=/13_1/Workflow.TasksWebPresUnit&
userId=5&
componentsToSet=test*testc', 'Details', '90%', '0', false, '¡',true);"
href="#">P01.07 Verification
</a>
No matter what I put in onclick, can be "blahblah", same with href, can be "foobar",
<a onclick="
abcd"
href="xyz">P01.07 Verification
</a>
i get that error window.
But, when I construct row's html that it not contain "onclick=sth", then i do not get this error.
Is there any way to stop IE from warning user or maybe I`m doing somethiong wrong?
Any help / clarification appreciated.
p.s. If i add about:blank to trusted sites, the problem is gone, but i don`t understand fully if this is secure solution.
Update 1: script
function OpenWindow(url, title, width, height, checkValue, multiSepar, showCloseButton) {
var progressIndImg = GLOBAL_CSS_PATH + '/Technology/modal/images/waiting.gif';
if (checkValue) {
var queryVals = parseQueryString(url);
var relatedComp = queryVals['componentToFill'];
var relatedVal = document.getElementById(relatedComp);
if (relatedVal.value != null && relatedVal.value != '') {
var win = dhtmlmodal.open('ModalBox', 'iframe', url, title, 'width=' + width + ', height=' + height + ',center=1,resize=1,scrolling=1', '', progressIndImg, showCloseButton);
win.onclose = function () {
return true;
}
}
} else {
var win = dhtmlmodal.open('ModalBox', 'iframe', url, title, 'width=' + width + ', height=' + height + ',center=1,resize=1,scrolling=1', '', progressIndImg, showCloseButton);
win.onclose = function () {
return true;
}
}
// } else {
// setInterval(checkForMessages, 200);
// }
// var ie7 = (navigator.appVersion.indexOf('MSIE 7.') == -1) ? false : true;
// if (ie7 != true) {
var onmessage = function (e) {
try {
var objects = JSON.parse(e.data);
if (window.addEventListener) {
window.removeEventListener('message', onmessage, false);
}
else if (window.attachEvent) {
window.detachEvent('onmessage', onmessage);
}
if (objects['methodName'] != null)
window[objects['methodName']](objects);
else
FillData(objects, true, multiSepar);
var close = objects['close'];
if (close == 'true') {
win.hide();
win.close();
}
}
catch (err) {
if (console)
console.error(err);
}
};
if (window.addEventListener) {
window.addEventListener('message', onmessage, false);
} else if (window.attachEvent) {
window.attachEvent('onmessage', onmessage);
}

Azure Media Player Silverlight fallback not working

I have used the azure media player with my project, it will play multiple adaptive bit rate streamed videos in an asp.net page, the best part is, it is working superb in html5 and flash but it will get stuck at spinner image in silverlight fallback.
Below is the code I have used.
I have also tried to get errors but it is not hitting the event listener code added for errors, but the play and pause events are working fine where flash and html5 is used, but silverlight fallback is not working at all.
<link href="https://amp.azure.net/libs/amp/1.3.0/skins/amp-default/azuremediaplayer.min.css" rel="stylesheet">
<script src="https://amp.azure.net/libs/amp/1.3.0/azuremediaplayer.min.js"></script>
<div class="marginBlock">
<h3>
<asp:Label ID="lblTitle" runat="server"><%=Title.ToString()%></asp:Label>
</h3>
<video id="<%=mediaPlayerID %>" class="azuremediaplayer amp-default-skin amp-big-play-centered">
<p class="amp-no-js">
To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML 5 video.
</p>
</video>
</div>
<p>
<asp:Label ID="lblDescription" runat="server"><%=Description.ToString()%>
</asp:Label>
</p>
<script>
$(document).ready(function () {
var playOptions = {
"nativeControlsForTouch": false,
techOrder: ['azureHtml5JS', 'flashSS', 'silverlightSS', 'html5'],
autoplay: false,
controls: true,
width: '100%',
height: '400',
logo: { enabled: false },
poster: "<%=ImageSelector%>"
}
var azurePlayer = amp('<%=mediaPlayerID%>', playOptions);
azurePlayer.src([{
src: "<%=VideoURL%>",
type: 'application/vnd.ms-sstr+xml'
}]);
azurePlayer.addEventListener("error", function () {
var errorDetails = azurePlayer.error();
var code = errorDetails.code;
var message = errorDetails.message;
alert(errorDetails + ' ' + code + " " + message);
if (azurePlayer.error().code & amp.errorCode.abortedErrStart) {
console.log("abortedErrStart");
}
else if (azurePlayer.error().code & amp.errorCode.networkErrStart) {
// MEDIA_ERR_NETWORK errors
console.log("networkErrStart");
}
else if (azurePlayer.error().code & amp.errorCode.decodeErrStart) {
// MEDIA_ERR_DECODE errors
console.log("decodeErrStart");
}
else if (azurePlayer.error().code & amp.errorCode.srcErrStart) {
// MEDIA_ERR_SRC_NOT_SUPPORTED errors
console.log("srcErrStart");
}
else if (azurePlayer.error().code & amp.errorCode.encryptErrStart) {
// MEDIA_ERR_ENCRYPTED errors
console.log("encryptErrStart");
}
else if (azurePlayer.error().code & amp.errorCode.srcPlayerMismatchStart) {
// SRC_PLAYER_MISMATCH errors
console.log("srcPlayerMismatchStart");
}
else {
// unknown errors
console.log("unknown");
}
});
azurePlayer.addEventListener('play', function () {
console.log('play');
});
azurePlayer.addEventListener('pause', function () {
console.log('pause');
});
});
Updated
Noticed I am getting following error for IE < 11.
Also I disabled the flash in firefox and removed the silverlight from techOrder, then it should hit the error event listener, it is not hitting.
This is also important for me to handle the analytics for error.
Play and Pause event listener are working fine.
Update 8/28/2015:
Fixed the JS error, it is because of multiple call to cdn of azure mentioned in link above, moved the code in master page and load it only once, browser like chrome handles duplicity of code easily but not IE.
After all the research I am lost why it is not working.
So added the following JS that will check for Silverlight and Flash and gracefully handle the error and update our analytics as well.
function getBrowserInformation() {
var ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return { name: 'IE ', version: (tem[1] || '') };
}
if (M[1] === 'Chrome') {
tem = ua.match(/\bOPR\/(\d+)/)
if (tem != null) { return { name: 'Opera', version: tem[1] }; }
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
if ((tem = ua.match(/version\/(\d+)/i)) != null) { M.splice(1, 1, tem[1]); }
return {
name: M[0],
version: M[1]
};};
function checkForAzureErrors() {
function isSilverlightInstalled() {
var isSilverlightInstalled = false;
try {
//check on IE
try {
var slControl = new ActiveXObject('AgControl.AgControl');
isSilverlightInstalled = true;
}
catch (e) {
//either not installed or not IE. Check Firefox/Safari
if (navigator.plugins["Silverlight Plug-In"]) {
isSilverlightInstalled = true;
}
}
}
catch (e) {
console.log(e);
}
return isSilverlightInstalled;
}
function isFlashInstalled() {
try {
return Boolean(new ActiveXObject('ShockwaveFlash.ShockwaveFlash'));
} catch (exception) {
return ('undefined' != typeof navigator.mimeTypes['application/x-shockwave-flash']);
}
}
function addErrorMessage() {
$($("#mediaPlayer.marginBlock").find('h3')).text('Media is not supported on this browser or device.');
$($("#mediaPlayer.marginBlock").find('video')).css('display', 'none');
$($("#mediaPlayer.marginBlock").find('p')).css('display', 'none');
$('.azuremediaplayer').css('display', 'none');
ga("send", "event", "Videos", "error",
getBrowserInformation().name + getBrowserInformation().version +
": is silverlight Installed " + isSilverlightInstalled() +
" and is Flash Installed " + isFlashInstalled());
}
function checkBrowser() {
if ((getBrowserInformation().name === 'MSIE' || getBrowserInformation().name === 'IE')) {
if (getBrowserInformation().version < 11) {
addErrorMessage();
}
} else if (getBrowserInformation().name === 'Firefox') {
addErrorMessage();
}
}
if ((getBrowserInformation().name === 'MSIE' || getBrowserInformation().name === 'IE')) {
if (getBrowserInformation().version < 9) { addErrorMessage() }
}
for (var key in amp.players) {
if (amp.players.hasOwnProperty(key)) {
if (isSilverlightInstalled()) {
if (!amp.players[key].isReady_) {
checkBrowser();
}
} else if (!isFlashInstalled()) {
checkBrowser();
}
}
}}
This function is called after 5 second of page load in document.ready function, giving it enough time to load and make the isReady_boolean true.
SetTimeout(function () { checkForAzureErrors(); }, 5000);
Still I am waiting for some angel to resolve this issue.
Updates: Partially Fixed
Need to add the xap refrences like older version, it will play silverlight but there is a catch, it will only work if you have one video per page.
<script>
amp.options.flashSS.swf = "http://amp.azure.net/libs/amp/1.3.0/techs/StrobeMediaPlayback.2.0.swf"
amp.options.flashSS.plugin = "http://amp.azure.net/libs/amp/1.3.0/techs/MSAdaptiveStreamingPlugin-osmf2.0.swf"
amp.options.silverlightSS.xap = "http://amp.azure.net/libs/amp/1.3.0/techs/SmoothStreamingPlayer.xap"
</script>
Fixed
As per comments from Amit Rajput
#Parshii Currently, as per the documentation, Azure Media Player doesn't support multi-instance playback. While it may work on some techs, it is not a tested scenario at this time. Please feel free to add it to the UserVoice forum (http://aka.ms/ampuservoice).
As per my testing it is working in html5 and flash but not Silverlight, for silverlight support we can try using iframes as per comments from rnrneverdies
Single Instance Media Player is working in all techs.
#Parshii Currently, as per the documentation, Azure Media Player doesn't support multi-instance playback. While it may work on some techs, it is not a tested scenario at this time. Please feel free to add it to the UserVoice forum (http://aka.ms/ampuservoice).
This may be not a complete answer, but could help you.
I made the following plugin for the Azure Media Player 1.3.0 which logs all the activity performed by the user and also the errors.
Set up it as:
var mylogFunction = function(data) { console.log(data); };
var options = {
techOrder: ["azureHtml5JS", "flashSS", "silverlightSS", "html5"],
nativeControlsForTouch: false,
loop: false,
logo: { enabled: false },
heuristicProfile: "Quick Start", //"High Quality", // could be "Quick Start"
customPlayerSettings: {
customHeuristicSettings: {
preRollInSec: 4,
windowSizeHeuristics: true
}
},
plugins: {
DebugLog: {
logFunction: mylogFunction
}
}
};
var amPlayer = amp("yourvideotagid", options);
Plugin Code:
var amp;
(function (amp) {
amp.plugin('DebugLog', DebugLog);
function DebugLog(options) {
var player = this;
var log = function (data) { console.log("Azure Media Player Log", data); }
if (options) {
if (options['logFunction']) {
log = options['logFunction'];
}
}
init();
function init() {
player.ready(handleReady);
player.addEventListener(amp.eventName.error, handleError);
}
function handleReady() {
player.addEventListener(amp.eventName.loadedmetadata, handleLoadedMetaData);
var data = {
ampVersion: "1.3.0",
appName: options['appName'],
userAgent: navigator.userAgent,
options: {
autoplay: player.options().autoplay,
heuristicProfile: player.options().heuristicProfile,
techOrder: JSON.stringify(player.options().techOrder)
}
};
logData("InstanceCreated", 1, data);
}
function handleError() {
var err = player.error();
var data = {
sessionId: player.currentSrc(),
currentTime: player.currentTime(),
code: "0x" + err.code.toString(16),
message: err.message
};
logData("Error", 0, data);
}
function handleLoadedMetaData() {
player.addEventListener(amp.eventName.playbackbitratechanged, handlePlaybackBitrateChanged);
player.addEventListener(amp.eventName.playing, handlePlaying);
player.addEventListener(amp.eventName.seeking, handleSeeking);
player.addEventListener(amp.eventName.pause, handlePaused);
player.addEventListener(amp.eventName.waiting, handleWaiting);
player.addEventListener(amp.eventName.ended, handleEnded);
if (player.audioBufferData()) {
player.audioBufferData().addEventListener(amp.bufferDataEventName.downloadfailed, function () {
var data = {
sessionId: player.currentSrc(),
currentTime: player.currentTime(),
bufferLevel: player.audioBufferData().bufferLevel,
url: player.audioBufferData().downloadFailed.mediaDownload.url,
code: "0x" + player.audioBufferData().downloadFailed.code.toString(16),
message: player.audioBufferData().downloadFailed
};
logData("DownloadFailed", 0, data);
});
}
if (player.videoBufferData()) {
player.videoBufferData().addEventListener(amp.bufferDataEventName.downloadfailed, function () {
var data = {
sessionId: player.currentSrc(),
currentTime: player.currentTime(),
bufferLevel: player.videoBufferData().bufferLevel,
url: player.videoBufferData().downloadFailed.mediaDownload.url,
code: "0x" + player.videoBufferData().downloadFailed.code.toString(16),
message: player.videoBufferData().downloadFailed
};
logData("DownloadFailed", 0, data);
});
}
var data = {
sessionId: player.currentSrc(),
isLive: player.isLive(),
duration: player.duration(),
tech: player.currentTechName(),
protection: ((player.currentProtectionInfo() && player.currentProtectionInfo()[0]) ? player.currentProtectionInfo()[0].type : "clear")
};
logData("PresentationInfo", 1, data);
}
function handlePlaybackBitrateChanged(event) {
logData("BitrateChanged", 1, eventData(event));
}
function handleWaiting(event) {
logData("Waiting", 0, eventData(event));
}
function handlePlaying(event) {
logData("Playing", 1, eventData(event));
}
function handleSeeking(event) {
logData("Seeking", 1, eventData(event));
}
function handlePaused(event) {
logData("Paused", 1, eventData(event));
}
function handleEnded(event) {
logData("Ended", 1, eventData(event));
}
function logData(eventId, level, data) {
var eventLog = {
eventId: eventId,
level: level,
data: data
};
log(eventLog);
}
function eventData(event) {
return {
sessionId: player.currentSrc(),
currentTime: player.currentTime(),
isLive: player.isLive(),
event: event.type,
presentationTimeInSec: event.presentationTimeInSec,
message: event.message ? event.message : ""
};
}
}
})(amp || (amp = {}));

Resources