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 = {}));
Related
(function ($) {
var webcam = {
"extern": null, // external select token to support jQuery dialogs
"append": true, // append object instead of overwriting
"width": 320,
"height": 240,
"mode": "callback", // callback | save | stream
"swffile": "../Webcam_Plugin/jscam_canvas_only.swf",
"quality": 85,
"debug": function () {},
"onCapture": function () {},
"onTick": function () {},
"onSave": function () {},
"onLoad": function () {}
};
window["webcam"] = webcam;
$["fn"]["webcam"] = function(options) {
if (typeof options === "object") {
for (var ndx in webcam) {
if (options[ndx] !== undefined) {
webcam[ndx] = options[ndx];
}
}
}
var source = '<object id="XwebcamXobjectX" type="application/x-shockwave-flash" data="'+webcam["swffile"]+'" width="'+webcam["width"]+'" height="'+webcam["height"]+'"><param name="movie" value="'+webcam["swffile"]+'" /><param name="FlashVars" value="mode='+webcam["mode"]+'&quality='+webcam["quality"]+'" /><param name="allowScriptAccess" value="always" /></object>';
if (null !== webcam["extern"]) {
$(webcam["extern"])[webcam["append"] ? "append" : "html"](source);
} else {
this[webcam["append"] ? "append" : "html"](source);
}
var run = 3;
(_register = function() {
var cam = document.getElementById('XwebcamXobjectX');
if (cam && cam["capture"] !== undefined) {
/* Simple callback methods are not allowed :-/ */
webcam["capture"] = function(x) {
try {
return cam["capture"](x);
} catch(e) {}
}
webcam["save"] = function(x) {
try {
return cam["save"](x);
} catch(e) {}
}
webcam["setCamera"] = function(x) {
try {
return cam["setCamera"](x);
} catch(e) {}
}
webcam["getCameraList"] = function() {
try {
return cam["getCameraList"]();
} catch(e) {}
}
webcam["pauseCamera"] = function() {
try {
return cam["pauseCamera"]();
} catch(e) {}
}
webcam["resumeCamera"] = function() {
try {
return cam["resumeCamera"]();
} catch(e) {}
}
webcam["onLoad"]();
} else if (0 == run) {
webcam["debug"]("error", "Flash movie not yet registered!");
} else {
/* Flash interface not ready yet */
run--;
window.setTimeout(_register, 1000 * (4 - run));
}
})();
}
})(jQuery);
Above is the function which I've used in order to access the webcam of the system. It work fine when i use it on localhost but the problem arises when the same is put on the server and then accessed through intranet.
I'm unable to find the reason to fix it. Kindly help me with the same.
The first two images are the ones when i use my code on localhost. It works fine as i'm able to access the webcam.
Problem statement:
The last image is the one where I try to do the same through server. The webcam opens by the images is completely wiped out. Only a white screen appears and even if I capture the photo through webcam, the white image is only saved on server instead of a proper original image.
Because of security reasons you have to serve the Site over Https to access the camera.
We are having an issue with signalR. We have an auction site that runs on signalr for real time bidding. We fixed some issues with the browser and everything seemed to be working well. Then we installed new relic on our server and noticed that every minute we are getting http error code 400 on signalr connect, reconnect and abort. Here's a screenshot:
SignalR connect and reconnect are the most time consuming operations of the site according to new relic.
Here is SignalR backend code (We use sql server as signalr backplane):
public class SignalRHub : Hub
{
public void BroadCastMessage(String msg)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<SignalRHub>();
hubContext.Clients.All.receiveMessage(msg);
}
}
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
string appString=string.Empty;
//Gets the connection string.
if (System.Configuration.ConfigurationSettings.AppSettings["SignaRScaleoutConn"] != null)
{
appString = System.Configuration.ConfigurationSettings.AppSettings["SignaRScaleoutConn"].ToString();
}
GlobalHost.DependencyResolver.UseSqlServer(appString);
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromMinutes(15); //I added this timeout, but it is not required.
app.MapSignalR();
}
}
The javascript client looks like this, it's lengthy, but most of it is jQuery to affect the DOM, I include it all in case something may be wrong inside it.
$(function () {
var chatProxy = $.connection.signalRHub;
$.connection.hub.start();
chatProxy.client.receiveMessage = function (msg) {
var all = $(".soon").map(function () {
var hiddenModelId = $("#hiddenListingId");
if (msg == hiddenModelId.val()) {
$.ajax({
async: "true",
url: "/Listing/AuctionRemainingTime",
type: "POST",
dataType: 'json',
data: '{ "listingID": "' + msg + '"}',
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data != null) {
SoonSettings.HasReloadedThisTick = false;
var element = document.getElementById(msg);
var obj = JSON.parse(data)
// For Clock Counter End Date Time Interval
// Adds 2 minutes to the soon clock when bid is close to finishing.
var hdID = "hdn" + obj.ListingId;
var hdValue = $("#" + hdID);
if (obj.EndDate != hdValue.val()) {
SoonSettings.HasUpdated = false; //Allows clock to change color once it gets under two minutes.
$('#' + hdID).val(obj.EndDate);
Soon.destroy(element);
Soon.create(element, { //Recreates clock with the before 2 minute tick event.
'due': 'in ' + obj.Seconds + ' seconds',
'layout':'group label-uppercase',
'visual':'ring cap-round progressgradient-00fff6_075fff ring-width-custom gap-0',
'face':'text',
'eventTick': 'tick'
});
}
var highbid = obj.HighBidderURL;
// For Date Ends Info.
var ListingEndDate = $("#tdAuctionListingEndDate");
if (obj.EndDate != ListingEndDate.val()) {
$('#' + hdID).val(obj.EndDate);
ListingEndDate.text(obj.EndDate + " Eastern");
ListingEndDate.effect("pulsate", { times: 5 }, 5000);
}
else
{
$(".Bidding_Current_Price").stop(true, true); ///Removes the pulsating effect.
$(".Bidding_Current_Price").removeAttr("style"); //Removes unnecessary attribute from HTML.
}
//Bid div notification.
if (obj.AcceptedActionCount.replace(/[^:]+:*/, "") > 0) {
if (obj.Disposition != '' && obj.Disposition != null) {
if (obj.Disposition == "Neutral") {
$("#spanNeutralBid").show();
$("#divOutbidNotification").hide();
$("#spanPositiveBid").hide();
$("#divProxyBidNotification").hide();
}
else if (obj.Disposition == "Positive") {
$("#spanPositiveBid").show();
$("#divOutbidNotification").hide();
$("#spanNeutralBid").hide();
$("#divProxyBidNotification").hide();
}
else if (obj.Disposition == "Negative") {
$("#divOutbidNotification").show();
$("#spanNeutralBid").hide();
$("#spanPositiveBid").hide();
$("#divProxyBidNotification").hide();
}
else {
$("#divOutbidNotification").hide();
$("#spanNeutralBid").hide();
$("#divProxyBidNotification").hide();
$("#spanPositiveBid").hide();
}
}
}
// For Highlight Current Price when it is Updated
var hdCurrentPrice = $("#hdnCurrentPrice");
if (obj.CurrentPrice != hdCurrentPrice.val()) {
$(".Bidding_Current_Price").text(obj.CurrentPrice);
$(".Bidding_Current_Price").effect("pulsate", { times: 5 }, 5000);
$("#hdnCurrentPrice").val(obj.CurrentPrice);
}
else {
$(".Bidding_Current_Price").stop(true, true);
$(".Bidding_Current_Price").removeAttr("style");
}
// For ReservePrice Status
$("#spanReservePriceStatus").html(obj.ReservePriceStatus);
$("#smallReservePriceStatus").html(obj.ReservePriceStatus);
// For Bid Count
var spanBidCounter = $("#spanBidCount");
$(spanBidCounter).text(obj.AcceptedActionCount);
var stringAppend = "<tr id='trhHighBidder'><td><strong>HighBidder</strong></td>";
stringAppend += "<td>";
if (obj.isAdmin == true) {
stringAppend += "<a id='anchorHighBid' href=" + obj.HighBidderURL + ">";
stringAppend += "<span id='spanHighBidder'>" + obj.CurrentListingActionUserName + "</span>"
stringAppend += "</a>";
}
else {
stringAppend += "<span id='spanHighBidderAnonymous'>" + obj.CurrentListingActionUserName + "</span>";
}
stringAppend += "</td></tr>";
if (obj.AcceptedActionCount.replace(/[^:]+:*/, "") > 0) {
if ($("#tblAuctionDetail").find("#rowHighBidder").length > 0) {
if ($("#tblAuctionDetail").find("#trhHighBidder").length > 0) {
$("#trhHighBidder").remove();
}
}
else {
//add tr to table
if (!$("#tblAuctionDetail").find("#trhHighBidder").length > 0) {
$('#tblAuctionDetail > tbody > tr:eq(6)').after(stringAppend);
}
}
}
// For High Bidder
if (obj.isAdmin) {
var anchorElement = $("#anchorHighBid");
$(anchorElement).attr("href", obj.HighBidderURL);
var spanHighBidder = $("#spanHighBidder");
$(spanHighBidder).text(obj.CurrentListingActionUserName);
}
else {
var spanAdminHighBid = $("#spanHighBidderAnonymous");
$(spanAdminHighBid).text(obj.CurrentListingActionUserName)
}
}
},
error: function (xhr, textStatus, errorThrown) {
}
});
}
});
};
});
Is there anything wrong with the client or the server signalr code that may need to be changed to avoid these errors happening so often? The 400 code has the tendency of showing up almost every minute. I am very new to signalR and know very little of how to make effective code with it.
The real time bidding in the site does work, it's just to find a way to avoid these constant errors. Any help explaining anything of how signalR works is appreciated.
Thanks,
I'd give a try changing the transportation method of SignalR: http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#transport
and check if problem persists.
If possible to get UserAgent from Bad Request log, try to narrow down which browsers get 400 error. I think, maybe, some browsers are not connecting with correct transport method.
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);
}
I am using keystone#0.2.32. I would like to change the post category to a tree structure. The below code is running well except when I create a category, it goes into a deadlock:
var keystone = require('keystone'),
Types = keystone.Field.Types;
/**
* PostCategory Model
* ==================
*/
var PostCategory = new keystone.List('PostCategory', {
autokey: { from: 'name', path: 'key', unique: true }
});
PostCategory.add({
name: { type: String, required: true },
parent: { type: Types.Relationship, ref: 'PostCategory' },
parentTree: { type: Types.Relationship, ref: 'PostCategory', many: true }
});
PostCategory.relationship({ ref: 'Post', path: 'categories' });
PostCategory.scanTree = function(item, obj, done) {
if(item.parent){
PostCategory.model.find().where('_id', item.parent).exec(function(err, cats) {
if(cats.length){
obj.parentTree.push(cats[0]);
PostCategory.scanTree(cats[0], obj, done);
}
});
}else{
done();
}
}
PostCategory.schema.pre('save', true, function (next, done) { //Parallel middleware, waiting done to be call
if (this.isModified('parent')) {
this.parentTree = [];
if(this.parent != null){
this.parentTree.push(this.parent);
PostCategory.scanTree(this, this, done);
}else
process.nextTick(done);
}else
process.nextTick(done); //here is deadlock.
next();
});
PostCategory.defaultColumns = 'name, parentTree';
PostCategory.register();
Thanks so much.
As I explained on the issue you logged on Keystone here: https://github.com/keystonejs/keystone/issues/759
This appears to be a reproducible bug in mongoose that prevents middleware from resolving when:
Parallel middleware runs that executes a query, followed by
Serial middleware runs that executes a query
Changing Keystone's autokey middleware to run in parallel mode may cause bugs in other use cases, so cannot be done. The answer is to implement your parentTree middleware in serial mode instead of parallel mode.
Also, some other things I noticed:
There is a bug in your middleware, where the first parent is added to the array twice.
The scanTree method would be better implemented as a method on the schama
You can use the findById method for a simpler parent query
The schema method looks like this:
PostCategory.schema.methods.addParents = function(target, done) {
if (this.parent) {
PostCategory.model.findById(this.parent, function(err, parent) {
if (parent) {
target.parentTree.push(parent.id);
parent.addParents(target, done);
}
});
} else {
done();
}
}
And the fixed middleware looks like this:
PostCategory.schema.pre('save', function(done) {
if (this.isModified('parent')) {
this.parentTree = [];
if (this.parent != null) {
PostCategory.scanTree(this, this, done);
} else {
process.nextTick(done);
}
} else {
process.nextTick(done);
}
});
I think it's a bug of keystone.js. I have changed schemaPlugins.js 104 line
from
this.schema.pre('save', function(next) {
to
this.schema.pre('save', true, function(next, done) {
and change from line 124 to the following,
// if has a value and is unmodified or fixed, don't update it
if ((!modified || autokey.fixed) && this.get(autokey.path)) {
process.nextTick(done);
return next();
}
var newKey = utils.slug(values.join(' ')) || this.id;
if (autokey.unique) {
r = getUniqueKey(this, newKey, done);
next();
return r;
} else {
this.set(autokey.path, newKey);
process.nextTick(done);
return next();
}
It works.
I would like to switch to an iframe using pure phantom.js code
Here is my first attempt
var page = new WebPage();
var url = 'http://www.theurltofectch'
page.open(url, function (status) {
if ('success' !== status) {
console.log("Error");
} else {
page.switchToFrame("thenameoftheiframe");
console.log(page.content);
phantom.exit();
}
});
It produces only the source code of the main page. Any idea ?
Notice that the iframe domain is different from the main page domain.
Please give this a try I believe it may be an async issues meaning the iframe is not present when trying to access it. I received the below snippet from another post.
var page = require('webpage').create(),
testindex = 0,
loadInProgress = false;
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onLoadStarted = function() {
loadInProgress = true;
console.log("load started");
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log("load finished");
};
/*
page.onNavigationRequested = function(url, type, willNavigate, main) {
console.log('Trying to navigate to: ' + url);
console.log('Caused by: ' + type);
console.log('Will actually navigate: ' + willNavigate);
console.log('Sent from the page\'s main frame: ' + main);
};
*/
/*
The steps array represents a finite set of steps in order to perform the unit test
*/
var steps = [
function() {
//Load Login Page
page.open("https://www.yourpage.com");
},
function() {
//access your iframe here
page.evaluate(function() {
});
},
function() {
//any other step you want
page.evaluate(function() {
});
},
function() {
// Output content of page to stdout after form has been submitted
page.evaluate(function() {
//console.log(document.querySelectorAll('html')[0].outerHTML);
});
//render a test image to see if login passed
page.render('test.png');
}
];
interval = setInterval(function() {
if (!loadInProgress && typeof steps[testindex] === "function") {
console.log("step " + (testindex + 1));
steps[testindex]();
testindex++;
}
if (typeof steps[testindex] !== "function") {
console.log("test complete!");
phantom.exit();
}
}, 50);
replace
console.log(page.content);
with
console.log(page.frameContent);
Should return the contents of the frame phantomjs switched to.
If the iframe is from another domain you may need to add the --web-security=no option like this:
phantomjs --web-security=no myscript.js
As an additional information, what xMythicx said could be true. Some iframes are rendered via Javascript after page finishes loading. If the iframe contents are empty, then you will need to wait for all resources to finish loading, before you start grabbing stuff from the page. But this is another issue, if you need an answer on this, I suggest you ask a new question about it, and I will answer there.
Had the same problem for iframes and
phantomjs --web-security=no
helped in my case :]