As a Java programmer, I'm new to the OOP-Approach of JavaScript and it's hard for me to find the best way to write code based on objects. I read a lot MDN and across the web to find a good way to code with JavaScript.
Just to see how can it look like, I realized the following functions: Add two INPUT-Elements to a video-element to provide a StartTime (second) and a EndTime (second) to enable a looping of the video in this give time range.
I expect there are already nice frameworks for dealing with video-elements (e. g. VideoJS) - but I just want to know how I can improve the object oriented parts of the code, how to handle events nicely, what is a really good approach to create and use objects, to add methods and so on...
Especially the event-handling (dealing with this inside a addEventListener-Function...) is interesting to me.
I hope this question is interesting also for others and somebody experienced can give me some hints.
Here is the code <HTML-site: index.html>
:
<html>
<head>
<script src="script.js" type="text/javascript"></script>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div id="controls" style="text-align: center"></div>
<div style="text-align: center">
<video id="video1" width="420">
<source src="somevideo.webm" type='video/webm' />
</video>
<p>
<input id="startFrom" type="number" name="startFrom" min="0" max="1000" value="0"> <input id="runUntil"
type="number" name="runUntil" min="0" max="1000" value="0" >
</p>
</div>
<div id="info" style="text-align: center; margin-top: 20px">
<input id="currentTime" type="number" min="0" value="0" readonly>
</div>
</body>
</html>
And here is the corresponding JavaScript script.js:
/**
* This script adds two input controls <startFrom>, <runUntil> to a "VideoPlayer"
* and allows to loop a certain range inside the given video
*
* Only works with HTML5 compatible browsers
*/
;
(function(window, undefined) {
var document = window.document;
/**
* Initial function to ensure the DOM-Content of the website is avaiable
*/
function go() {
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM ready");
new VideoPlayer();
}, false);
}
;
/**
* Wrapper-Class for the Video, which provides the video-Element,
* the control-button and the EventHandling for changing
* the startFrom and runUntil-Input-Elements
*/
function VideoPlayer() {
//global variable for the Video-Handler
_Vid_ = new Video("video1");
_Vid_.setControls();
var startFrom = document.getElementById("startFrom");
var runUntil = document.getElementById("runUntil");
startFrom.addEventListener("change", function(event) {
var value = event.target.value;
_Vid_.startTime = value;
console.log("StartFromValue: " + value);
}, false);
runUntil.addEventListener("change", function(event) {
var value = event.target.value;
if(value==0)
_Vid_.endTime = _Vid_.duration;
else
_Vid_.endTime = value;
console.log("RunUntilValue: " + value);
}, false);
}
/**
* Video-Class (Video-Handler) which provides all fields and methods necessary to
* steer the video
*
* Also initializes the video-instance with everything needed
*/
function Video(elementId) {
this.elementId = elementId;
if (this.elementId === undefined) {
console.log('No Video-Element given!');
return null;
}
console.log("creating element Video");
this.elementId = elementId;
this.videoElement = new Object();
this.videoIsReady = false;
this.startTime = 0.0;
this.endTime = 0.0;
this.duration = 0.0;
this.currentTime = 0.0;
this.source = "none";
this.loopEnabled = false;
this.videoElement = document.getElementById(this.elementId);
this.videoElement.addEventListener("loadedmetadata", function() {
console.log("metadata loaded...");
_Vid_.videoIsReady = true;
_Vid_.endTime = _Vid_.videoElement.duration;
_Vid_.duration = _Vid_.videoElement.duration;
_Vid_.source = _Vid_.videoElement.currentSrc.toString();
console.log(_Vid_.getInfos());
}, false);
//this Event and it's function realizes the loop capability
this.videoElement.addEventListener("timeupdate", function() {
var ct = _Vid_.videoElement.currentTime.valueOf();
_Vid_.currentTime = ct;
var ctElement = document.getElementById("currentTime");
ctElement.setAttribute("value", ct);
if (ct >= _Vid_.endTime) {
_Vid_.videoElement.currentTime = _Vid_.startTime;
console.log("LOOP");
}
}, false);
this.getInfos = function getInfos() {
console.log("getInfos()");
var outputTxt = "StartTime: " + _Vid_.startTime;
outputTxt += "\nDuration: " + _Vid_.duration;
outputTxt += "\nSource: " + _Vid_.source;
return outputTxt;
};
}
//another kind of how to set up a class-method
Video.prototype.setControls = function() {
var playPauseBtn = new VideoControl("playPause", "Play/Pause", "click", function() {
if (_Vid_.videoElement.paused)
_Vid_.videoElement.play();
else
_Vid_.videoElement.pause();
});
var layer = document.getElementById("controls");
layer.appendChild(playPauseBtn.btn);
};
//Class for realizing VideoControl-Buttons
function VideoControl(name, text, event, fn) {
this.name = name;
this.text = text;
this.event = event;
this.btn = document.createElement("button");
var txt = document.createTextNode(text);
this.btn.appendChild(txt);
this.btn.addEventListener(event, fn, false);
}
//call the start function
go();
})(window);
-
\$\begingroup\$ I realize your program is in vanilla JS but if you check out the following video on handling events in jQuery, it just might provide some clarity on the JS subject. You should check out the methods covered in the jQuery source code so you can get a deeper understanding of how you can apply them to your JS. training.bocoup.com/screencasts/more-efficient-event-handlers \$\endgroup\$Jonny Sooter– Jonny Sooter2013年03月20日 15:09:13 +00:00Commented Mar 20, 2013 at 15:09
-
\$\begingroup\$ Thank you for this nice hint/link! Going to dive in... So far I didn't want to use any framework to understand the core javascript better (good approach?)... \$\endgroup\$OrbiVanGebirgi– OrbiVanGebirgi2013年03月20日 15:34:18 +00:00Commented Mar 20, 2013 at 15:34
-
\$\begingroup\$ Yeah! Great way to approach the subject. I posted that link so you can see how the guys at jQuery do it. Not that you should use their framework, but so you can see this in a practical real world example. \$\endgroup\$Jonny Sooter– Jonny Sooter2013年03月20日 15:38:00 +00:00Commented Mar 20, 2013 at 15:38
1 Answer 1
From a once over:
Not sure if this occurred during the copy pasting of your code, but the indentation is bad, for example this:
//another kind of how to set up a class-method Video.prototype.setControls = function() { var playPauseBtn = new VideoControl("playPause", "Play/Pause", "click", function() { if (_Vid_.videoElement.paused) _Vid_.videoElement.play(); else _Vid_.videoElement.pause(); }); var layer = document.getElementById("controls"); layer.appendChild(playPauseBtn.btn); };
should be this:
//another kind of how to set up a class-method Video.prototype.setControls = function() { var playPauseBtn = new VideoControl("playPause", "Play/Pause", "click", function() { if (_Vid_.videoElement.paused) _Vid_.videoElement.play(); else _Vid_.videoElement.pause(); }); var layer = document.getElementById("controls"); layer.appendChild(playPauseBtn.btn); };
- You could also exchange the
if
in that snippet with a ternary operation - You only use
layer
once, you might as well merge that line with the next one That would give:
Video.prototype.setControls = function() { var playPauseBtn = new VideoControl("playPause", "Play/Pause", "click", function() { Vid_.videoElement.paused ? _Vid_.videoElement.play() : _Vid_.videoElement.pause(); }); document.getElementById("controls").appendChild(playPauseBtn.btn); };
- JsHint.com could not find anything serious
- Do not use
console.log
in production code So that this: runUntil.addEventListener("change", function(event) {
var value = event.target.value; if(value==0) _Vid_.endTime = _Vid_.duration; else _Vid_.endTime = value; console.log("RunUntilValue: " + value); }, false);
can be
runUntil.addEventListener("change", function(event) { var value = event.target.value; _Vid_.endTime = value ? value : _Vid_.duration; }, false);
- Since you put everything into an IIFE, you could put 'use strict'; after
(function(window, undefined) {
_Vid_
is a bad name, don't overdo the underscores- Since you should not do
console.log
in production code, you don't needthis.getInfos
at all.
All in all, I think your usage of _Vid_
breaks the OOP approach, I am pretty sure that you cannot run 2 instances of the video element which means it's broken.