I have probelm running video.js player.
First I put the video.js and video-js.css in client/compatibility folder so it will load first
Then in my client side html I write the following simple code,, It is not working
<video id="example_video_1" class="video-js vjs-default-skin vjs-big-play-centered"
controls width="640" height="264"
poster="{{video.thumbs}}"
data-setup='{"controls": true, "autoplay": true,"techOrder":["flash", "html5"],preload="auto"}'>
<source type='video/flv' src="{{uurl}}" />
</video>
There are no issues with the template helpers they are working fine but
The problem is with the video.js player , It is not loading.
Anyone tried this before? Struck here, Any help appreciated
UPDATE:
dynamic loading solution working fine for me but
when I click on a video it redirects to /video/:_id/:_slug page with subscribing to single video but when I go back to the home page and again click on another video, this time video player is not initializing again
Code
when onclick on video:
'click .videothumb > a':function(e,t){
Session.set("url",e.currentTarget.getAttribute("data-url"));
var url=e.currentTarget.getAttribute("data-url");
var title=e.currentTarget.getAttribute("data-title");
var cid=e.currentTarget.getAttribute("data-id");
Meteor.call("videoData",url,function(er,da){
console.log(cid);
Session.set('vurl',da);
Router.go("video",{_id:cid,slug:title});
});
}
routing
this.route("video",{
path:'/video/:_id/:slug',
waitOn: function() {
// return Meteor.subscribe('singleVideo', this.params._id);
},
onBeforeAction: function () {
},
data:function(){
Session.set("currentVideoId",this.params._id);
var video;
video= Videos.findOne({_id: this.params._id});
return {
video:video
};
}
});
rendered function:
Template.video.rendered=function(){
var id=Session.get("currentVideoId");
Meteor.call("incViews",id,function(e,d){
console.log("view added");
});
videojs("videoId",{"controls": true, "autoplay": false,"techOrder":["html5","flash"],preload:"auto"},function(){
// Player (this) is initialized and ready.
**console.log("videojs initialized");**
console.log(this) ;
}
);
};
that console "videojs initialized" is loging when only first when I route the video page
from next routing(when I click video thumbnail on homepage)The log functions is not loggind(means player is not initializing)
Any suggestions to make it work better
In the time videojs script is initialized there is no template rendered, you need to manually initialize videojs player.
tpl1.html:
<template name="tpl1">
<video id="example_video_1" class="video-js vjs-default-skin vjs-big-play-centered"
controls width="640" height="264"
poster="{{video.thumbs}}">
<source type='video/flv' src="{{uurl}}" />
</video>
</template>
tpl1.js:
Template.tpl1.rendered = function(){
videojs(
"example_video_1",
{"controls": true, "autoplay": true,"techOrder":["flash", "html5"],preload="auto"},
function(){ // Player (this) is initialized and ready. }
);
})
Please read documentation of Video.js:
"Alternative Setup for Dynamically Loaded HTML"
I implemented it in my project w/o using Blaze but using a lower-level Tracker dependencies. When the Template is rendered, I would dynamically start the player and then have a reactive data-source of the current position that I can control: https://github.com/Slava/talk-player/blob/master/client/player.js
This worked for me on Meteor 1.6.1.1.
template html
<template name="tebVideo">
<video class="video-js">
<source src="{{src}}" type="video/mp4">
</video>
</template>
template js
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import 'video.js/dist/video-js.css';
import videojs from 'video.js';
import './video.html';
// prevent analytics
window.HELP_IMPROVE_VIDEOJS = false;
// helper for local dev vs product cdn
const envUrl = (localPath, fileName) => {
if (Meteor.isProduction) {
return Meteor.settings.public.host.cdnUrl+'/'+fileName;
}
else {
return localPath+fileName;
}
};
Template.tebVideo.onRendered(() => {
const instance = Template.instance();
const video = videojs(document.querySelector('.video-js'),
{
controls: true,
autoplay: false,
preload: 'auto',
width: 854,
height: 480,
aspectRatio: "16:9",
poster: envUrl('/images/', instance.data.poster),
function() {
Log.log(['debug', 'video'], 'Video loaded ok');
}
}
);
});
Template.tebVideo.helpers({
src() {
const instance = Template.instance();
return envUrl('/videos/', instance.data.src);
}
});
show it
{{>tebVideo poster="three_robots.png" src="how-knowledge-automation-works.mp4"}}
Related
My company is getting a scorm test from another company. (scorm schemaversion 1.2)
We are embedded the test in an iframe like this:
<html>
</head>
<iframe src="exam/scormcontent/index.html" name="course">
</iframe>
</html>
This is the test folder structure:
I am new this scorm solution. What we are trying to do is to get the final result of the scorm test (student passed/failed) in the parent html page.
The html page and the scorm are planned to be hosted on the same domain.
P.S: The entire project involves a react app, where at some stage, the user is supposed to do the scorm test, and he will only be allowed to continue if he passed the test. I am not sure if our plan to use iframe is what we should do. I would love to learn if there is a better option.
I have found a way to do it based on this:
https://github.com/hershkoy/react_scrom
The idea is to inject javascript code into the iframe (requires that the iframe and the parent are on the same domain).
The injected javascript code is listening to the button click events, and send a postMessage event to the parent when detects that the course is completed.
<div id="result"></div>
<input id="btn" type="button" value="Go to course" name="btnOpenPopup" onClick="OpenNewWindow()" />
<iframe style="display:none;" id="myiframe" src="http://localhost/training/content" name="course" frameborder="0" style="overflow:hidden;height:100%;width:100%" height="100%" width="100%"></iframe>
<script type="text/javascript">
const iframe = document.getElementById('myiframe');
const iframeWin = iframe.contentWindow || iframe;
const iframeDoc = iframe.contentDocument || iframeWin.document;
function OpenNewWindow() {
iframe.style.display="block";
document.getElementById('result').innerHTML = "";
document.getElementById('btn').style.display="none";
}
function injectThis() {
//alert("hi!");
document.addEventListener('click', (event) => {
console.log("click!");
let chk_condition = event &&
event.target &&
event.target.href &&
event.target.href.includes("exam_completed");
if (chk_condition) {
event.preventDefault();
event.stopPropagation();
window.parent.postMessage({type: 'course:completed'}, '*');
//window.close();
};
});
};
window.addEventListener('message', event => {
// IMPORTANT: check the origin of the data!
if ( true /*event.origin.startsWith('http://localhost:3002')*/) {
// The data was sent from your site.
// Data sent with postMessage is stored in event.data:
console.log(event.data);
if (event.data.type=="course:completed"){
iframe.style.display="none";
document.getElementById('result').innerHTML = "TEST PASSED!";
};
} else {
// The data was NOT sent from your site!
// Be careful! Do not use it. This else branch is
// here just for clarity, you usually shouldn't need it.
return;
}
});
var script = iframeDoc.createElement("script");
script.append('window.onload = ' + injectThis.toString() + ';');
iframeDoc.documentElement.appendChild(script);
</script>
Is it possible to access iframe contents within Jest test?
This is my approach. Unfortunately no luck in there. headerElement is undefined.
document.body.innerHTML = `
<iframe
class="js-iframe"
src="https://example.com"
onload="${iframeLoaded()}"
></iframe>
<script></script>
`;
function iframeLoaded() {
const headerElement = domMethodsService.getElement<HTMLIFrameElement>('.js-iframe')?.contentWindow?.document.getElementsByTagName('h1')
expect(headerElement).toBe('Example Domain');
doneCallback();
}
You are calling iframeLoaded()function before iframe loads it's content. Try creating the iframe element using document.createElement:
const iframe = document.createElement("iframe");
iframe.classList.add("js-iframe");
iframe.onload = iframeLoaded;
iframe.src = "https://example.com";
document.body.appendChild(iframe);
function iframeLoaded() {
const headerElement = iframe.contentWindow.document.querySelector('h1'); //--> getElementsByTagName will return more than one element
expect(headerElement).toBe('Example Domain');
doneCallback();
}
By default, jsdom will not load any sub-resources like iframes. You can load such resources by setting resources: "usable", which will load all usable resources.
jest.config.js
"testEnvironmentOptions": { "resources": "usable" }
I'm trying to just get off the ground with Meteor 1.2.1 and am failing miserably.
I've simply used the code from this question but always receive a blank page. If I remove the Button class, there's no problem with getting the div to appear or text inside it.
I receive no console errors.
My added packages:
twbs:bootstrap 3.3.6
universe:react-bootstrap 0.24.0
react 0.14.3*
Code:
if (Meteor.isClient) {
Meteor.startup(function () {
let App=React.createClass({
render: function () {
return (
<div>
<Button>Default</Button>
</div>
);
}
});
React.render(<App/>, document.getElementById("container"));
});
}
I expect that whatever I'm missing is very simple, but can't narrow it down other then reac-bootstrap being the cause.
Did you require/import the Button component anywhere in your code? Maybe that's what was missing.
In my ignorance, I simply did not follow the universe:react-bootstrap documentation.
As a global
This package additionally export ReactBootstrap as a global, so you
can write inside any .jsx file:
let { Button } = ReactBootstrap;
<Button /> // React component
or
<ReactBootstrap.Button /> // React component
let { Button } = ReactBootstrap;
if (Meteor.isClient) {
Meteor.startup(function () {
let App=React.createClass({
render: function () {
return (
<div>
<Button>Default</Button>
</div>
);
}
});
React.render(<App/>, document.getElementById("container"));
});
}
I'm trying to use redactor.js to edit in place some divs in meteor;
in the template I have:
<template name="home">
<section class="editable">
</section>
...
</template>
and in the js:
Template.home.events({
"click section.editable": function(event) {
$(event.target).redactor();
},
});
this creates the redactor wysiwyg editor correctly when I click on the section; the problem is that by clicking again, another editor (nested inside the previous one is created); I'm trying without success to limit the execution of redactor() method only if the editor is not there already.
Could you wrap the state in a session variable? Of course, you'd need to set it back again once the redactor was finished (maybe try hooking into a blur event?)
Template.home.events({
"click section.editable": function(event) {
var isEditorActive = Session.get("editorActive", false);
if (!isEditorActive) {
Session.set("editorActive",true);
$(event.target).redactor({
blurCallback: function(e)
{
Session.set("editorActive",false);
this.core.destroy(); // destroy redactor ?
}
});
}
}
});
PREVIOUSLY:
Is there a particular reason you want to use meteor events for this? You could just use redactor.
if (Meteor.isClient) {
Meteor.startup(function() {
$('section.editable').redactor({
focus: false
});
});
}
In a project we use the VideoJS player in a Meteor App to play some videos. We have a playlist to navigate though the videos. The problem is, that when the template gets rerendered, the Player cannot be initialized again after that.
I have written a template file and coffescript part for that:
<template name="videoPlayer">
<video id="videoJsPlayer" class="video-js vjs-default-skin"
controls preload="auto" width="572" height="350"
poster="...file.jpg"
>
<source src="...video.mp4" type='video/mp4' />
</video>
</template>
I already tried to work with the ID,
but When I come back to the same video the ID will be the same.
and the coffee-script:
Template.videoPlayer.rendered = ->
videojs.options.flash.swf = "/video-js.swf"
$vid_obj = _V_ "videoJsPlayer", {}, ()->
console.log "Player Loaded"
$vid_obj.ready () ->
console.log("Element ready");
I have also tried to put "vid_obj" somewhere global and calling the videojs "destroy()" method before. That gives an error, that destroy() doesn't exist. Also an V.players = {} to delete all player bindings doesn't work.
I have solved my issue. The Trick was not to apply that styling on the template.
I added the video player via jQuery:
if videojs.players.videoJsPlayer
videojs.players.videoJsPlayer.dispose()
$v = $(".videoPlayerFrame")
$v.html("").append $("<video id=\"videoJsPlayer\" class=\"video-js vjs-default-skin \">")
.attr("controls", true)
.attr("preload", "none")
.attr("width", $v.attr("data-width"))
.attr("height", $v.attr("data-height"))
.attr("poster", $v.attr("data-poster"))
.append("<source src=\""+$v.attr("data-video")+"\" type=\"video/mp4\" />")
$vid_obj = _V_ "videoJsPlayer", {}, ()->
# console.log "video #{vid} is ready.";
console.log "Element Loaded"
Try adding this code,
Template.videoPlayer.destroyed = function () {
var mPlayer = vidoejs("#playerId");
mPlayer.dispose();
}
Each time Meteor render the player template it's destroyed and created. I hope this wont happen in Shark, the new Meteor renderer.