I'm trying to compare whether the video has been fully downloaded before I fade in the player using jQuery. To do this I'm using a loop using the setInterval() function and comparing the video attributes 'buffered.end(0)' and 'duration', however the length of both differs - as the first one contains more decimal places (by 3) than the second one:
25.946847656 > 25.946847
Is there any way I could check whether the video has been fully downloaded before I show the player?
Here's what I've got at the moment:
var playerObject = {
init : function(obj) {
"use strict";
if (obj.length > 0) {
if (obj.length > 1) {
jQuery.each(obj, function() {
playerObject.start($(this));
});
} else {
playerObject.start(obj);
}
}
},
start : function(obj) {
"use strict";
var thisTime = window.setInterval(function() {
if (obj[0].buffered.end(0) === obj[0].duration) {
window.clearInterval(thisTime);
obj.fadeIn(200);
playerObject.create(obj);
}
}, 1000);
},
create : function(obj) {
"use strict";
obj.live('click', function() {
var thisVideo = $(this)[0];
if (thisVideo.paused === false) {
thisVideo.pause();
} else {
thisVideo.play();
}
});
playerObject.endVideo(obj);
},
endVideo : function(obj) {
"use strict";
var thisTime = window.setInterval(function() {
if (obj[0].ended == true) {
window.clearInterval(thisTime);
obj.fadeOut(200);
}
}, 1000);
}
};
$(function() {
"use strict";
playerObject.init($('.player'));
});
There dosn't appear to be anything in the HTML 5 specification which would trigger once download/buffering has completed there is however a canplaythrough event that fires once the browser determines enough of the media has been downloaded such that it can be played through to the end without having to stop and buffer more of the media.
I've now amended the start() method by simply dividing both, rounding the result and comparing to 1, which would indicate that they are both the same:
start : function(obj) {
"use strict";
var thisTime = window.setInterval(function() {
if (Math.round(obj[0].buffered.end(0) / obj[0].duration) === 1) {
window.clearInterval(thisTime);
obj.fadeIn(200);
playerObject.create(obj);
}
}, 1000);
}
Related
I am using this library:
!function(e,n,t,r){
function o(){try{var e;if((e="string"==typeof this.response?JSON.parse(this.response):this.response).url){var t=n.getElementsByTagName("script")[0],r=n.createElement("script");r.async=!0,r.src=e.url,t.parentNode.insertBefore(r,t)}}catch(e){}}var s,p,a,i=[],c=[];e[t]={init:function(){s=arguments;var e={then:function(n){return c.push({type:"t",next:n}),e},catch:function(n){return c.push({type:"c",next:n}),e}};return e},on:function(){i.push(arguments)},render:function(){p=arguments},destroy:function(){a=arguments}},e.__onWebMessengerHostReady__=function(n){if(delete e.__onWebMessengerHostReady__,e[t]=n,s)for(var r=n.init.apply(n,s),o=0;o<c.length;o++){var u=c[o];r="t"===u.type?r.then(u.next):r.catch(u.next)}p&&n.render.apply(n,p),a&&n.destroy.apply(n,a);for(o=0;o<i.length;o++)n.on.apply(n,i[o])};var u=new XMLHttpRequest;u.addEventListener("load",o),u.open("GET","https://"+r+".webloader.smooch.io/",!0),u.responseType="json",u.send()
}(window,document,"Smooch",smooch_key);
And this is how I init:
function initSmooch() {
if (!$rootScope.smooch_inited) {
try {
var window_focus = true;
$(window).focus(function() {
window_focus = true;
}).blur(function() {
window_focus = false;
});
Smooch.on('message:received', function() {
if (!window_focus || !Smooch.isOpened()) {
//Play sound
var audio = new Audio('assets/audio/ding.wav');
audio.play();
}
Smooch.open();
});
var promise = Smooch.init({
appId: smooch_key,
});
promise.then(function() {
$('#sk-holder').addClass('no-print');
$rootScope.smooch_inited = true;
Smooch.updateUser({
givenName: $rootScope.data.user.first_name,
surname: $rootScope.data.user.last_name,
properties: {
email: $rootScope.data.user.email,
uid: $rootScope.data.user.id,
language: $rootScope.data.user.language,
country: $rootScope.data.user.country
}
});
});
} catch(e) {
console.log("error trying to init smooch: " + e);
$timeout(function() {
initSmooch();
}, 1000);
}
}
}
Looked but I have nothing where I add the view, so I don't know how to modify, force it to be on top. Any ideeas?
This looks like there is a conflict between the Z index of the Web Messenger and the elements beneath it. The Web Messenger already has a very high z-index of 9998, but to fix this issue you'll either need to increase that value more, or decrease the z-index of the elements that appear on top.
For the former, you can insert this CSS rule on your page and tweak the value to something suitable:
#web-messenger-container {
z-index: 9998;
}
Or write a similar rule targeting the problematic elements and giving them a lower number
The below code is working for firefox but not for chrome. I have a chrome extension for screen share the screen stream is caught and I am able to send that to a video element on browser but it does not goes to other webrtc end.
function getScreenConstraints(test, callback) {
var firefoxScreenConstraints = {
mozMediaSource: 'window',
mediaSource: 'window'
};
//if(isFirefox) return firefoxScreenConstraints;
if (isFirefox) return callback(null, firefoxScreenConstraints);
// this statement defines getUserMedia constraints
// that will be used to capture content of screen
var screen_constraints = {
mandatory: {
chromeMediaSource: chromeMediaSource,
maxWidth: screen.width > 1920 ? screen.width : 1920,
maxHeight: screen.height > 1080 ? screen.height : 1080
}
};
// this statement verifies chrome extension availability
// if installed and available then it will invoke extension API
// otherwise it will fallback to command-line based screen capturing API
if (chromeMediaSource == 'desktop' && !sourceId) {
getSourceId(function() {
screen_constraints.mandatory.chromeMediaSourceId = sourceId;
/*navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
navigator.getUserMedia({ video: screen_constraints }, function(stream) {
var video = document.querySelector('video');
console.log(video);
//var video = document.getElementById('videoInput');
video.src = URL.createObjectURL(stream);
video.play();
}, function(error) {
alert(JSON.stringify(error, null, '\t'));
});*/
callback(sourceId == 'PermissionDeniedError' ? sourceId : null, screen_constraints);
});
//return;
}
// this statement sets gets 'sourceId" and sets "chromeMediaSourceId"
if (chromeMediaSource == 'desktop') {
screen_constraints.mandatory.chromeMediaSourceId = sourceId;
}
console.log(screen_constraints);
// now invoking native getUserMedia API
callback(null, screen_constraints);
}
function screen(to, from) {
if (to == '') {
window.alert("You must specify the peer name");
return;
}
var constraints = {
audio: true,
video: {
mediaSource: 'window' || 'screen'
}
}
setCallState(PROCESSING_CALL);
showSpinner(videoInput, videoOutput);
var options = {
localVideo: videoInput, //if you want to see what you are sharing
onicecandidate: onIceCandidate,
sendSource: 'screen',
mediaConstraints: constraints
}
webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options,
function(error) {
if (error) return onError(error) //You'll need to use whatever you use for handling errors
this.generateOffer(
function(error, offerSdp) {
if (error) {
console.error(error);
setCallState(NO_CALL);
}
$("#callDiv").fadeIn();
var message = {
id: 'call',
from: from,
to: to,
sdpOffer: offerSdp,
type: 'screen'
};
sendMessage(message);
});
});
}
I have put together a sidebar with hover-delay animation, but I can't seem to exactly copy the column to place next to the first. This is my first problem.
The second is that I would like to use the jspanel plugin, so that a dragable window will pop up when I click on a sub-item in the sidebar.
I hope this can be brought to a working state.
Thank you very much for responses in advance!
Here's [a link] (http://jsfiddle.net/chrisoutwright/tc4d9t6d/)!
$('#categories').corner("top keep");
$(document).ready(function(){
$("#foo").click(function(){
$().jsPanel().show();
});
});
$( "#navigation ul.sub-level" ).corner("").css( "border", "3px double blue" );
jQuery.fn.hoverWithDelay = function(inCallback,outCallback,delay) {
this.each(function() {
var timer, $this = this;
$(this).hover(function(){
timer = setTimeout(function(){
timer = null;
inCallback.call($this);
}, delay);
},function() {
if (timer) {
clearTimeout(timer);
timer = null;
} else
outCallback.call($this);
});
});
};
var hovering = {mainMenu: false, categories: false};
function closeSubMenus() {
$('ul.sub-level').css('display', 'none');
}
closeSubMenus();
function closeMenuIfOut() {
setTimeout(function(){
if (!hovering.mainMenu && !hovering.categories) {
$('#navigation').fadeOut('fast',closeSubMenus);
}
},100);
}
$('ul.top-level li').hoverWithDelay(function() {
$(this).find('ul').show();
}, function() {
$(this).find('ul').fadeOut('fast', closeMenuIfOut);
}, 500);
$('#categories').hoverWithDelay(function() {
$('#navigation').show();
hovering.categories = true;
},
function(){
hovering.categories = false;
closeMenuIfOut();
},500);
$('#navigation').hover(function() {
hovering.mainMenu = true;
}, function() {
hovering.mainMenu = false;
});
I can see at least one error in line 4 where you try to generate/open the jsPanel.
Which jsPanel version do you use? Version 1.x or Version 2.x? The two versions differ on how to use the jsPanel() command.
version 1.x: $( selector ).jsPanel( config );
version 2.x: $.jsPanel( config );
Do you get any error messages?
I know there are a lot of similar questions on here, but, when putting them to action, I still resolve in the same problem.
I have 2 angular directives (drag and drop) and one angular factory (dndAPI). This is all based off of fisshy's Angular Drag and Drop on github.
I finally got firefox to accept and drag movement by adding data to the event, however I can't seem to keep it from doing it's default behavior (and loading that data as a url). I also apologize I couldn't get it to work at all on jsfiddle...at all. I'll try again if someone can't see if I'm doing something outrageously wrong.
angular.module('dragAndDrop', [])
.directive('drag',function (dndApi) {
var drags = [],
dragging = new RegExp('(\\s|^)dragging(\\s|$)');
return {
restrict: 'A',
scope: {
item: '=drag',
whenStart: '&',
whenEnd: '&',
dropzones: '='
},
link: function (scope, elem, attr, ctrl) {
elem.bind('dragstart', function (e) {
angular.element('query-tool-tip').removeClass('active');
//if ( drags.length === 0 ) {
drags = document.querySelectorAll('.drop');
//}
angular.forEach(drags, function (value, key) {
if (scope.dropzones.indexOf(value.getAttribute('drop')) >= 0) {
value.className = value.className + ' dragging';
}
});
elem.addClass('dragging');
dndApi.setData(scope.item, scope.dropzones);
e.originalEvent.dataTransfer.effectAllowed = 'move';
//KEEPS FIREFOX FROM CRAPPING OUT:
e.originalEvent.dataTransfer.setData( 'text/plain', 'stop' );
scope.$apply(function () {
scope.whenStart({ data: dndApi.getData() });
});
});
elem.bind('dragleave', function(e){});
elem.bind('dragend', function (e) {
elem.removeClass('dragging');
angular.forEach(drags, function (value, key) {
value.className = value.className.replace(dragging, '');
});
scope.$apply(function () {
scope.whenEnd({ data: dndApi.getData() });
});
dndApi.removeData();
e.preventDefault();
});
elem[0].draggable = true;
elem[0].className = elem[0].className + ' drag';
}
};
}).directive('drop',function (dndApi) {
var drags = [],
dragging = new RegExp('(\\s|^)dragging(\\s|$)');
return {
scope: {
drop: '=drop',
whenDrop: '&',
whenEnter: '&',
whenLeave: '&',
queryIndex: "=queryIndex",
hideElem: '='
},
link: function (scope, elem, attr, ctrl) {
var left = elem[0].offsetLeft,
right = left + elem[0].offsetWidth,
top = elem[0].offsetTop,
bottom = top + elem[0].offsetHeight;
elem.bind('drop', function (e) {
// e.originalEvent.preventDefault();
//if (e.stopPropagation()) {
// e.stopPropagation();
//e.originalEvent.stopPropagation();
//e.preventDefault();
//e.originalEvent.preventDefault();
//}
e.originalEvent.dataTransfer.clearData();
if (dndApi.getDropZones().indexOf(scope.drop) >= 0) {
scope.$apply(function () {
scope.whenDrop({ data: dndApi.getData(), queryI: scope.queryIndex });
});
}
if (drags.length === 0) {
drags = document.querySelectorAll('.drop');
}
angular.forEach(drags, function (value, key) {
value.className = value.className.replace(dragging, '');
});
dndApi.removeData();
e.stopPropagation();
e.originalEvent.stopPropagation();
e.preventDefault();
e.originalEvent.preventDefault();
});
elem.bind('dragenter', function (e) {
e.preventDefault();
e.originalEvent.preventDefault();
if (elem[0] == e.target) {
scope.$apply(function () {
scope.whenEnter({ data: dndApi.getData() });
});
}
return false;
});
elem.bind('dragleave', function (e) {
e.preventDefault();
e.originalEvent.preventDefault();
if ((e.x < left || e.x > right) ||
(e.y < top || e.y > bottom)) {
scope.$apply(function () {
scope.whenLeave({ data: dndApi.getData() });
});
}
return false;
});
elem.bind('dragover', function (e) {
//if (e.preventDefault) {
e.preventDefault();
e.originalEvent.preventDefault();
//}
return false;
});
elem[0].className = elem[0].className + ' drop';
scope.$watch('hideElem', function () {
if (scope.hideElem === true) {
elem.hide();
} else {
elem.show();
}
});
}
};
}).factory('dndApi', function () {
var dnd = {
dragObject: {},
dropzones: []
};
return {
setData: function (data, areas) {
dnd.dragObject = data;
dnd.dropzones = areas;
},
removeData: function () {
dnd.dragObject = null;
dnd.dropZones = [];
},
getData: function () {
return dnd.dragObject;
},
getDropZones: function () {
return dnd.dropzones;
}
};
});
I've done a lot of what's recommended on other questions. I've added event.preventDefault() to the dragenter and dragleave spots. And then when that didn't work I added them everywhere. I have a feeling it has to do with my drop method. If i put event.prevendDefault() at the beginning of the binding, the rest of my code isn't executed.
Any advice, even if it's something small that I might've overlooked, will be helpful.
Thanks!
You are calling e.originalEvent.dataTransfer.clearData(); in the drop event handler which will cause an exception to be thrown (you won't have permission to alter the original dataTransfer object). This is preventing e.originalEvent.preventDefault(); from being called.
Hi all I have a site developed in cakephp and I would to integrate backbone on it.
For my scope I would to use external js for backbone to reuse the code.
I have write some lines but I can't append results on my element.
I have tried to print the "el" in this modes:
console.log($(this.el));
console.log(this.el);
console.log(this.$el);
But nothing I can't enter into el to make a simple append!
The container #search-results already exist
This is my main view:
<script type="text/javascript">
var search = {};
search.product = {};
search.product.template = "#results-product-template";
search.product.container = "#search-results";
search.product.defaults = {
id:0,
type:"product",
};
$(function(){
var ProductList = new Search.Collections.Products();
var ProductView = new Search.Views.Product({
// new Search.Collections.Products();
collection:ProductList
,el:$("#search-results")
});
function parseResults () {
var json = {
//my data
}
for (var i = json.products.length - 1; i >= 0; i--) {
ProductList.add([new Search.Models.Product(json.products[i])]);
};
updateResults();
}
function updateResults () {
console.log('updateResults: Ritorno il risultato quando hunter riceve una risposta dal server');
if ($('#search-results').length == 0) {
$('div.main > section:first-child').before('<section id="search-results"> <ul id="product-results"> <li>Contenuto</li> </ul> </section>');
}
ProductView.render();
}
// search
$('#search-results .close').on('click', function () {
$('#search-results').animate({height:0}, 500, function () {
$(this).remove();
})
});
});
</script>
And this is my external js with backbone
var Search = {
Models: {},
Collections: {},
Views: {},
Templates:{}
}
Search.Models.Product = Backbone.Model.extend({
defaults: search.product.defaults || {},
toUrl:function (url) {
return url.replace(" ", "-").toLowerCase();
},
initialize:function () {
console.log("initialize Search.Models.Product");
this.on("change", function (){
console.log("chiamato evento change del Model Search.Models.Product");
});
this.on("change:text", function () {
console.log("chiamato evento change:text del Model Search.Models.Product");
});
}
});
Search.Collections.Products = Backbone.Collection.extend({
model: Search.Models.Product,
initialize:function () {
console.log("initialize Search.Collections.Products");
console.log(this);
console.log(this.length);
console.log(this.models);
}
});
Search.Views.Product = Backbone.View.extend({
initialize:function () {
console.log("initialize Search.Views.Product");
console.log($(search.product.template).html());
},
template:function (data) {
if (data == null) {
data = this.collection.toJSON();
}
var template = Handlebars.compile($(search.product.template).html());
template(data);
},
render:function () {
console.log($(this.el));
$(this.el.append("TEST"));
//HERE IS THE PROBLEM
// I have tried this.$el.append("TEST");
return this;
}
});
Does this change anything?
var ProductView = new Search.Views.Product({
// new Search.Collections.Products();
collection:ProductList,
el:$("#search-results")[0]
});
I think backbone can accept both jQuery wrapped or not wrapped object and be fine, but I don't know what Backbone version you are using, see if this works
EDIT: From backbone 1.0 sources, it seems backbone can indeed take either a jQuery wrapped object or a regular dom element, it should still work
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
Do you have something online (JSFiddle?) I will be happy to take a look, but this.$el should work and be equal to $("#search-results") from your code in a quick glance.
Have you tried using ProductView.setElement($("#search-results")) instead? it should be the same, but worth a try as well.