Merge pull request #4796 from lduarte1991/lduarte-harvardx-pr18

Annotation Tools: Fixing implicit typecasting and reordering plugins
This commit is contained in:
Sarina Canelake
2014-08-13 20:38:09 -04:00
2 changed files with 2430 additions and 2427 deletions

View File

@@ -352,7 +352,7 @@ CatchAnnotation.prototype = {
// if the default tab is instructor, we must refresh the catch to pull the ones
// under the instructor's email. Calling changeUserId will update this.options.userId
// and most importantly refresh not only the highlights (from Annotator)
// but also the table below from the annotations database server (called Catch).
// but also the table below from the annotations database server (called Catch).
if(this.options.default_tab.toLowerCase() === 'instructor') {
this.changeUserId(this.options.instructor_email);
}
@@ -717,7 +717,7 @@ CatchAnnotation.prototype = {
var isInList = false;
var list = $('#mainCatch .annotationList .annotationRow.item');
for (_i = 0, _len = list.length; _i < _len; _i++) {
if ($(list[_i]).parent().attr('annotationid') === an.id)
if (parseInt($(list[_i]).parent().attr('annotationid'), 10) === an.id)
isInList = true;
}
return isInList;
@@ -800,7 +800,7 @@ CatchAnnotation.prototype = {
$(evt.target).parents('.detailHeader:first').find('#myLocationMap .map').html(imgSrc);
},
_onPlaySelectionClick: function(evt) {
var id = $(evt.target).find('.idAnnotation').html();
var id = parseInt($(evt.target).find('.idAnnotation').html(), 10);
var uri = $(evt.target).find('.uri').html();
var container = $(evt.target).find('.container').html();
if (this.options.externalLink) {
@@ -858,7 +858,7 @@ CatchAnnotation.prototype = {
},
_onZoomToImageBoundsButtonClick: function(evt){
var zoomToBounds = $(evt.target).hasClass('zoomToImageBounds')?$(evt.target):$(evt.target).parents('.zoomToImageBounds:first');
var osdaId = zoomToBounds.find('.idAnnotation').html();
var osdaId = parseInt(zoomToBounds.find('.idAnnotation').html(), 10);
var uri = zoomToBounds.find('.uri').html();
var allannotations = this.annotator.plugins['Store'].annotations;
@@ -887,7 +887,7 @@ CatchAnnotation.prototype = {
},
_onQuoteMediaButton: function(evt) {
var quote = $(evt.target).hasClass('quote')?$(evt.target):$(evt.target).parents('.quote:first');
var id = quote.find('.idAnnotation').html();
var id = parseInt(quote.find('.idAnnotation').html(), 10);
var uri = quote.find('.uri').html();
if (typeof id === 'undefined' || id === ''){
this.refreshCatch();
@@ -927,7 +927,7 @@ CatchAnnotation.prototype = {
},
_refreshReplies: function(evt) {
var item = $(evt.target).parents('.annotationItem:first');
var anId = item.attr('annotationId');
var anId = parseInt(item.attr('annotationId'), 10);
var replyElem = $(evt.target).parents('.annotationItem:first').find('.replies');
var annotator = this.annotator;
@@ -954,7 +954,7 @@ CatchAnnotation.prototype = {
if (typeof replyItems !== 'undefined' && replyItems.length > 0) {
annotations.forEach(function(ann) {
replyItems.each(function(item) {
var id = $(replyItems[item]).attr('annotationid');
var id = parseInt($(replyItems[item]).attr('annotationid'), 10);
if (id === ann.id) {
var perm = self.annotator.plugins.Permissions;
if (!perm.options.userAuthorize('delete', ann, perm.user)) {
@@ -1031,7 +1031,7 @@ CatchAnnotation.prototype = {
if (confirm("Would you like to delete the annotation?")) {
var annotator = this.annotator;
var item = $(evt.target).parents('.annotationItem:first');
var id = item.attr('annotationId');
var id = parseInt(item.attr('annotationId'), 10);
var store = annotator.plugins.Store;
var annotations = store.annotations;
var permissions = annotator.plugins.Permissions;
@@ -1048,7 +1048,7 @@ CatchAnnotation.prototype = {
var annotator = this.annotator;
var item = $(evt.target).parents('.annotationItem:first');
var id = item.attr('annotationId');
var id = parseInt(item.attr('annotationId'), 10);
var store = annotator.plugins.Store;
var annotations = store.annotations;
var permissions = annotator.plugins.Permissions;

View File

@@ -17,12 +17,29 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//----------------Utilities----------------//
var _ref,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
createDateFromISO8601 = function(string) {
// ----------------Utilities---------------- //
var _ref;
var __bind = function(fn, me) {
return function() {
return fn.apply(me, arguments);
};
};
var __hasProp = {}.hasOwnProperty;
var __extends = function(child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key))
child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
var createDateFromISO8601 = function(string) {
var d, date, offset, regexp, time, _ref;
regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?" + "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
d = string.match(new RegExp(regexp));
@@ -57,7 +74,7 @@ var _ref,
date.setTime(Number(time));
return date;
};
var Util = typeof Util !='undefined'? Util:{};
var Util = typeof Util != 'undefined' ? Util : {};
Util.mousePosition = function(e, offsetEl) {
var offset, _ref1;
if ((_ref1 = $(offsetEl).css('position')) !== 'absolute' && _ref1 !== 'fixed' && _ref1 !== 'relative') {
@@ -73,2472 +90,2458 @@ Util.mousePosition = function(e, offsetEl) {
//----------------Load videojs-Annotation Plugin----------------//
(function (){
//-- Load Annotation plugin in videojs
function vjsAnnotation_(options){
var player = this;
//variables to know if it is ready
player.annotations=new vjsAnnotation(player, options);
//When the DOM, Range Slider and the video media is loaded
function initialVideoFinished(event) {
//-- wait for plugins --//
var wrapper = $('.annotator-wrapper').parent()[0],
annotator = $.data(wrapper, 'annotator');
//wait for Annotator and the Share plugin
if (typeof Annotator.Plugin["Share"] === 'function') {
if (typeof annotator.isShareLoaded!='undefined' && annotator.isShareLoaded){
annotator.unsubscribe('shareloaded',initialVideoFinished);
}else{
annotator.subscribe('shareloaded',initialVideoFinished);
return false;
}
}
var plugin = player.annotations;
//All components will be initialize after they have been loaded by videojs
for (var index in plugin.components) {
plugin.components[index].init_();
}
// ----------------Load videojs-Annotation Plugin---------------- //
(function () {
// -- Load Annotation plugin in videojs
function vjsAnnotation_(options){
var player = this;
// variables to know if it is ready
player.annotations = new vjsAnnotation(player, options);
// When the DOM, Range Slider and the video media is loaded
function initialVideoFinished(event) {
// -- wait for plugins -- //
var wrapper = $('.annotator-wrapper').parent()[0];
var annotator = $.data(wrapper, 'annotator');
// wait for Annotator and the Share plugin
if (typeof Annotator.Plugin["Share"] === 'function') {
if (typeof annotator.isShareLoaded != 'undefined' && annotator.isShareLoaded) {
annotator.unsubscribe('shareloaded', initialVideoFinished);
} else {
annotator.subscribe('shareloaded', initialVideoFinished);
return false;
}
}
var plugin = player.annotations;
// All components will be initialize after they have been loaded by videojs
for (var index in plugin.components) {
plugin.components[index].init_();
}
player.annotations.BigNewAn.show();
//set the position of the big buttom
plugin.setposBigNew(plugin.options.posBigNew);
if(!options.showDisplay) plugin.hideDisplay();
if(!options.showStatistics) plugin.hideStatistics();
//Get current instance of annotator
player.annotator = annotator;
plugin.annotator = annotator;
//get annotations
var allannotations = annotator.plugins['Store'].annotations;
plugin.refreshDisplay();
//-- Listener to Range Slider Plugin
player.rangeslider.rstb.on('mousedown', function(){plugin._onMouseDownRS(event)});
//Open the autoPlay from the API
if (player.autoPlayAPI){
var OnePlay = function (){
player.annotations.showAnnotation(player.autoPlayAPI);
$('html,body').animate({
scrollTop: $("#"+player.id_).offset().top},
'slow');
}
if (player.techName == 'Youtube')
setTimeout(OnePlay, 100);//fix the delay playing youtube
else
OnePlay();
}
//set the number of Annotations to display
plugin.refreshDesignPanel();
//check full-screen change
player.on('fullscreenchange',function() {
if (player.isFullScreen) {
$(player.annotator.wrapper[0]).addClass('vjs-fullscreen');
} else {
$(player.annotator.wrapper[0]).removeClass('vjs-fullscreen');
}
plugin.refreshDesignPanel();
});
//loaded plugin
plugin.loaded = true;
}
player.one('loadedRangeSlider', initialVideoFinished);//Loaded RangeSlider
console.log("Loaded Annotation Plugin");
}
videojs.plugin('annotations', vjsAnnotation_);
player.annotations.BigNewAn.show();
// set the position of the big buttom
plugin.setposBigNew(plugin.options.posBigNew);
if(!options.showDisplay)
plugin.hideDisplay();
if(!options.showStatistics)
plugin.hideStatistics();
// Get current instance of annotator
player.annotator = annotator;
plugin.annotator = annotator;
// get annotations
var allannotations = annotator.plugins['Store'].annotations;
plugin.refreshDisplay();
// -- Listener to Range Slider Plugin
player.rangeslider.rstb.on('mousedown', function(){plugin._onMouseDownRS(event)});
// Open the autoPlay from the API
if (player.autoPlayAPI) {
var OnePlay = function () {
player.annotations.showAnnotation(player.autoPlayAPI);
$('html, body').animate({
scrollTop: $("#" + player.id_).offset().top},
'slow');
};
if (player.techName == 'Youtube')
setTimeout(OnePlay, 100); // fix the delay playing youtube
else
OnePlay();
}
// set the number of Annotations to display
plugin.refreshDesignPanel();
// check full-screen change
player.on('fullscreenchange', function() {
if (player.isFullScreen) {
$(player.annotator.wrapper[0]).addClass('vjs-fullscreen');
} else {
$(player.annotator.wrapper[0]).removeClass('vjs-fullscreen');
}
plugin.refreshDesignPanel();
});
// loaded plugin
plugin.loaded = true;
}
player.one('loadedRangeSlider', initialVideoFinished); // Loaded RangeSlider
console.log("Loaded Annotation Plugin");
}
videojs.plugin('annotations', vjsAnnotation_);
//-- Plugin
function vjsAnnotation(player,options){
var player = player || this;
this.player = player;
this.components = {}; // holds any custom components we add to the player
// -- Plugin
function vjsAnnotation(player, options) {
var player = player || this;
this.player = player;
this.components = {}; // holds any custom components we add to the player
options = options || {}; // plugin options
if(!options.hasOwnProperty('posBigNew'))
options.posBigNew = 'none'; // ul = up left || ur = up right || bl = below left || br = below right || c = center
if(!options.hasOwnProperty('showDisplay'))
options.showDisplay = false;
/*if(!options.hasOwnProperty('NumAnnotations'))
options.NumAnnotations = 16; */
if(!options.hasOwnProperty('showStatistics'))
options.showStatistics = false;
this.options = options;
this.init();
}
options = options || {}; // plugin options
if(!options.hasOwnProperty('posBigNew'))
options.posBigNew = 'none'; // ul = up left || ur = up right || bl = below left || br = below right || c = center
if(!options.hasOwnProperty('showDisplay'))
options.showDisplay = false;
if(!options.hasOwnProperty('showStatistics'))
options.showStatistics = false;
this.options = options;
this.init();
}
//-- Methods
vjsAnnotation.prototype = {
/*Constructor*/
init:function(){
var player = this.player || {},
controlBar = player.controlBar,
seekBar = player.controlBar.progressControl.seekBar;
this.updatePrecision = 3;
//Components and Quick Aliases
this.BigNewAn = this.components.BigNewAnnotation = player.BigNewAnnotation;
this.AnConBut = this.components.AnContainerButtons = controlBar.AnContainerButtons;
this.ShowSt = this.components.ShowStatistics = this.AnConBut.ShowStatistics;
this.NewAn = this.components.NewAnnotation = this.AnConBut.NewAnnotation;
this.ShowAn =this.components.ShowAnnotations = this.AnConBut.ShowAnnotations;
this.BackAnDisplay = this.components.BackAnDisplay = controlBar.BackAnDisplay;//Background of the panel
this.AnDisplay = this.components.AnDisplay = controlBar.BackAnDisplay.AnDisplay;//Panel with all the annotations
this.AnStat = this.components.AnStat = controlBar.BackAnDisplay.AnStat;//Panel with statistics of the number of annotations
this.BackAnDisplayScroll = this.components.BackAnDisplayScroll = controlBar.BackAnDisplayScroll;//Back Panel with all the annotations
this.backDSBar = this.components.BackAnDisplayScrollBar = this.BackAnDisplayScroll.BackAnDisplayScrollBar;//Scroll Bar
this.backDSBarSel = this.components.ScrollBarSelector = this.backDSBar.ScrollBarSelector;//Scroll Bar Selector
this.backDSTime = this.components.BackAnDisplayScrollTime = this.BackAnDisplayScroll.BackAnDisplayScrollTime;//Back Panel with time of the annotations in the scroll
this.rsd = this.components.RangeSelectorDisplay = controlBar.BackAnDisplay.RangeSelectorDisplay;//Selection the time to display the annotations
this.rsdl = this.components.RangeSelectorLeft = this.rsd.RangeSelectorLeft;
this.rsdr = this.components.RangeSelectorRight = this.rsd.RangeSelectorRight;
this.rsdb = this.components.RangeSelectorBar = this.rsd.RangeSelectorBar;
this.rsdbl = this.components.RangeSelectorBarL = this.rsdb.RangeSelectorBarL;
this.rsdbr = this.components.RangeSelectorBarR = this.rsdb.RangeSelectorBarR;
this.rs = player.rangeslider;
//local variables
this.editing = false;
var wrapper = $('.annotator-wrapper').parent()[0],
annotator = $.data(wrapper, 'annotator'),
self = this;
//Subscribe to Annotator changes
annotator.subscribe("annotationsLoaded", function (annotations){
if(self.loaded)
self.refreshDisplay();
});
annotator.subscribe("annotationUpdated", function (annotation){
if(self.loaded)
self.refreshDisplay();
});
annotator.subscribe("annotationDeleted", function (annotation){
var annotations = annotator.plugins['Store'].annotations,
tot = typeof annotations !='undefined'?annotations.length:0,
attempts = 0; // max 100
//This is to watch the annotations object, to see when is deleted the annotation
var ischanged = function(){
var new_tot = annotator.plugins['Store'].annotations.length;
if (attempts<100)
setTimeout(function(){
if (new_tot != tot){
if(self.loaded)
self.refreshDisplay();
}else{
attempts++;
ischanged();
}
},100); //wait for the change in the annotations
// -- Methods
vjsAnnotation.prototype = {
/* Constructor */
init: function() {
var player = this.player || {};
var controlBar = player.controlBar;
var seekBar = player.controlBar.progressControl.seekBar;
this.updatePrecision = 3;
// Components and Quick Aliases
this.BigNewAn = this.components.BigNewAnnotation = player.BigNewAnnotation;
this.AnConBut = this.components.AnContainerButtons = controlBar.AnContainerButtons;
this.ShowSt = this.components.ShowStatistics = this.AnConBut.ShowStatistics;
this.NewAn = this.components.NewAnnotation = this.AnConBut.NewAnnotation;
this.ShowAn =this.components.ShowAnnotations = this.AnConBut.ShowAnnotations;
this.BackAnDisplay = this.components.BackAnDisplay = controlBar.BackAnDisplay; // Background of the panel
this.AnDisplay = this.components.AnDisplay = controlBar.BackAnDisplay.AnDisplay; // Panel with all the annotations
this.AnStat = this.components.AnStat = controlBar.BackAnDisplay.AnStat; // Panel with statistics of the number of annotations
this.BackAnDisplayScroll = this.components.BackAnDisplayScroll = controlBar.BackAnDisplayScroll; // Back Panel with all the annotations
this.backDSBar = this.components.BackAnDisplayScrollBar = this.BackAnDisplayScroll.BackAnDisplayScrollBar; // Scroll Bar
this.backDSBarSel = this.components.ScrollBarSelector = this.backDSBar.ScrollBarSelector; // Scroll Bar Selector
this.backDSTime = this.components.BackAnDisplayScrollTime = this.BackAnDisplayScroll.BackAnDisplayScrollTime; // Back Panel with time of the annotations in the scroll
this.rsd = this.components.RangeSelectorDisplay = controlBar.BackAnDisplay.RangeSelectorDisplay; // Selection the time to display the annotations
this.rsdl = this.components.RangeSelectorLeft = this.rsd.RangeSelectorLeft;
this.rsdr = this.components.RangeSelectorRight = this.rsd.RangeSelectorRight;
this.rsdb = this.components.RangeSelectorBar = this.rsd.RangeSelectorBar;
this.rsdbl = this.components.RangeSelectorBarL = this.rsdb.RangeSelectorBarL;
this.rsdbr = this.components.RangeSelectorBarR = this.rsdb.RangeSelectorBarR;
this.rs = player.rangeslider;
// local variables
this.editing = false;
var wrapper = $('.annotator-wrapper').parent()[0];
var annotator = $.data(wrapper, 'annotator');
var self = this;
// Subscribe to Annotator changes
annotator.subscribe("annotationsLoaded", function (annotations) {
if(self.loaded)
self.refreshDisplay();
});
annotator.subscribe("annotationUpdated", function (annotation) {
if(self.loaded)
self.refreshDisplay();
});
annotator.subscribe("annotationDeleted", function (annotation) {
var annotations = annotator.plugins['Store'].annotations;
var tot = typeof annotations !== 'undefined' ? annotations.length : 0;
var attempts = 0; // max 100
// This is to watch the annotations object, to see when is deleted the annotation
var ischanged = function() {
var new_tot = annotator.plugins['Store'].annotations.length;
if (attempts < 100)
setTimeout(function(){
if (new_tot !== tot) {
if(self.loaded)
self.refreshDisplay();
} else {
attempts++;
ischanged();
}
}, 100); // wait for the change in the annotations
};
ischanged();
});
this.BigNewAn.hide(); // Hide until the video is load
},
newan: function(start, end) {
var player = this.player;
var annotator = this.annotator;
var sumPercent = 10; // percentage for the last mark
var currentTime = player.currentTime();
var lastTime = this._sumPercent(currentTime, sumPercent);
var start = typeof start !== 'undefined' ? start : currentTime;
var end = typeof end !== 'undefined' ? end : lastTime;
this._reset();
// set position RS and pause the player
player.showSlider();
player.pause();
player.setValueSlider(start, end);
// This variable is to say the editor that we want create a VideoJS annotation
annotator.editor.VideoJS = this.player.id_;
annotator.adder.show();
this._setOverRS(annotator.adder);
// Open a new annotator dialog
annotator.onAdderClick();
},
showDisplay: function() {
this._reset();
// show
this.BackAnDisplay.removeClass('disable'); // show the Container
this.BackAnDisplayScroll.removeClass('disable'); // show the scroll
// active button
this.ShowAn.addClass('active');
this.options.showDisplay =true;
},
hideDisplay: function() {
// hide
this.BackAnDisplay.addClass('disable'); // hide the Container
this.BackAnDisplayScroll.addClass('disable'); // hide the scroll
// no active button
videojs.removeClass(this.ShowAn.el_, 'active');
this.options.showDisplay =false;
},
showStatistics: function() {
this._reset();
// show
this.BackAnDisplay.removeClass('disable'); // show the Container
this.AnStat.removeClass('disable'); // show Statistics
// mode (this mode will hide the annotations to show the statistics in the container)
this.BackAnDisplay.addClass('statistics'); // mode statistics
// paint
this.AnStat.paintCanvas(); // refresh canvas
// active button
this.ShowSt.addClass('active');
this.options.showStatistics =true;
},
hideStatistics: function() {
// hide
this.BackAnDisplay.addClass('disable'); // hide the Container
this.AnStat.addClass('disable'); // hide Statistics
// remove mode statistics
this.BackAnDisplay.removeClass('statistics');
// no active button
this.ShowSt.removeClass('active');
this.options.showStatistics = false;
},
showAnnotation: function(annotation) {
var isVideo = this._isVideoJS(annotation);
if (isVideo) {
var start = annotation.rangeTime.start;
var end = annotation.rangeTime.end;
var duration = this.player.duration();
var isPoint = videojs.round(start, 3) == videojs.round(end, 3);
this._reset();
// show the range slider
this.rs.show();
// set the slider position
this.rs.setValues(start, end);
// lock the player
this.rs.lock();
// play
if (!isPoint)
this.rs.playBetween(start, end);
// fix small bar
var width = Math.min(1, Math.max(0.005, (this.rs._percent(end - start)))) * 100;
this.rs.bar.el_.style.width = width + '%';
// Add the annotation object to the bar
var bar = isPoint ? this.rs[((duration - start) / duration < 0.1) ? 'left' : 'right'].el_ : this.rs.bar.el_;
var holder = $(this.rs.left.el_).parent()[0];
$(holder).append('<span class="annotator-hl"></div>');
$(bar).appendTo( $(holder).find('.annotator-hl'));
var span = $(bar).parent()[0];
$.data(span, 'annotation', annotation); // Set the object in the span
// set the editor over the range slider
this._setOverRS(this.annotator.editor.element);
this.annotator.editor.checkOrientation();
// hide the panel
this.rs.hidePanel();
}
},
hideAnnotation: function() {
this.rs.hide();
this.rs.showPanel();
// remove the last single showed annotation
var holder = $(this.rs.left.el_).parent()[0];
var holderRight = $(this.rs.right.el_).parent()[0];
if ($(holder).find('.annotator-hl').length > 0) {
$($(holder).find('.annotator-hl')[0].children[0]).appendTo(holder);
$(holder).find('.annotator-hl').remove();
} else if ($(holderRight).find('.annotator-hl').length > 0) {
$($(holderRight).find('.annotator-hl')[0].children[0]).appendTo(holderRight);
$(holderRight).find('.annotator-hl').remove();
}
},
editAnnotation: function(annotation, editor) {
// This will be usefull when we are going to edit an annotation.
if (this._isVideoJS(annotation)) {
this.hideDisplay();
var player = this.player;
var editor = editor || this.annotator.editor;
// show the slider and set in the position
player.showSlider();
player.unlockSlider();
player.setValueSlider(annotation.rangeTime.start, annotation.rangeTime.end);
// show the time panel
player.showSliderPanel();
// set the editor over the range slider
this._setOverRS(editor.element);
editor.checkOrientation();
// set the VideoJS variable
editor.VideoJS = player.id_;
}
},
refreshDisplay: function() {
var count = 0;
var allannotations = this.annotator.plugins['Store'].annotations;
// Sort by date the Array
this._sortByDate(allannotations);
// reset the panel
$(this.AnDisplay.el_).find('span').remove(); // remove the last html items
$(this.player.el_).find('.vjs-anpanel-annotation .annotation').remove(); // remove a deleted annotation without span wrapper
for (var item in allannotations) {
var an = allannotations[item];
// check if the annotation is a video annotation
if (this._isVideoJS(an)){
var div = document.createElement('div');
var span = document.createElement('span');
var start = this.rs._percent(an.rangeTime.start) * 100;
var end = this.rs._percent(an.rangeTime.end) * 100;
var width;
span.appendChild(div);
span.className = "annotator-hl";
width = Math.min(100, Math.max(0.2, end - start));
div.className = "annotation";
div.id = count;
div.style.top = count + "em";
div.style.left = start + '%';
div.style.width = width + '%';
div.start = an.rangeTime.start;
div.end = an.rangeTime.end;
this.AnDisplay.el_.appendChild(span);
// detect point annotations
if (videojs.round(start, 0) == videojs.round(end, 0)) {
$(div).css('width', '');
$(div).addClass("point");
}
// Set the object in the div
$.data(span, 'annotation', an);
// Add the highlights to the annotation
an.highlights = $(span);
count++;
}
};
ischanged();
var start = this.rs._seconds(parseFloat(this.rsdl.el_.style.left) / 100);
var end = this.rs._seconds(parseFloat(this.rsdr.el_.style.left) / 100);
this.showBetween(start, end, this.rsdl.include, this.rsdr.include);
},
showBetween: function (start, end, includeLeft, includeRight) {
var duration = this.player.duration();
var start = start || 0;
var end = end || duration;
var annotationsHTML = $.makeArray($(this.player.el_).find('.vjs-anpanel-annotation .annotator-hl'));
var count = 0;
for (var index in annotationsHTML) {
var an = $.data(annotationsHTML[index], 'annotation');
var expressionLeft = includeLeft ? (an.rangeTime.end >= start) : (an.rangeTime.start >= start);
var expressionRight = includeRight ? (an.rangeTime.start <= end) : (an.rangeTime.end <= end);
if (this._isVideoJS(an) && expressionLeft && expressionRight && typeof an.highlights[0] !== 'undefined') {
var annotationHTML = an.highlights[0].children[0];
annotationHTML.style.marginTop = (-1 * parseFloat(annotationHTML.style.top) + count) + 'em';
$(an.highlights[0]).show();
count++;
} else if (this._isVideoJS(an) && typeof an.highlights[0] !== 'undefined') {
$(an.highlights[0]).hide();
an.highlights[0].children[0].style.marginTop = '';
}
}
// Set the times in the scroll time panel
this.backDSTime.setTimes();
},
setposBigNew: function(pos) {
var pos = pos || 'ul';
var el = this.player.BigNewAnnotation.el_;
videojs.removeClass(el, 'ul');
videojs.removeClass(el, 'ur');
videojs.removeClass(el, 'c');
videojs.removeClass(el, 'bl');
videojs.removeClass(el, 'br');
videojs.addClass(el, pos);
},
pressedKey: function (key) {
var player = this.player;
var rs = this.player.rs;
if (typeof key !== 'undefined' && key == 73) { // -- i key
this._reset();
// show slider
this.rs.show();
// hide other elements
this.rs._reset();
this.rs.setValue(0, player.currentTime());
this.rs.right.el_.style.visibility = 'hidden';
this.rs.tpr.el_.style.visibility = 'hidden';
this.rs.ctpr.el_.style.visibility = 'hidden';
this.rs.bar.el_.style.visibility = 'hidden';
this.lastStartbyKey = player.currentTime();
} else if (typeof key!='undefined' && key==79) { // -- o key
if (this.rs.bar.el_.style.visibility == 'hidden') { // the last action was to type the i key
var start = this.lastStartbyKey != 'undefined' ? this.lastStartbyKey:0;
this.newan(start, player.currentTime());
} else {
this.newan(player.currentTime(), player.currentTime());
}
}
},
refreshDesignPanel: function() {
var player = this.player;
var emtoPx = parseFloat($(this.backDSBar.el_).css('width'));
var playerHeight = parseFloat($(player.el_).css('height'));
var controlBarHeight = parseFloat($(player.controlBar.el_).css('height'));
var newHeight = (playerHeight - controlBarHeight) / emtoPx - 5;
this.BackAnDisplay.el_.style.height = this.backDSBar.el_.style.height = (newHeight + 'em');
this.BackAnDisplay.el_.style.top = this.backDSBar.el_.style.top = "-" + (newHeight + 3 + 'em');
this.BackAnDisplayScroll.el_.children[0].style.top = "-" + (newHeight + 5 + 'em');
this.backDSTime.el_.children[0].style.top = "-" + (newHeight + 5 + 'em');
},
_reset: function() {
// Hide all the components
this.hideDisplay();
this.hideAnnotation();
this.hideStatistics();
this.player.annotator.adder.hide();
this.player.annotator.editor.hide();
this.player.annotator.viewer.hide();
// make visible all the range slider element that maybe were hidden in pressedKey event
this.rs.right.el_.style.visibility = '';
this.rs.tpr.el_.style.visibility = '';
this.rs.ctpr.el_.style.visibility = '';
this.rs.bar.el_.style.visibility = '';
// by default the range slider must be unlocked
this.rs.unlock();
// whether there is a playing selection
this.rs.bar.suspendPlay();
// refresh the design
this.refreshDesignPanel();
},
_setOverRS: function(elem) {
var annotator = this.player.annotator;
var wrapper = $('.annotator-wrapper')[0];
var positionLeft = videojs.findPosition(this.rs.left.el_);
var positionRight = videojs.findPosition(this.rs.right.el_);
var positionAnnotator = videojs.findPosition(wrapper);
var positionAdder = {};
elem[0].style.display = 'block'; // Show the adder
if (this.player.isFullScreen) {
positionAdder.top = positionLeft.top;
positionAdder.left = positionLeft.left + (positionRight.left - positionLeft.left) / 2;
} else {
positionAdder.left = positionLeft.left + (positionRight.left - positionLeft.left) / 2 - positionAnnotator.left;
positionAdder.top = positionLeft.top - positionAnnotator.top;
}
elem.css(positionAdder);
},
_onMouseDownRS: function(event) {
event.preventDefault();
if (!this.rs.options.locked) {
videojs.on(document, "mousemove", videojs.bind(this, this._onMouseMoveRS));
videojs.on(document, "mouseup", videojs.bind(this, this._onMouseUpRS));
}
},
_onMouseMoveRS: function(event) {
var player = this.player;
var annotator = player.annotator;
var rs = player.rangeslider;
annotator.editor.element[0].style.display = 'none';
rs.show();
this._setOverRS(annotator.adder);
},
_onMouseUpRS: function(event) {
videojs.off(document, "mousemove", this._onMouseMoveRS, false);
videojs.off(document, "mouseup", this._onMouseUpRS, false);
var player = this.player;
var annotator = player.annotator;
var rs = player.rangeslider;
annotator.editor.element[0].style.display = 'block';
this._setOverRS(annotator.editor.element);
},
_sumPercent: function(seconds, percent) {
// the percentage is in %
var duration = this.player.duration();
var seconds = seconds || 0;
var percent = percent || 10;
percent = Math.min(100, Math.max(0, percent));
if (isNaN(duration)) {
return 0;
}
return Math.min(duration, Math.max(0, seconds + duration * percent / 100));
},
// Detect if we are creating or editing a video-js annotation
_EditVideoAn: function () {
var annotator = this.annotator;
var isOpenVideojs = (typeof this.player != 'undefined');
var VideoJS = annotator.editor.VideoJS;
return (isOpenVideojs && typeof VideoJS!='undefined' && VideoJS!==-1);
},
// Detect if the annotation is a video-js annotation
_isVideoJS: function (an) {
var player = this.player;
var rt = an.rangeTime;
var isOpenVideojs = (typeof this.player !== 'undefined');
var isVideo = (typeof an.media !== 'undefined' && (an.media === 'video' || an.media === 'audio'));
var isContainer = (typeof an.target !== 'undefined' && an.target.container == player.id_ );
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
var isSource = false;
if (isContainer) {
// Compare without extension
var isYoutube = (isOpenVideojs && typeof this.player.techName !== 'undefined') ? (this.player.techName === 'Youtube') : false;
var targetSrc = isYoutube ? an.target.src : an.target.src.substring(0, an.target.src.lastIndexOf("."));
var playerSrc = isYoutube ? player.options_.sources[0].src : player.options_.sources[0].src.substring(0, player.options_.sources[0].src.lastIndexOf("."));
isSource = (targetSrc === playerSrc);
}
return (isOpenVideojs && isVideo && isContainer && isSource && isNumber);
},
_sortByDate: function (annotations, type) {
var type = type || 'asc'; // asc => The value [0] will be the most recent date
annotations.sort(function(a, b) {
a = new Date(typeof a.updated !== 'undefined' ? createDateFromISO8601(a.updated) : '');
b = new Date(typeof b.updated !== 'undefined' ? createDateFromISO8601(b.updated) : '');
if (type == 'asc')
return (b < a) ? -1 : ((b > a) ? 1 : 0);
else
return (a < b) ? -1 : ((a > b) ? 1 : 0);
});
}
};
// ----------------CREATE new Components for video-js---------------- //
// --Charge the new Component into videojs
videojs.ControlBar.prototype.options_.children.AnContainerButtons = {}; // Container with the css for the buttons
videojs.ControlBar.prototype.options_.children.BackAnDisplay = {}; // Range Slider Time Bar
videojs.ControlBar.prototype.options_.children.BackAnDisplayScroll = {}; // Range Slider Time Bar
videojs.options.children.BigNewAnnotation = {}; // Big Button New Annotation
// -- Player--> BigNewAnnotation
/**
* Create a New Annotation with big Button
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BigNewAnnotation = videojs.Button.extend({
/** @constructor */
init: function(player, options) {
videojs.Button.call(this, player, options);
}
});
videojs.BigNewAnnotation.prototype.init_ = function() {
this.an = this.player_.annotations;
// Hide Button if the user has selected readOnly in the Annotator options
var opts = this.an.options.optionsAnnotator;
if (typeof opts !== 'undefined' && typeof opts.readOnly !== 'undefined' && opts.readOnly)
this.hide();
};
videojs.BigNewAnnotation.prototype.createEl = function() {
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-big-new-annotation vjs-menu-button vjs-control',
innerHTML: '<div class="vjs-big-menu-button vjs-control">A</div>',
title: 'New Annotation',
});
this.BigNewAn.hide(); //Hide until the video is load
},
newan: function(start,end){
var player = this.player,
annotator = this.annotator,
sumPercent = 10,//percentage for the last mark
currentTime = player.currentTime(),
lastTime = this._sumPercent(currentTime,sumPercent);
var start = typeof start!='undefined'?start:currentTime,
end = typeof end!='undefined'?end:lastTime;
this._reset();
//set position RS and pause the player
player.showSlider();
player.pause();
player.setValueSlider(start,end);
//This variable is to say the editor that we want create a VideoJS annotation
annotator.editor.VideoJS = this.player.id_;
annotator.adder.show();
this._setOverRS(annotator.adder);
//Open a new annotator dialog
annotator.onAdderClick();
},
showDisplay: function(){
this._reset();
//show
this.BackAnDisplay.removeClass('disable');//show the Container
this.BackAnDisplayScroll.removeClass('disable');//show the scroll
//active button
this.ShowAn.addClass('active');
this.options.showDisplay =true;
},
hideDisplay: function(){
//hide
this.BackAnDisplay.addClass('disable');//hide the Container
this.BackAnDisplayScroll.addClass('disable');//hide the scroll
//no active button
videojs.removeClass(this.ShowAn.el_, 'active');
this.options.showDisplay =false;
},
showStatistics: function(){
this._reset();
//show
this.BackAnDisplay.removeClass('disable');//show the Container
this.AnStat.removeClass('disable');//show Statistics
//mode (this mode will hide the annotations to show the statistics in the container)
this.BackAnDisplay.addClass('statistics');//mode statistics
//paint
this.AnStat.paintCanvas();//refresh canvas
//active button
this.ShowSt.addClass('active');
this.options.showStatistics =true;
},
hideStatistics: function(){
//hide
this.BackAnDisplay.addClass('disable');//hide the Container
this.AnStat.addClass('disable');//hide Statistics
//remove mode statistics
this.BackAnDisplay.removeClass('statistics');
//no active button
this.ShowSt.removeClass('active');
this.options.showStatistics =false;
},
showAnnotation: function(annotation){
var isVideo = this._isVideoJS(annotation);
if (isVideo){
var start = annotation.rangeTime.start,
end = annotation.rangeTime.end,
duration = this.player.duration(),
isPoint = videojs.round(start,3)==videojs.round(end,3);
this._reset();
//show the range slider
this.rs.show();
//set the slider position
this.rs.setValues(start,end);
//lock the player
this.rs.lock();
//play
if(!isPoint)
this.rs.playBetween(start,end);
//fix small bar
var width = Math.min(1, Math.max(0.005, (this.rs._percent(end-start))))*100;
this.rs.bar.el_.style.width = width+'%';
//Add the annotation object to the bar
var bar = isPoint?this.rs[((duration-start)/duration<0.1)?'left':'right'].el_:this.rs.bar.el_,
holder = $(this.rs.left.el_).parent()[0];
$(holder).append('<span class="annotator-hl"></div>');
$(bar).appendTo( $(holder).find('.annotator-hl'));
var span = $(bar).parent()[0];
$.data(span, 'annotation', annotation);//Set the object in the span
//set the editor over the range slider
this._setOverRS(this.annotator.editor.element);
this.annotator.editor.checkOrientation();
//hide the panel
this.rs.hidePanel();
}
},
hideAnnotation: function(){
this.rs.hide();
this.rs.showPanel();
//remove the last single showed annotation
var holder = $(this.rs.left.el_).parent()[0];
var holderRight = $(this.rs.right.el_).parent()[0];
if ($(holder).find('.annotator-hl').length > 0){
$($(holder).find('.annotator-hl')[0].children[0]).appendTo(holder);
$(holder).find('.annotator-hl').remove();
}else if ($(holderRight).find('.annotator-hl').length > 0){
$($(holderRight).find('.annotator-hl')[0].children[0]).appendTo(holderRight);
$(holderRight).find('.annotator-hl').remove();
}
},
editAnnotation: function(annotation,editor){
//This will be usefull when we are going to edit an annotation.
if (this._isVideoJS(annotation)){
this.hideDisplay();
var player = this.player,
editor = editor || this.annotator.editor;
//show the slider and set in the position
player.showSlider();
player.unlockSlider();
player.setValueSlider(annotation.rangeTime.start,annotation.rangeTime.end);
//show the time panel
player.showSliderPanel();
//set the editor over the range slider
this._setOverRS(editor.element);
editor.checkOrientation();
//set the VideoJS variable
editor.VideoJS = player.id_;
}
},
refreshDisplay: function(){
console.log("loadingAnnotations");
var count = 0,
allannotations = this.annotator.plugins['Store'].annotations;
//Sort by date the Array
this._sortByDate(allannotations);
//reset the panel
$(this.AnDisplay.el_).find('span').remove();//remove the last html items
$(this.player.el_).find('.vjs-anpanel-annotation .annotation').remove();//remove a deleted annotation without span wrapper
for (var item in allannotations) {
var an = allannotations[item];
//check if the annotation is a video annotation
if (this._isVideoJS(an)){
var div = document.createElement('div'),
span = document.createElement('span'),
start = this.rs._percent(an.rangeTime.start) * 100,
end = this.rs._percent(an.rangeTime.end) * 100,
width;
span.appendChild(div);
span.className = "annotator-hl";
width = Math.min(100, Math.max(0.2, end - start));
div.className = "annotation";
div.id = count;
div.style.top = count+"em";
div.style.left = start+'%';
div.style.width = width+'%';
div.start = an.rangeTime.start;
div.end = an.rangeTime.end;
this.AnDisplay.el_.appendChild(span);
//detect point annotations
if(videojs.round(start,0)==videojs.round(end,0)){
$(div).css('width','');
$(div).addClass("point");
}
//Set the object in the div
$.data(span, 'annotation', an);
//Add the highlights to the annotation
an.highlights = $(span);
count++;
}
};
var start = this.rs._seconds(parseFloat(this.rsdl.el_.style.left)/100),
end = this.rs._seconds(parseFloat(this.rsdr.el_.style.left)/100);
this.showBetween(start,end,this.rsdl.include,this.rsdr.include);
},
showBetween: function (start,end,includeLeft,includeRight){
var duration = this.player.duration(),
start = start || 0,
end = end || duration,
annotationsHTML = $.makeArray($(this.player.el_).find('.vjs-anpanel-annotation .annotator-hl')),
count = 0;
for (var index in annotationsHTML){
var an = $.data(annotationsHTML[index], 'annotation'),
expressionLeft = includeLeft?(an.rangeTime.end >= start):(an.rangeTime.start >= start),
expressionRight = includeRight?(an.rangeTime.start <= end):(an.rangeTime.end <= end);
if (this._isVideoJS(an) && expressionLeft && expressionRight && typeof an.highlights[0]!='undefined'){
var annotationHTML = an.highlights[0].children[0];
annotationHTML.style.marginTop = (-1*parseFloat(annotationHTML.style.top)+count) + 'em';
$(an.highlights[0]).show();
count++;
}else if(this._isVideoJS(an) && typeof an.highlights[0]!='undefined'){
$(an.highlights[0]).hide();
an.highlights[0].children[0].style.marginTop = '';
}
}
//Set the times in the scroll time panel
this.backDSTime.setTimes();
},
setposBigNew: function(pos){
var pos = pos || 'ul',
el = this.player.BigNewAnnotation.el_;
videojs.removeClass(el, 'ul');
videojs.removeClass(el, 'ur');
videojs.removeClass(el, 'c');
videojs.removeClass(el, 'bl');
videojs.removeClass(el, 'br');
videojs.addClass(el, pos);
},
pressedKey: function (key){
var player = this.player,
rs = this.player.rs;
if (typeof key!='undefined' && key==73){ //-- i key
this._reset();
//show slider
this.rs.show();
//hide other elements
this.rs._reset();
this.rs.setValue(0,player.currentTime());
this.rs.right.el_.style.visibility = 'hidden';
this.rs.tpr.el_.style.visibility = 'hidden';
this.rs.ctpr.el_.style.visibility = 'hidden';
this.rs.bar.el_.style.visibility = 'hidden';
this.lastStartbyKey = player.currentTime();
}else if (typeof key!='undefined' && key==79){ //-- o key
if (this.rs.bar.el_.style.visibility == 'hidden'){//the last action was to type the i key
var start = this.lastStartbyKey!='undefined'?this.lastStartbyKey:0;
this.newan(start,player.currentTime());
}else{
this.newan(player.currentTime(),player.currentTime());
}
}
},
refreshDesignPanel: function(){
var player = this.player,
emtoPx = parseFloat($(this.backDSBar.el_).css('width')),
playerHeight = parseFloat($(player.el_).css('height')),
controlBarHeight = parseFloat($(player.controlBar.el_).css('height')),
newHeight = (playerHeight - controlBarHeight)/emtoPx-5;
/*this.BackAnDisplay.el_.style.height = this.backDSBar.el_.style.height = (this.options.NumAnnotations+'em');
this.BackAnDisplay.el_.style.top = this.backDSBar.el_.style.top = "-"+(this.options.NumAnnotations+3+'em');
this.BackAnDisplayScroll.el_.children[0].style.top = "-"+(this.options.NumAnnotations+5+'em');
this.backDSTime.el_.children[0].style.top = "-"+(this.options.NumAnnotations+5+'em');*/
this.BackAnDisplay.el_.style.height = this.backDSBar.el_.style.height = (newHeight+'em');
this.BackAnDisplay.el_.style.top = this.backDSBar.el_.style.top = "-"+(newHeight+3+'em');
this.BackAnDisplayScroll.el_.children[0].style.top = "-"+(newHeight+5+'em');
this.backDSTime.el_.children[0].style.top = "-"+(newHeight+5+'em');
},
_reset: function(){
//Hide all the components
this.hideDisplay();
this.hideAnnotation();
this.hideStatistics();
this.player.annotator.adder.hide();
this.player.annotator.editor.hide();
this.player.annotator.viewer.hide();
//make visible all the range slider element that maybe were hidden in pressedKey event
this.rs.right.el_.style.visibility = '';
this.rs.tpr.el_.style.visibility = '';
this.rs.ctpr.el_.style.visibility = '';
this.rs.bar.el_.style.visibility = '';
//by default the range slider must be unlocked
this.rs.unlock();
//whether there is a playing selection
this.rs.bar.suspendPlay();
//refresh the design
this.refreshDesignPanel();
},
_setOverRS: function(elem){
var annotator = this.player.annotator,
wrapper = $('.annotator-wrapper')[0],
positionLeft = videojs.findPosition(this.rs.left.el_),
positionRight = videojs.findPosition(this.rs.right.el_),
positionAnnotator = videojs.findPosition(wrapper),
positionAdder = {};
elem[0].style.display = 'block'; //Show the adder
if (this.player.isFullScreen){
positionAdder.top = positionLeft.top;
positionAdder.left = positionLeft.left + (positionRight.left - positionLeft.left) / 2;
}else{
positionAdder.left = positionLeft.left + (positionRight.left - positionLeft.left) / 2 - positionAnnotator.left;
positionAdder.top = positionLeft.top - positionAnnotator.top;
}
elem.css(positionAdder);
},
_onMouseDownRS: function(event){
event.preventDefault();
//videojs.blockTextSelection();
if(!this.rs.options.locked) {
videojs.on(document, "mousemove", videojs.bind(this,this._onMouseMoveRS));
videojs.on(document, "mouseup", videojs.bind(this,this._onMouseUpRS));
}
},
_onMouseMoveRS: function(event) {
var player = this.player,
annotator = player.annotator,
rs = player.rangeslider;
annotator.editor.element[0].style.display = 'none';
rs.show();
this._setOverRS(annotator.adder);
},
_onMouseUpRS: function(event){
videojs.off(document, "mousemove", this._onMouseMoveRS, false);
videojs.off(document, "mouseup", this._onMouseUpRS, false);
var player = this.player,
annotator = player.annotator,
rs = player.rangeslider;
annotator.editor.element[0].style.display = 'block';
this._setOverRS(annotator.editor.element);
},
_sumPercent: function(seconds,percent) {
//the percentage is in %
var duration = this.player.duration();
var seconds = seconds || 0;
var percent = percent || 10;
percent = Math.min(100, Math.max(0, percent));
if(isNaN(duration)) {
return 0;
}
return Math.min(duration, Math.max(0, seconds + duration * percent / 100));
},
//Detect if we are creating or editing a video-js annotation
_EditVideoAn: function (){
var annotator = this.annotator,
isOpenVideojs = (typeof this.player != 'undefined'),
VideoJS = annotator.editor.VideoJS;
return (isOpenVideojs && typeof VideoJS!='undefined' && VideoJS!==-1);
},
//Detect if the annotation is a video-js annotation
_isVideoJS: function (an){
var player = this.player,
rt = an.rangeTime,
isOpenVideojs = (typeof this.player != 'undefined'),
isVideo = (typeof an.media!='undefined' && (an.media=='video' || an.media=='audio')),
isContainer = (typeof an.target!='undefined' && an.target.container==player.id_ ),
isNumber = (typeof rt!='undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end)),
isSource = false;
if(isContainer){
//Compare without extension
var isYoutube = (isOpenVideojs && typeof this.player.techName!='undefined')?(this.player.techName == 'Youtube'):false,
targetSrc = isYoutube?an.target.src:an.target.src.substring(0,an.target.src.lastIndexOf(".")),
playerSrc = isYoutube?player.options_.sources[0].src:player.options_.sources[0].src.substring(0,player.options_.sources[0].src.lastIndexOf("."));
isSource = (targetSrc == playerSrc);
}
return (isOpenVideojs && isVideo && isContainer && isSource && isNumber);
},
_sortByDate: function (annotations,type){
var type = type || 'asc'; //asc => The value [0] will be the most recent date
annotations.sort(function(a,b){
a = new Date(typeof a.updated!='undefined'?createDateFromISO8601(a.updated):'');
b = new Date(typeof b.updated!='undefined'?createDateFromISO8601(b.updated):'');
if (type == 'asc')
return b<a?-1:b>a?1:0;
else
return a<b?-1:a>b?1:0;
});
}
};
//----------------CREATE new Components for video-js----------------//
//--Charge the new Component into videojs
videojs.ControlBar.prototype.options_.children.AnContainerButtons={}; //Container with the css for the buttons
videojs.ControlBar.prototype.options_.children.BackAnDisplay={}; //Range Slider Time Bar
videojs.ControlBar.prototype.options_.children.BackAnDisplayScroll={}; //Range Slider Time Bar
videojs.options.children.BigNewAnnotation={}; //Big Button New Annotation
//-- Player--> BigNewAnnotation
/**
* Create a New Annotation with big Button
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BigNewAnnotation = videojs.Button.extend({
/** @constructor */
init: function(player, options){
videojs.Button.call(this, player, options);
}
});
videojs.BigNewAnnotation.prototype.init_ = function(){
this.an = this.player_.annotations;
//Hide Button if the user has selected readOnly in the Annotator options
var opts = this.an.options.optionsAnnotator;
if (typeof opts!='undefined' && typeof opts.readOnly!='undefined' && opts.readOnly)
this.hide();
};
videojs.BigNewAnnotation.prototype.createEl = function(){
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-big-new-annotation vjs-menu-button vjs-control',
innerHTML: '<div class="vjs-big-menu-button vjs-control">A</div>',
title: 'New Annotation',
});
};
videojs.BigNewAnnotation.prototype.onClick = function(){
this.an.newan();
};
//-- Player--> ControlBar--> AnContainerButtons
/**
* Container for the button CSS
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.AnContainerButtons = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.AnContainerButtons.prototype.init_ = function(){};
videojs.AnContainerButtons.prototype.options_ = {
children: {
'ShowStatistics': {},
'ShowAnnotations': {},
'NewAnnotation': {},
}
};
videojs.AnContainerButtons.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-container-button-annotation vjs-menu-button vjs-control',
});
};
//-- Player--> ControlBar--> AnContainerButtons--> ShowStatistics
/**
* Button for show/hide the chart with statistics of the annotation's number
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.ShowStatistics = videojs.Button.extend({
/** @constructor */
init: function(player, options){
videojs.Button.call(this, player, options);
}
});
videojs.ShowStatistics.prototype.init_ = function(){
this.an = this.player_.annotations;
};
videojs.ShowStatistics.prototype.createEl = function(){
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-statistics-annotation vjs-menu-button vjs-control',
title: 'Show the Statistics',
});
};
videojs.ShowStatistics.prototype.onClick = function(){
if (!this.an.options.showStatistics) this.an.showStatistics();
else this.an.hideStatistics();
};
//-- Player--> ControlBar--> AnContainerButtons--> ShowAnnotations
/**
* Button for show/hide the annotation panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.ShowAnnotations = videojs.Button.extend({
/** @constructor */
init: function(player, options){
videojs.Button.call(this, player, options);
}
});
videojs.ShowAnnotations.prototype.init_ = function(){
this.an = this.player_.annotations;
};
videojs.ShowAnnotations.prototype.createEl = function(){
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-showannotations-annotation vjs-menu-button vjs-control',
title: 'Show Annotations',
});
};
videojs.ShowAnnotations.prototype.onClick = function(){
if (!this.an.options.showDisplay) this.an.showDisplay();
else this.an.hideDisplay();
};
//-- Player--> ControlBar--> AnContainerButtons--> NewAnnotation
/**
* Create a New Annotation
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.NewAnnotation = videojs.Button.extend({
/** @constructor */
init: function(player, options){
videojs.Button.call(this, player, options);
}
});
videojs.NewAnnotation.prototype.init_ = function(){
this.an = this.player_.annotations;
//Hide Button if the user has selected readOnly in the Annotator options
var opts = this.an.options.optionsAnnotator;
if (typeof opts!='undefined' && typeof opts.readOnly!='undefined' && opts.readOnly)
this.hide();
};
videojs.NewAnnotation.prototype.createEl = function(){
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-new-annotation vjs-menu-button vjs-control',
title: 'New Annotation',
});
};
videojs.NewAnnotation.prototype.onClick = function(){
this.an.newan();
};
//-- Player--> ControlBar--> BackAnDisplay
/**
* The background annotations panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BackAnDisplay = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.BackAnDisplay.prototype.init_ = function(){
this.an = this.player_.annotations
self = this;
//Fix error resizing the display panel. The scroll always went up.
$(this.el_).watch('font-size', function(){
self.an.backDSBarSel.setPosition(self.an.BackAnDisplayScroll.currentValue,false);
});
};
videojs.BackAnDisplay.prototype.options_ = {
children: {
'RangeSelectorDisplay': {},
'AnDisplay': {},
'AnStat': {},
}
};
videojs.BackAnDisplay.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-back-anpanel-annotation',
});
};
//-- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay
/**
* The selector to show the annotations in a time selection
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorDisplay = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
}
});
videojs.RangeSelectorDisplay.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
var duration = this.an.player.duration();
this.start = 0;
this.end = duration;
//set the selection area in the extreme position
this.setPosition(0,0,false);
this.setPosition(1,this.rs._percent(duration),false);
};
videojs.RangeSelectorDisplay.prototype.options_ = {
children: {
'RangeSelectorLeft': {},
'RangeSelectorRight': {},
'RangeSelectorBar': {},
}
};
videojs.RangeSelectorDisplay.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-rangeselector-anpanel-annotation',
});
};
videojs.RangeSelectorDisplay.prototype.onMouseDown = function(event) {
event.preventDefault();
//videojs.blockTextSelection();
videojs.on(document, "mousemove", videojs.bind(this,this.onMouseMove));
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
videojs.removeClass(this.an.rsdb.el_,'disable');
};
videojs.RangeSelectorDisplay.prototype.onMouseUp = function(event) {
videojs.off(document, "mousemove", this.onMouseMove, false);
videojs.off(document, "mouseup", this.onMouseUp, false);
videojs.addClass(this.an.rsdb.el_,'disable');
};
videojs.RangeSelectorDisplay.prototype.onMouseMove = function(event) {
var left = this.calculateDistance(event);
if (this.an.rsdl.pressed)
this.setPosition(0,left);
else if (this.an.rsdr.pressed)
this.setPosition(1,left);
//move the frame to the position of the arrow
this.an.player.currentTime(this.rs._seconds(left));
};
videojs.RangeSelectorDisplay.prototype.calculateDistance = function(event){
var rstbX = this.getRSTBX();
var rstbW = this.getRSTBWidth();
var handleW = this.getWidth();
// Adjusted X and Width, so handle doesn't go outside the bar
rstbX = rstbX + (handleW / 2);
rstbW = rstbW - handleW;
// Percent that the click is through the adjusted area
return Math.max(0, Math.min(1, (event.pageX - rstbX) / rstbW));
};
videojs.RangeSelectorDisplay.prototype.getRSTBWidth = function() {
return this.el_.offsetWidth;
};
videojs.RangeSelectorDisplay.prototype.getRSTBX = function() {
return videojs.findPosition(this.el_).left;
};
videojs.RangeSelectorDisplay.prototype.getWidth = function() {
var arrow = $(this.an.rsdl.el_).find('.vjs-selector-arrow')[0];
return arrow.offsetWidth;//does not matter left or right
};
videojs.RangeSelectorDisplay.prototype.setPosition = function(index,left,changeTime) {
//index = 0 for left side, index = 1 for right side
var index = index || 0,
changeTime = typeof changeTime!='undefined'?changeTime:true;
// Check for invalid position
if(isNaN(left))
return false;
// Check index between 0 and 1
if(!(index === 0 || index === 1))
return false;
// Alias
var ObjLeft = this.an.rsdl.el_,
ObjRight = this.an.rsdr.el_,
Obj = this.an[index === 0 ? 'rsdl' : 'rsdr'].el_;
//Check if left arrow is over the right arrow
if ((index === 0 ?this.updateLeft(left):this.updateRight(left))){
if (index===1){//right
Obj.style.left = (left * 100)+'%';
Obj.style.width = ((1-left) * 100)+'%';
}else{//left
Obj.style.left = (left * 100)+'%';
Obj.style.width = ((left) * 100)+'%';
}
this[index === 0 ? 'start' : 'end'] = this.rs._seconds(left);
//Fix the problem when you press the button and the two arrow are underhand
//left.zIndex = 10 and right.zIndex=20. This is always less in this case:
if (index === 0 && (left * 100) >= 90)
$(ObjLeft).find('.vjs-selector-arrow')[0].style.zIndex = 25;
else
$(ObjLeft).find('.vjs-selector-arrow')[0].style.zIndex = 10;
//-- Panel
/*var MaxP,MinP,MaxDisP;
MaxP = this.player_.isFullScreen?96:92;
MinP = this.player_.isFullScreen?0.1:0.5;
MaxDisP = this.player_.isFullScreen?3.75:7.5;*/
var rsdbl = this.an.rsdbl.el_,
rsdbr = this.an.rsdbr.el_,
distance = parseFloat(ObjRight.style.left)-parseFloat(ObjLeft.style.left);
if (index===0)
rsdbl.children[0].innerHTML = videojs.formatTime(this.rs._seconds(left));
else
rsdbr.children[0].innerHTML = videojs.formatTime(this.rs._seconds(left));
if (typeof distance!='undefined' && distance <= 12.5){
if(parseFloat(ObjLeft.style.left)<7){
rsdbl.style.top = (-1.5) + 'em';rsdbl.style.left = 1 + 'em';
}else{
rsdbl.style.left = (-2.5) + 'em';rsdbl.style.top = '';
}
if(parseFloat(ObjRight.style.left)>93){
rsdbr.style.top = (-1.5) + 'em';rsdbr.style.right = 1 + 'em';
}else{
rsdbr.style.right = (-2.5) + 'em';rsdbr.style.top = '';
}
}else{
rsdbl.style.left = 1 + 'em';
rsdbr.style.right = 1 + 'em';
rsdbl.style.top = '';
rsdbr.style.top = '';
}
var start = this.rs._seconds(parseFloat(ObjLeft.style.left)/100),
end = this.rs._seconds(parseFloat(ObjRight.style.left)/100);
if(changeTime)
this.an.showBetween(start,end,this.an.rsdl.include,this.an.rsdr.include);
}
return true;
};
videojs.RangeSelectorDisplay.prototype.updateLeft = function(left) {
var rightVal = this.an.rsdr.el_.style.left!=''?this.an.rsdr.el_.style.left:100;
var right = parseFloat(rightVal) / 100,
bar = this.an.rsdb.el_;
var width = videojs.round((right - left),this.an.updatePrecision); //round necessary for not get 0.6e-7 for example that it's not able for the html css width
//(right+0.00001) is to fix the precision of the css in html
if(left <= (right+0.00001)) {
bar.style.left = (left * 100) + '%';
bar.style.width = (width * 100) + '%';
return true;
}
return false;
};
videojs.RangeSelectorDisplay.prototype.updateRight = function(right) {
var leftVal = this.an.rsdl.el_.style.left!=''?this.an.rsdl.el_.style.left:0;
var left = parseFloat(leftVal) / 100,
bar = this.an.rsdb.el_;
var width = videojs.round((right - left),this.an.updatePrecision); //round necessary for not get 0.6e-7 for example that it's not able for the html css width
//(right+0.00001) is to fix the precision of the css in html
if((right+0.00001) >= left) {
bar.style.width = (width * 100) + '%';
bar.style.left = ((right - width) * 100) + '%';
return true;
}
return false;
};
//-- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorLeft
/**
* Left Time selector
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorLeft = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.on('dblclick', this.ondblclick);
this.pressed = false;//to know when is mousedown
this.include = true;//to know when we want to include the boundary time in the selection or not
}
});
videojs.RangeSelectorLeft.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
videojs.addClass(this.el_, 'include');
};
videojs.RangeSelectorLeft.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-leftselector-anpanel-annotation',
innerHTML: '<div class="vjs-selector-arrow" title="Left Annotation Selector"></div><div class="vjs-leftselector-back"></div>'
});
};
videojs.RangeSelectorLeft.prototype.onMouseDown = function(event) {
event.preventDefault();
//videojs.blockTextSelection();
this.pressed = true;
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
videojs.addClass(this.el_, 'active');
videojs.addClass(this.el_.parentNode, 'active');
};
videojs.RangeSelectorLeft.prototype.onMouseUp = function(event) {
videojs.off(document, "mouseup", this.onMouseUp, false);
videojs.removeClass(this.el_, 'active');
videojs.removeClass(this.el_.parentNode, 'active');
this.pressed = false;
};
videojs.RangeSelectorLeft.prototype.ondblclick = function(event) {
if (this.include){
this.include = false;
videojs.removeClass(this.el_, 'include');
}else{
this.include = true;
videojs.addClass(this.el_, 'include');
}
var left = this.an.rsd.calculateDistance(event);
this.an.rsd.setPosition(0,left);
};
//-- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorRight
/**
* Right Time selector
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorRight = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.on('dblclick', this.ondblclick);
this.pressed = false;//to know when is mousedown
this.include = true;//to know when we want to include the boundary time in the selection or not
}
});
videojs.RangeSelectorRight.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
videojs.addClass(this.el_, 'include');
};
videojs.RangeSelectorRight.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-rightselector-anpanel-annotation',
innerHTML: '<div class="vjs-selector-arrow" title="Right Annotation Selector"></div><div class="vjs-rightselector-back"></div>'
});
};
videojs.RangeSelectorRight.prototype.onMouseDown = function(event) {
event.preventDefault();
//videojs.blockTextSelection();
this.pressed = true;
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
videojs.addClass(this.el_, 'active');
videojs.addClass(this.el_.parentNode, 'active');
};
videojs.RangeSelectorRight.prototype.onMouseUp = function(event) {
videojs.off(document, "mouseup", this.onMouseUp, false);
videojs.removeClass(this.el_, 'active');
videojs.removeClass(this.el_.parentNode, 'active');
this.pressed = false;
};
videojs.RangeSelectorRight.prototype.ondblclick = function(event) {
if (this.include){
this.include = false;
videojs.removeClass(this.el_, 'include');
}else{
this.include = true;
videojs.addClass(this.el_, 'include');
}
var left = this.an.rsd.calculateDistance(event);
this.an.rsd.setPosition(1,left);
};
//-- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar
/**
* Bar to display the selected Time
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorBar = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.RangeSelectorBar.prototype.init_ = function(){
videojs.addClass(this.el_,'disable');
};
videojs.RangeSelectorBar.prototype.options_ = {
children: {
'RangeSelectorBarL': {},
'RangeSelectorBarR': {},
}
};
videojs.RangeSelectorBar.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-barselector-anpanel-annotation',
});
};
//-- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar--> RangeSelectorBarL
/**
* This is the left time panel for RangeSelectorBar
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorBarL = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.RangeSelectorBarL.prototype.init_ = function(){};
videojs.RangeSelectorBarL.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-barselector-left',
innerHTML: '<span class="vjs-time-text">00:00</span>',
});
};
//-- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar--> RangeSelectorBarR
/**
* This is the right time panel for RangeSelectorBar
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorBarR = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.RangeSelectorBarR.prototype.init_ = function(){};
videojs.RangeSelectorBarR.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-barselector-right',
innerHTML: '<span class="vjs-time-text">00:00</span>'
});
};
//-- Player--> ControlBar--> BackAnDisplay--> AnDisplay
/**
* Show the annotations in a panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.AnDisplay = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.on('mouseover', this.onMouseOver);
}
});
videojs.AnDisplay.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
this.transition = false;
};
videojs.AnDisplay.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-anpanel-annotation',
});
};
videojs.AnDisplay.prototype.onMouseDown = function(event){
var elem = $(event.target).parents('.annotator-hl').andSelf(),
_self = this;
if (elem.hasClass("annotator-hl")){
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
//Clone the bar box to make the animation
var boxup = document.createElement('div'),
ElemTop = parseFloat(elem[1].style.top),
ElemMargin = parseFloat(elem[1].style.marginTop),
emtoPx = parseFloat($(elem[1]).css('height')),
isPoint = $(elem[1]).hasClass("point");
boxup.className = isPoint?"boxup-dashed-line point":"boxup-dashed-line";
boxup.style.left = elem[1].style.left;
boxup.style.width = elem[1].style.width;
boxup.style.top = (ElemTop+ElemMargin-this.el_.scrollTop/emtoPx)+'em';
elem[0].parentNode.parentNode.appendChild(boxup);
}
}
videojs.AnDisplay.prototype.onMouseUp = function(event){
if (typeof this.lastelem == 'undefined')
return false;
var elem = this.lastelem,
_self = this;
if (elem.hasClass("annotator-hl")){
var annotation = elem.map(function() {
return $(this).data("annotation");
})[0];
var displayHeight = (-1)*parseFloat($(this.el_).parent()[0].style.top),
emtoPx = parseFloat($(elem[1]).css('height'));
if (typeof $(elem).parent().parent().find('.boxup-dashed-line')[0]!='undefined'){
$(elem).parent().parent().find('.boxup-dashed-line')[0].style.top=(displayHeight-2)+'em';
}
this.an.player.pause();
this.transition = true;
window.setTimeout(function () {
_self.an.showAnnotation(annotation);
_self.transition = false;
_self.onCloseViewer();
}, 900);
}
videojs.off(document, "mouseup", this.onMouseUp, false);
};
videojs.AnDisplay.prototype.onMouseOver = function(event){
if (!this.transition && !this.an.rsdl.pressed && !this.an.rsdr.pressed){
var annotator = this.an.annotator;
var elem = $(event.target).parents('.annotator-hl').andSelf();
//if there is a opened annotation then show the new annotation mouse over
if (typeof annotator!='undefined' && annotator.viewer.isShown() && elem.hasClass("annotator-hl")){
//hide the last open viewer
annotator.viewer.hide();
//get the annotation over the mouse
var annotations = elem.map(function() {
return $(this).data("annotation");
});
//show the annotation in the viewer
annotator.showViewer($.makeArray(annotations), Util.mousePosition(event, annotator.wrapper[0]));
}
//create dashed line
elem.addClass('active');
if (typeof elem != 'undefined' && $(elem[1]).hasClass('annotation')){
//create dashed line under the bar
var dashed = document.createElement('div'),
boxdown = document.createElement('div'),
DisplayHeight = parseFloat(this.an.BackAnDisplay.el_.style.height),
ElemMarginTop = elem[1].style.marginTop!=''?parseFloat(elem[1].style.marginTop):0;
ElemTop = parseFloat(elem[1].style.top)+ElemMarginTop,
emtoPx = parseFloat($(elem[1]).css('height')),
isPoint = $(elem[1]).hasClass("point");
dashed.className = isPoint?'dashed-line point':'dashed-line';
boxdown.className = "box-dashed-line";
dashed.style.left = boxdown.style.left = elem[1].style.left;
dashed.style.width = boxdown.style.width = isPoint?'0':elem[1].style.width;
dashed.style.top = ((ElemTop+1)-this.el_.scrollTop/emtoPx)+'em';
dashed.style.height = ((DisplayHeight-ElemTop+2)+this.el_.scrollTop/emtoPx)+'em';//get the absolute value of the top to put in the height
boxdown.style.top = (DisplayHeight+2)+'em';
elem[0].parentNode.parentNode.appendChild(dashed);
elem[0].parentNode.parentNode.appendChild(boxdown);
$(this.player).find('.vjs-play-progress').css('z-index', 2);
$(this.player).find('.vjs-seek-handle').css('z-index', 2);
}
//store the last selected item
if (elem.hasClass("annotator-hl"))
this.lastelem = elem;
}
};
videojs.AnDisplay.prototype.onCloseViewer = function(){
if (!this.transition){
if (typeof this.lastelem != 'undefined')
this.lastelem.removeClass('active');
//remove dashed line
if (typeof this.lastelem != 'undefined' && this.lastelem.hasClass("annotator-hl")){
$(this.lastelem).parent().parent().find('.dashed-line').remove();
$(this.lastelem).parent().parent().find('.box-dashed-line').remove();
$(this.lastelem).parent().parent().find('.boxup-dashed-line').remove();
$(this.player).find('.vjs-play-progress').css('z-index', "");
$(this.player).find('.vjs-seek-handle').css('z-index', "");
}
}
};
videojs.AnDisplay.prototype.countVisibles = function() {
var AnArray = $.makeArray(this.el_.children);
//Count visible annotations in Panel
var count = 0;
for (var index in AnArray){
var an = AnArray[index];
if (an.style.display!='none'){
count++;
}
}
return count;
};
//-- Player--> ControlBar--> BackAnDisplay--> AnStat
/**
* Display with a chart with the statistics of the number of Annotations
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.AnStat = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.marginTop = 20;
this.marginBottom = 0;
}
});
videojs.AnStat.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
this.canvas = this.el_.children[0];
};
videojs.AnStat.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-anstat-annotation',
innerHTML: '<canvas class="vjs-char-anstat-annotation">Your browser does not support the HTML5 canvas tag.</canvas>',
});
};
videojs.AnStat.prototype.paintCanvas = function(){
var ctx=this.canvas.getContext("2d"),
points = this._getPoints(),
w = this._getWeights(points),
maxEn = this._getMaxArray(points,'entries'),
TotAn = this.an.AnDisplay.el_.children.length;
duration = this.an.player.duration();
//set the position of the canvas
this.canvas.style.marginTop = Math.round(this.marginTop)+'px';
//Add the Max Concentration and Number of annotations
if($(this.canvas).parent().find('.vjs-totan-anstat-annotation').length==0){
$(this.canvas).parent().append('<div class="vjs-totan-anstat-annotation">');
$(this.canvas).parent().append('<div class="vjs-maxcon-anstat-annotation">');
}
var textCanvas = $(this.canvas).parent().find('.vjs-totan-anstat-annotation')[0];
textCanvas.innerHTML = TotAn+' total annotations';
var textCanvas = $(this.canvas).parent().find('.vjs-maxcon-anstat-annotation')[0];
textCanvas.innerHTML = 'Max Annotations = '+maxEn;
//Added dashed line function to paint
if (window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype.lineTo) {
CanvasRenderingContext2D.prototype.dashedLine = function(x1, y1, x2, y2, dashLen) {
if (dashLen == undefined) dashLen = 2;
this.beginPath();
this.moveTo(x1, y1);
var dX = x2 - x1;
var dY = y2 - y1;
var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
var dashX = dX / dashes;
var dashY = dY / dashes;
var q = 0;
while (q++ < dashes) {
x1 += dashX;
y1 += dashY;
this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x1, y1);
}
this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x2, y2);
this.stroke();
this.closePath();
};
};
//set the canvas size
this.canvas.height = this.an.AnDisplay.el_.offsetHeight-(this.marginTop+this.marginBottom);
this.canvas.width = this.an.AnDisplay.el_.offsetWidth;
ctx.beginPath();
ctx.strokeStyle="rgb(255, 163, 0)";
var lastSe = 0, lastEn = 0;
ctx.moveTo(0,maxEn*w.Y); //Move pointer to 0,0
for (var index in points){
var p = points[index],
x1 =lastSe*w.X, y1 =(maxEn-lastEn)*w.Y, // Old Point
x2 =p.second*w.X, y2 =(maxEn-p.entries)*w.Y; // New Point
//new line
ctx.lineTo(x2,y1); //move horizontally to the new point
ctx.moveTo(x2,y1); //Move pointer
ctx.lineTo(x2,y2); //move vertically to the new point height
ctx.moveTo(x2,y2); //Prepare pointer for a new instance
//new rectangle under the curve
ctx.fillStyle="rgba(0, 0, 0,0.5)";
ctx.fillRect(x1,y1,(x2-x1),(maxEn*w.Y-y1));
//store the last point
lastSe = p.second;
lastEn = p.entries;
}
//set the graphic to the end of the video
ctx.lineTo(lastSe*w.X,maxEn*w.Y);
ctx.moveTo(lastSe*w.X,maxEn*w.Y);
ctx.lineTo(duration*w.X,maxEn*w.Y);
ctx.stroke();
//dashed line down
ctx.beginPath();
ctx.dashedLine(0,maxEn*w.Y, duration*w.X, maxEn*w.Y, 8);
ctx.stroke();
//dashed line top
ctx.beginPath();
ctx.dashedLine(0,0, duration*w.X, 0, 8);
ctx.stroke();
};
videojs.AnStat.prototype._getWeights = function(points){
var weight = {},
panel = $(this.an.AnDisplay.el_),
maxSe = this.an.player.duration(),
maxEn = this._getMaxArray(points,'entries'),
panelW = parseFloat(panel.css('width')),
panelH = parseFloat(panel.css('height'))-(this.marginTop+this.marginBottom);
weight.X = maxSe != 0? (panelW / maxSe):0;
weight.Y = maxEn != 0? (panelH / maxEn):0;
return weight;
};
videojs.AnStat.prototype._getMaxArray = function(points,variable){
var highest = 0,
tmp;
for (var index in points){
tmp = points[index][variable];
if (tmp > highest) highest = tmp;
}
return highest;
};
videojs.AnStat.prototype._getPoints = function(){
var points = [],
allannotations = this.an.annotator.plugins['Store'].annotations;
for (var index in allannotations){
var an = allannotations[index],
start,end;
if (this.an._isVideoJS(an)){
start = an.rangeTime.start;
end = an.rangeTime.end;
//start
if(!this._isFound(points,start)){
points.push({
second:an.rangeTime.start,
entries:this._getNumberAnnotations(start)
});
if (an.rangeTime.start==an.rangeTime.end){//is a point
points.push({
second:an.rangeTime.end,
entries:this._getNumberAnnotations(end,true)
});
}
}
//end
if(!this._isFound(points,end)){
points.push({
second:an.rangeTime.end,
entries:this._getNumberAnnotations(end,true)
});
}
found = false;
}
}
points.sort(function(a,b) {return parseFloat(a.second) - parseFloat(b.second)});
return points;
};
videojs.AnStat.prototype._isFound = function(array,elem){
var found = false;
for (var indexA in array){
if(typeof array[indexA].second!='undefined' && array[indexA].second == elem)
found = true;
}
return found;
};
videojs.AnStat.prototype._getNumberAnnotations = function(time,end){
var num = (typeof end!='undefined' && end)?-1:0,
allannotations = this.an.annotator.plugins['Store'].annotations;
for (var index in allannotations){
var an = allannotations[index];
if (this.an._isVideoJS(an)){
if(an.rangeTime.start<=time && an.rangeTime.end>=time)
num++;
}
}
return num;
};
//-- Player--> ControlBar--> BackAnDisplayScroll
/**
* The background annotations panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BackAnDisplayScroll = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.UpValue = 0.1;
this.currentValue = 0;
}
});
videojs.BackAnDisplayScroll.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
this.mousedownID = -1;
var self = this,
direction;
//Firefox
$(this.an.AnDisplay.el_).bind('DOMMouseScroll', function(e){
if(e.originalEvent.detail > 0)
direction = self.UpValue;
else
direction = -self.UpValue;
self.an.backDSBarSel.setPosition(self.getPercentScroll()+direction);
return false;
});
//IE, Opera, Safari
$(this.an.AnDisplay.el_).bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta < 0)
direction = self.UpValue;
else
direction = -self.UpValue;
self.an.backDSBarSel.setPosition(self.getPercentScroll()+direction);
return false;
});
};
videojs.BackAnDisplayScroll.prototype.options_ = {
children: {
'BackAnDisplayScrollBar': {},
'BackAnDisplayScrollTime': {},
}
};
videojs.BackAnDisplayScroll.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scroll-anpanel-annotation',
innerHTML: '<div class="vjs-up-scroll-annotation"></div><div class="vjs-down-scroll-annotation"></div>',
});
};
videojs.BackAnDisplayScroll.prototype.onMouseDown = function(event){
var self = this;
if (event.target.className == 'vjs-scrollbar-anpanel-annotation'){
//change position with a click in the scrollbar
this.an.backDSBarSel.onMouseMove(event);
return false;
}else if (event.target.className == 'vjs-scrollbar-selector'){
//change position with scrollbar
//this event is controlled by this.an.backDSBarSel
return false;
}else{
//change position with arrows
var direction = event.target.className=='vjs-down-scroll-annotation'?this.UpValue:-this.UpValue;
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
if(this.mousedownID==-1) //Prevent multimple loops!
this.mousedownID = setInterval(function () {
var pos = Math.max(0,Math.min(1,self.getPercentScroll()+direction));
self.an.backDSBarSel.setPosition(pos);
},100);
}
};
videojs.BackAnDisplayScroll.prototype.onMouseUp = function(event){
videojs.off(document, "mouseup", this.onMouseUp, false);
var self = this;
if(this.mousedownID!=-1) { //Only stop if exists
clearInterval(this.mousedownID);
self.mousedownID=-1;
}
};
videojs.BackAnDisplayScroll.prototype.getPercentScroll = function(){
var scroll = this.an.AnDisplay.el_,
maxscroll = scroll.scrollHeight-scroll.offsetHeight,
currentValue = scroll.scrollTop;
return Math.max(0, Math.min(1, maxscroll != 0 ?(currentValue / maxscroll):0));
};
videojs.BackAnDisplayScroll.prototype.setPercentScroll = function(percent){
var scroll = this.an.AnDisplay.el_,
maxscroll = scroll.scrollHeight-scroll.offsetHeight;
percent = Math.max(0, Math.min(1, percent?percent:0));
scroll.scrollTop = Math.round(maxscroll*percent);
};
//-- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollBar
/**
* The Scroll bar for the display
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BackAnDisplayScrollBar = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.BackAnDisplayScrollBar.prototype.init_ = function(){};
videojs.BackAnDisplayScrollBar.prototype.options_ = {
children: {
'ScrollBarSelector': {},
}
};
videojs.BackAnDisplayScrollBar.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scrollbar-anpanel-annotation',
});
};
//-- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollBar--> ScrollBarSelector
/**
* The Scroll bar for the display
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.ScrollBarSelector = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
}
});
videojs.ScrollBarSelector.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
videojs.addClass(this.an.backDSBar.el_, 'disable');
};
videojs.ScrollBarSelector.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scrollbar-selector',
});
};
videojs.ScrollBarSelector.prototype.onMouseDown = function(event){
event.preventDefault();
//videojs.blockTextSelection();
videojs.on(document, "mousemove", videojs.bind(this,this.onMouseMove));
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
}
videojs.ScrollBarSelector.prototype.onMouseUp = function(event){
videojs.off(document, "mousemove", this.onMouseMove, false);
videojs.off(document, "mouseup", this.onMouseUp, false);
};
videojs.ScrollBarSelector.prototype.onMouseMove = function(event){
var top = this.calculateDistance(event);
top = this.parseMaxPercent(top); //set the max value fixing the height of the handle
this.setPosition(top);
}
videojs.ScrollBarSelector.prototype.calculateDistance = function(event){
var scrollY = this.getscrollY();
var scrollH = this.getscrollHeight();
var handleH = this.getHeight();
// Adjusted X and Width, so handle doesn't go outside the bar
scrollY = scrollY + (handleH);
scrollH = scrollH - (handleH);
// Adjusted X and Width, so handle doesn't go outside the bar
// Percent that the click is through the adjusted area
return Math.max(0, Math.min(1, (event.pageY - scrollY) / scrollH));
};
videojs.ScrollBarSelector.prototype.getscrollHeight = function() {
return this.el_.parentNode.offsetHeight;
};
videojs.ScrollBarSelector.prototype.getscrollY = function() {
return videojs.findPosition(this.el_.parentNode).top;
};
videojs.ScrollBarSelector.prototype.getHeight = function() {
return this.el_.offsetHeight;
};
videojs.ScrollBarSelector.prototype.parseMaxHeight = function(top){
var scrollH = this.getscrollHeight(),
handleH = this.getHeight(),
percent = handleH / scrollH;
return Math.max(0,Math.min(1-percent, top));
};
videojs.ScrollBarSelector.prototype.parseMaxPercent = function(top){
var scrollH = this.getscrollHeight(),
handleH = this.getHeight(),
percent = handleH / scrollH,
newTop = top;
if(top >= (1-percent))
newTop = 1;
return newTop;
};
videojs.ScrollBarSelector.prototype.setPosition = function(top,showBar){
var showBar = typeof showBar != 'undefined'?showBar:true;
// Check for invalid position
if(isNaN(top))
return false;
//Check if there is enough annotations to scroll
if(!this.isScrollable())
return false;
// Show the Scrollbar
if(showBar){
videojs.removeClass(this.an.backDSBar.el_, 'disable')
}
// Alias
var Obj = this.el_,
scroll = this.an.BackAnDisplayScroll,
scrollTime = this.an.backDSTime;
Obj.style.top = (this.parseMaxHeight(top) * 100) + '%';
scroll.setPercentScroll(top);
//Set the times in the scroll time panel
scrollTime.setTimes();
//Hide the Scrollbar in 1 sec
if(showBar){
var _self = this;
if (typeof this.Timeout!='undefined')
clearTimeout(this.Timeout);
this.Timeout = window.setTimeout(function () {
videojs.addClass(_self.an.backDSBar.el_, 'disable');
}, 1000);
}
//set current position
this.an.BackAnDisplayScroll.currentValue = top;
return true;
}
videojs.ScrollBarSelector.prototype.isScrollable = function(){
var scroll = this.an.AnDisplay.el_,
emtoPx = parseFloat($(scroll).find('.annotation').css('height')),
minTop = parseInt(scroll.offsetHeight/emtoPx);
//Count visible annotations in Panel
var count = this.an.AnDisplay.countVisibles();
return (count>minTop);
}
//-- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollTime
videojs.BackAnDisplayScrollTime = videojs.Component.extend({
/** @constructor */
init: function(player, options){
videojs.Component.call(this, player, options);
}
});
videojs.BackAnDisplayScrollTime.prototype.init_ = function(){
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
};
videojs.BackAnDisplayScrollTime.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scrolltime-anpanel-annotation',
innerHTML: '<div class="vjs-up-scrolltime-annotation"><span class="vjs-time-text"></span></div><div class="vjs-down-scrolltime-annotation"><span class="vjs-time-text"></span></div>',
});
};
videojs.BackAnDisplayScrollTime.prototype.setTimes = function(){
var AnPos = this.getAnnotationPosition(),
AnEl = this.getElements(AnPos),
AnTimes = this.getTimes(AnEl);
if(AnTimes.top!='Invalid Date'){
$(this.el_).find('.vjs-up-scrolltime-annotation')[0].style.visibility='';
$(this.el_).find('.vjs-up-scrolltime-annotation span')[0].innerHTML = AnTimes.top;
}else{
$(this.el_).find('.vjs-up-scrolltime-annotation')[0].style.visibility='hidden';
}
if(AnTimes.bottom!='Invalid Date'){
$(this.el_).find('.vjs-down-scrolltime-annotation')[0].style.visibility='';
$(this.el_).find('.vjs-down-scrolltime-annotation span')[0].innerHTML = AnTimes.bottom;
}else{
$(this.el_).find('.vjs-down-scrolltime-annotation')[0].style.visibility='hidden';
}
};
videojs.BackAnDisplayScrollTime.prototype.getAnnotationPosition = function(){
var backDSBarSel = this.an.backDSBarSel,
percent = backDSBarSel.parseMaxPercent(parseFloat(backDSBarSel.el_.style.top)/100),
scroll = this.an.AnDisplay.el_,
maxTop = scroll.scrollHeight,
minTop = scroll.offsetHeight,
maxBottom = maxTop-minTop,
minBottom = 0,
pos = {};
percent = percent || 0;
pos.top = Math.max(minTop, Math.min(maxTop,maxBottom*percent+scroll.offsetHeight));
pos.bottom = Math.max(minBottom, Math.min(maxBottom,maxBottom*percent));
return pos;
};
videojs.BackAnDisplayScrollTime.prototype.getElements = function(AnPos){
var AnPos = AnPos || {},
scroll = this.an.AnDisplay.el_,
emtoPx = parseFloat($(scroll).find('.annotation').css('height')),
maxTop = parseInt(scroll.scrollHeight/emtoPx),
minTop = parseInt(scroll.offsetHeight/emtoPx),
maxBottom = (maxTop-minTop),
minBottom = 0,
AnEl = {};
AnEl.top = Math.max(minTop, Math.min(maxTop,parseInt(AnPos.top/emtoPx)));
AnEl.bottom = Math.max(minBottom, Math.min(maxBottom,parseInt(AnPos.bottom/emtoPx)));
return AnEl;
};
videojs.BackAnDisplayScrollTime.prototype.getTimes = function(AnEl){
var AnEl = AnEl || {},
AnTimes = {},
TopEl, BottomEl, AnTop, AnBottom,
AnArray = $.makeArray(this.an.AnDisplay.el_.children);
AnEl.top = AnEl.top || 0;
AnEl.bottom = AnEl.bottom || 0;
//Get HTML Elements
var count = 0, lastEl;
for (var index in AnArray){
var an = AnArray[index];
if (an.style.display!='none'){
if(count == AnEl.bottom){
TopEl = an;
}else if(count == AnEl.top){
BottomEl = an;
}
lastEl = an;
count++;
}
}
if (typeof BottomEl=='undefined')
BottomEl = lastEl;
//Annotation Element
AnTop = typeof TopEl!='undefined'?$.data(TopEl, 'annotation'):undefined;
AnBottom = typeof BottomEl!='undefined'?$.data(BottomEl, 'annotation'):undefined;
//Update of the element
AnTimes.top = (typeof AnTop!='undefined' && typeof AnTop.updated!='undefined')?AnTop.updated:'';
AnTimes.bottom = (typeof AnBottom!='undefined' && typeof AnBottom.updated!='undefined')?AnBottom.updated:'';
//Format
AnTimes.top = new Date(AnTimes.top!=''?createDateFromISO8601(AnTimes.top):'');
AnTimes.bottom = new Date(AnTimes.bottom!=''?createDateFromISO8601(AnTimes.bottom):'');
return AnTimes;
};
})();
//----------------Plugin for Annotator to setup videojs----------------//
};
videojs.BigNewAnnotation.prototype.onClick = function() {
this.an.newan();
};
// -- Player--> ControlBar--> AnContainerButtons
/**
* Container for the button CSS
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.AnContainerButtons = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.AnContainerButtons.prototype.init_ = function() {};
videojs.AnContainerButtons.prototype.options_ = {
children: {
'ShowStatistics': {},
'ShowAnnotations': {},
'NewAnnotation': {},
}
};
videojs.AnContainerButtons.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-container-button-annotation vjs-menu-button vjs-control',
});
};
// -- Player--> ControlBar--> AnContainerButtons--> ShowStatistics
/**
* Button for show/hide the chart with statistics of the annotation's number
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.ShowStatistics = videojs.Button.extend({
/** @constructor */
init: function(player, options) {
videojs.Button.call(this, player, options);
}
});
videojs.ShowStatistics.prototype.init_ = function() {
this.an = this.player_.annotations;
};
videojs.ShowStatistics.prototype.createEl = function() {
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-statistics-annotation vjs-menu-button vjs-control',
title: 'Show the Statistics',
});
};
videojs.ShowStatistics.prototype.onClick = function() {
if (!this.an.options.showStatistics) this.an.showStatistics();
else this.an.hideStatistics();
};
// -- Player--> ControlBar--> AnContainerButtons--> ShowAnnotations
/**
* Button for show/hide the annotation panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.ShowAnnotations = videojs.Button.extend({
/** @constructor */
init: function(player, options) {
videojs.Button.call(this, player, options);
}
});
videojs.ShowAnnotations.prototype.init_ = function() {
this.an = this.player_.annotations;
};
videojs.ShowAnnotations.prototype.createEl = function() {
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-showannotations-annotation vjs-menu-button vjs-control',
title: 'Show Annotations',
});
};
videojs.ShowAnnotations.prototype.onClick = function() {
if (!this.an.options.showDisplay) this.an.showDisplay();
else this.an.hideDisplay();
};
// -- Player--> ControlBar--> AnContainerButtons--> NewAnnotation
/**
* Create a New Annotation
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.NewAnnotation = videojs.Button.extend({
/** @constructor */
init: function(player, options) {
videojs.Button.call(this, player, options);
}
});
videojs.NewAnnotation.prototype.init_ = function() {
this.an = this.player_.annotations;
// Hide Button if the user has selected readOnly in the Annotator options
var opts = this.an.options.optionsAnnotator;
if (typeof opts !== 'undefined' && typeof opts.readOnly !== 'undefined' && opts.readOnly)
this.hide();
};
videojs.NewAnnotation.prototype.createEl = function() {
return videojs.Button.prototype.createEl.call(this, 'div', {
className: 'vjs-new-annotation vjs-menu-button vjs-control',
title: 'New Annotation',
});
};
videojs.NewAnnotation.prototype.onClick = function() {
this.an.newan();
};
// -- Player--> ControlBar--> BackAnDisplay
/**
* The background annotations panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BackAnDisplay = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.BackAnDisplay.prototype.init_ = function() {
this.an = this.player_.annotations
self = this;
// Fix error resizing the display panel. The scroll always went up.
$(this.el_).watch('font-size', function() {
self.an.backDSBarSel.setPosition(self.an.BackAnDisplayScroll.currentValue, false);
});
};
videojs.BackAnDisplay.prototype.options_ = {
children: {
'RangeSelectorDisplay': {},
'AnDisplay': {},
'AnStat': {},
}
};
videojs.BackAnDisplay.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-back-anpanel-annotation',
});
};
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay
/**
* The selector to show the annotations in a time selection
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorDisplay = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
}
});
videojs.RangeSelectorDisplay.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
var duration = this.an.player.duration();
this.start = 0;
this.end = duration;
// set the selection area in the extreme position
this.setPosition(0, 0, false);
this.setPosition(1, this.rs._percent(duration), false);
};
videojs.RangeSelectorDisplay.prototype.options_ = {
children: {
'RangeSelectorLeft': {},
'RangeSelectorRight': {},
'RangeSelectorBar': {},
}
};
videojs.RangeSelectorDisplay.prototype.createEl = function(){
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-rangeselector-anpanel-annotation',
});
};
videojs.RangeSelectorDisplay.prototype.onMouseDown = function(event) {
event.preventDefault();
// videojs.blockTextSelection();
videojs.on(document, "mousemove", videojs.bind(this, this.onMouseMove));
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
videojs.removeClass(this.an.rsdb.el_, 'disable');
};
videojs.RangeSelectorDisplay.prototype.onMouseUp = function(event) {
videojs.off(document, "mousemove", this.onMouseMove, false);
videojs.off(document, "mouseup", this.onMouseUp, false);
videojs.addClass(this.an.rsdb.el_, 'disable');
};
videojs.RangeSelectorDisplay.prototype.onMouseMove = function(event) {
var left = this.calculateDistance(event);
if (this.an.rsdl.pressed)
this.setPosition(0, left);
else if (this.an.rsdr.pressed)
this.setPosition(1, left);
// move the frame to the position of the arrow
this.an.player.currentTime(this.rs._seconds(left));
};
videojs.RangeSelectorDisplay.prototype.calculateDistance = function(event) {
var rstbX = this.getRSTBX();
var rstbW = this.getRSTBWidth();
var handleW = this.getWidth();
// Adjusted X and Width, so handle doesn't go outside the bar
rstbX = rstbX + (handleW / 2);
rstbW = rstbW - handleW;
// Percent that the click is through the adjusted area
return Math.max(0, Math.min(1, (event.pageX - rstbX) / rstbW));
};
videojs.RangeSelectorDisplay.prototype.getRSTBWidth = function() {
return this.el_.offsetWidth;
};
videojs.RangeSelectorDisplay.prototype.getRSTBX = function() {
return videojs.findPosition(this.el_).left;
};
videojs.RangeSelectorDisplay.prototype.getWidth = function() {
var arrow = $(this.an.rsdl.el_).find('.vjs-selector-arrow')[0];
return arrow.offsetWidth; // does not matter left or right
};
videojs.RangeSelectorDisplay.prototype.setPosition = function(index, left, changeTime) {
// index = 0 for left side, index = 1 for right side
var index = index || 0;
var changeTime = typeof changeTime !== 'undefined' ? changeTime : true;
// Check for invalid position
if(isNaN(left))
return false;
// Check index between 0 and 1
if (!(index === 0 || index === 1))
return false;
// Alias
var ObjLeft = this.an.rsdl.el_;
var ObjRight = this.an.rsdr.el_;
var Obj = this.an[index === 0 ? 'rsdl' : 'rsdr'].el_;
// Check if left arrow is over the right arrow
if ((index === 0 ? this.updateLeft(left) : this.updateRight(left))) {
if (index === 1) { // right
Obj.style.left = (left * 100) + '%';
Obj.style.width = ((1 - left) * 100) + '%';
} else { // left
Obj.style.left = (left * 100) + '%';
Obj.style.width = ((left) * 100) + '%';
}
this[index === 0 ? 'start' : 'end'] = this.rs._seconds(left);
// Fix the problem when you press the button and the two arrow are underhand
// left.zIndex = 10 and right.zIndex=20. This is always less in this case:
if (index === 0 && (left * 100) >= 90)
$(ObjLeft).find('.vjs-selector-arrow')[0].style.zIndex = 25;
else
$(ObjLeft).find('.vjs-selector-arrow')[0].style.zIndex = 10;
// -- Panel
var rsdbl = this.an.rsdbl.el_,
rsdbr = this.an.rsdbr.el_,
distance = parseFloat(ObjRight.style.left) - parseFloat(ObjLeft.style.left);
if (index === 0)
rsdbl.children[0].innerHTML = videojs.formatTime(this.rs._seconds(left));
else
rsdbr.children[0].innerHTML = videojs.formatTime(this.rs._seconds(left));
if (typeof distance !== 'undefined' && distance <= 12.5) {
if (parseFloat(ObjLeft.style.left) < 7) {
rsdbl.style.top = (-1.5) + 'em';
rsdbl.style.left = 1 + 'em';
} else {
rsdbl.style.left = (-2.5) + 'em';
rsdbl.style.top = '';
}
if (parseFloat(ObjRight.style.left) > 93) {
rsdbr.style.top = (-1.5) + 'em';
rsdbr.style.right = 1 + 'em';
} else {
rsdbr.style.right = (-2.5) + 'em';
rsdbr.style.top = '';
}
} else {
rsdbl.style.left = 1 + 'em';
rsdbr.style.right = 1 + 'em';
rsdbl.style.top = '';
rsdbr.style.top = '';
}
var start = this.rs._seconds(parseFloat(ObjLeft.style.left) / 100);
var end = this.rs._seconds(parseFloat(ObjRight.style.left) / 100);
if (changeTime)
this.an.showBetween(start, end, this.an.rsdl.include, this.an.rsdr.include);
}
return true;
};
videojs.RangeSelectorDisplay.prototype.updateLeft = function(left) {
var rightVal = this.an.rsdr.el_.style.left !== '' ? this.an.rsdr.el_.style.left : 100;
var right = parseFloat(rightVal) / 100;
var bar = this.an.rsdb.el_;
var width = videojs.round((right - left), this.an.updatePrecision); // round necessary for not get 0.6e-7 for example that it's not able for the html css width
if(left <= (right+0.00001)) {
bar.style.left = (left * 100) + '%';
bar.style.width = (width * 100) + '%';
return true;
}
return false;
};
videojs.RangeSelectorDisplay.prototype.updateRight = function(right) {
var leftVal = this.an.rsdl.el_.style.left !== '' ? this.an.rsdl.el_.style.left : 0;
var left = parseFloat(leftVal) / 100;
var bar = this.an.rsdb.el_;
var width = videojs.round((right - left), this.an.updatePrecision); // round necessary for not get 0.6e-7 for example that it's not able for the html css width
if((right+0.00001) >= left) {
bar.style.width = (width * 100) + '%';
bar.style.left = ((right - width) * 100) + '%';
return true;
}
return false;
};
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorLeft
/**
* Left Time selector
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorLeft = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.on('dblclick', this.ondblclick);
this.pressed = false; // to know when is mousedown
this.include = true; // to know when we want to include the boundary time in the selection or not
}
});
videojs.RangeSelectorLeft.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
videojs.addClass(this.el_, 'include');
};
videojs.RangeSelectorLeft.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-leftselector-anpanel-annotation',
innerHTML: '<div class="vjs-selector-arrow" title="Left Annotation Selector"></div><div class="vjs-leftselector-back"></div>'
});
};
videojs.RangeSelectorLeft.prototype.onMouseDown = function(event) {
event.preventDefault();
this.pressed = true;
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
videojs.addClass(this.el_, 'active');
videojs.addClass(this.el_.parentNode, 'active');
};
videojs.RangeSelectorLeft.prototype.onMouseUp = function(event) {
videojs.off(document, "mouseup", this.onMouseUp, false);
videojs.removeClass(this.el_, 'active');
videojs.removeClass(this.el_.parentNode, 'active');
this.pressed = false;
};
videojs.RangeSelectorLeft.prototype.ondblclick = function(event) {
if (this.include) {
this.include = false;
videojs.removeClass(this.el_, 'include');
} else {
this.include = true;
videojs.addClass(this.el_, 'include');
}
var left = this.an.rsd.calculateDistance(event);
this.an.rsd.setPosition(0, left);
};
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorRight
/**
* Right Time selector
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorRight = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.on('dblclick', this.ondblclick);
this.pressed = false; // to know when is mousedown
this.include = true; // to know when we want to include the boundary time in the selection or not
}
});
videojs.RangeSelectorRight.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
videojs.addClass(this.el_, 'include');
};
videojs.RangeSelectorRight.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-rightselector-anpanel-annotation',
innerHTML: '<div class="vjs-selector-arrow" title="Right Annotation Selector"></div><div class="vjs-rightselector-back"></div>'
});
};
videojs.RangeSelectorRight.prototype.onMouseDown = function(event) {
event.preventDefault();
this.pressed = true;
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
videojs.addClass(this.el_, 'active');
videojs.addClass(this.el_.parentNode, 'active');
};
videojs.RangeSelectorRight.prototype.onMouseUp = function(event) {
videojs.off(document, "mouseup", this.onMouseUp, false);
videojs.removeClass(this.el_, 'active');
videojs.removeClass(this.el_.parentNode, 'active');
this.pressed = false;
};
videojs.RangeSelectorRight.prototype.ondblclick = function(event) {
if (this.include){
this.include = false;
videojs.removeClass(this.el_, 'include');
}else{
this.include = true;
videojs.addClass(this.el_, 'include');
}
var left = this.an.rsd.calculateDistance(event);
this.an.rsd.setPosition(1, left);
};
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar
/**
* Bar to display the selected Time
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorBar = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.RangeSelectorBar.prototype.init_ = function() {
videojs.addClass(this.el_, 'disable');
};
videojs.RangeSelectorBar.prototype.options_ = {
children: {
'RangeSelectorBarL': {},
'RangeSelectorBarR': {},
}
};
videojs.RangeSelectorBar.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-barselector-anpanel-annotation',
});
};
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar--> RangeSelectorBarL
/**
* This is the left time panel for RangeSelectorBar
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorBarL = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.RangeSelectorBarL.prototype.init_ = function() {};
videojs.RangeSelectorBarL.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-barselector-left',
innerHTML: '<span class="vjs-time-text">00:00</span>',
});
};
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar--> RangeSelectorBarR
/**
* This is the right time panel for RangeSelectorBar
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.RangeSelectorBarR = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.RangeSelectorBarR.prototype.init_ = function() {};
videojs.RangeSelectorBarR.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-barselector-right',
innerHTML: '<span class="vjs-time-text">00:00</span>'
});
};
// -- Player--> ControlBar--> BackAnDisplay--> AnDisplay
/**
* Show the annotations in a panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.AnDisplay = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.on('mouseover', this.onMouseOver);
}
});
videojs.AnDisplay.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
this.transition = false;
};
videojs.AnDisplay.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-anpanel-annotation',
});
};
videojs.AnDisplay.prototype.onMouseDown = function(event) {
var elem = $(event.target).parents('.annotator-hl').andSelf();
var _self = this;
if (elem.hasClass("annotator-hl")) {
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
// Clone the bar box to make the animation
var boxup = document.createElement('div');
var ElemTop = parseFloat(elem[1].style.top);
var ElemMargin = parseFloat(elem[1].style.marginTop);
var emtoPx = parseFloat($(elem[1]).css('height'));
var isPoint = $(elem[1]).hasClass("point");
boxup.className = isPoint ? "boxup-dashed-line point" : "boxup-dashed-line";
boxup.style.left = elem[1].style.left;
boxup.style.width = elem[1].style.width;
boxup.style.top = (ElemTop + ElemMargin - this.el_.scrollTop / emtoPx) + 'em';
elem[0].parentNode.parentNode.appendChild(boxup);
}
}
videojs.AnDisplay.prototype.onMouseUp = function(event) {
if (typeof this.lastelem === 'undefined')
return false;
var elem = this.lastelem;
var _self = this;
if (elem.hasClass("annotator-hl")) {
var annotation = elem.map(function() {
return $(this).data("annotation");
})[0];
var displayHeight = (-1) * parseFloat($(this.el_).parent()[0].style.top);
var emtoPx = parseFloat($(elem[1]).css('height'));
if (typeof $(elem).parent().parent().find('.boxup-dashed-line')[0] !== 'undefined') {
$(elem).parent().parent().find('.boxup-dashed-line')[0].style.top = (displayHeight - 2) + 'em';
}
this.an.player.pause();
this.transition = true;
window.setTimeout(function () {
_self.an.showAnnotation(annotation);
_self.transition = false;
_self.onCloseViewer();
}, 900);
}
videojs.off(document, "mouseup", this.onMouseUp, false);
};
videojs.AnDisplay.prototype.onMouseOver = function(event) {
if (!this.transition && !this.an.rsdl.pressed && !this.an.rsdr.pressed) {
var annotator = this.an.annotator;
var elem = $(event.target).parents('.annotator-hl').andSelf();
// if there is a opened annotation then show the new annotation mouse over
if (typeof annotator !== 'undefined' && annotator.viewer.isShown() && elem.hasClass("annotator-hl")) {
// hide the last open viewer
annotator.viewer.hide();
// get the annotation over the mouse
var annotations = elem.map(function() {
return $(this).data("annotation");
});
// show the annotation in the viewer
annotator.showViewer($.makeArray(annotations), Util.mousePosition(event, annotator.wrapper[0]));
}
// create dashed line
elem.addClass('active');
if (typeof elem !== 'undefined' && $(elem[1]).hasClass('annotation')) {
// create dashed line under the bar
var dashed = document.createElement('div');
var boxdown = document.createElement('div');
var DisplayHeight = parseFloat(this.an.BackAnDisplay.el_.style.height);
var ElemMarginTop = elem[1].style.marginTop !== '' ? parseFloat(elem[1].style.marginTop) : 0;
var ElemTop = parseFloat(elem[1].style.top) + ElemMarginTop;
var emtoPx = parseFloat($(elem[1]).css('height'));
var isPoint = $(elem[1]).hasClass("point");
dashed.className = isPoint ? 'dashed-line point' : 'dashed-line';
boxdown.className = "box-dashed-line";
dashed.style.left = boxdown.style.left = elem[1].style.left;
dashed.style.width = boxdown.style.width = isPoint ? '0' : elem[1].style.width;
dashed.style.top = ((ElemTop + 1) - this.el_.scrollTop / emtoPx) + 'em';
dashed.style.height = ((DisplayHeight - ElemTop + 2) + this.el_.scrollTop / emtoPx) + 'em'; // get the absolute value of the top to put in the height
boxdown.style.top = (DisplayHeight + 2) + 'em';
elem[0].parentNode.parentNode.appendChild(dashed);
elem[0].parentNode.parentNode.appendChild(boxdown);
$(this.player).find('.vjs-play-progress').css('z-index', 2);
$(this.player).find('.vjs-seek-handle').css('z-index', 2);
}
// store the last selected item
if (elem.hasClass("annotator-hl"))
this.lastelem = elem;
}
};
videojs.AnDisplay.prototype.onCloseViewer = function() {
if (!this.transition) {
if (typeof this.lastelem !== 'undefined')
this.lastelem.removeClass('active');
// remove dashed line
if (typeof this.lastelem !== 'undefined' && this.lastelem.hasClass("annotator-hl")) {
$(this.lastelem).parent().parent().find('.dashed-line').remove();
$(this.lastelem).parent().parent().find('.box-dashed-line').remove();
$(this.lastelem).parent().parent().find('.boxup-dashed-line').remove();
$(this.player).find('.vjs-play-progress').css('z-index', "");
$(this.player).find('.vjs-seek-handle').css('z-index', "");
}
}
};
videojs.AnDisplay.prototype.countVisibles = function() {
var AnArray = $.makeArray(this.el_.children);
// Count visible annotations in Panel
var count = 0;
for (var index in AnArray) {
var an = AnArray[index];
if (an.style.display !== 'none') {
count++;
}
}
return count;
};
// -- Player--> ControlBar--> BackAnDisplay--> AnStat
/**
* Display with a chart with the statistics of the number of Annotations
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.AnStat = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.marginTop = 20;
this.marginBottom = 0;
}
});
videojs.AnStat.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
this.canvas = this.el_.children[0];
};
videojs.AnStat.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-anstat-annotation',
innerHTML: '<canvas class="vjs-char-anstat-annotation">Your browser does not support the HTML5 canvas tag.</canvas>',
});
};
videojs.AnStat.prototype.paintCanvas = function() {
var ctx = this.canvas.getContext("2d");
var points = this._getPoints();
var w = this._getWeights(points);
var maxEn = this._getMaxArray(points, 'entries');
var TotAn = this.an.AnDisplay.el_.children.length;
var duration = this.an.player.duration();
// set the position of the canvas
this.canvas.style.marginTop = Math.round(this.marginTop) + 'px';
// Add the Max Concentration and Number of annotations
if($(this.canvas).parent().find('.vjs-totan-anstat-annotation').length === 0) {
$(this.canvas).parent().append('<div class="vjs-totan-anstat-annotation">');
$(this.canvas).parent().append('<div class="vjs-maxcon-anstat-annotation">');
}
var textCanvas = $(this.canvas).parent().find('.vjs-totan-anstat-annotation')[0];
textCanvas.innerHTML = TotAn + ' total annotations';
var textCanvas = $(this.canvas).parent().find('.vjs-maxcon-anstat-annotation')[0];
textCanvas.innerHTML = 'Max Annotations = ' + maxEn;
// Added dashed line function to paint
if (window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype.lineTo) {
CanvasRenderingContext2D.prototype.dashedLine = function(x1, y1, x2, y2, dashLen) {
if (dashLen === undefined) dashLen = 2;
this.beginPath();
this.moveTo(x1, y1);
var dX = x2 - x1;
var dY = y2 - y1;
var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
var dashX = dX / dashes;
var dashY = dY / dashes;
var q = 0;
while (q++ < dashes) {
x1 += dashX;
y1 += dashY;
this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x1, y1);
}
this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x2, y2);
this.stroke();
this.closePath();
};
};
// set the canvas size
this.canvas.height = this.an.AnDisplay.el_.offsetHeight - (this.marginTop + this.marginBottom);
this.canvas.width = this.an.AnDisplay.el_.offsetWidth;
ctx.beginPath();
ctx.strokeStyle = "rgb(255, 163, 0)";
var lastSe = 0;
var lastEn = 0;
ctx.moveTo(0, maxEn * w.Y); // Move pointer to 0, 0
for (var index in points) {
var p = points[index];
var x1 = lastSe * w.X, y1 = (maxEn - lastEn) * w.Y; // Old Point
var x2 = p.second * w.X, y2 = (maxEn - p.entries) * w.Y; // New Point
// new line
ctx.lineTo(x2, y1); // move horizontally to the new point
ctx.moveTo(x2, y1); // Move pointer
ctx.lineTo(x2, y2); // move vertically to the new point height
ctx.moveTo(x2, y2); // Prepare pointer for a new instance
// new rectangle under the curve
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
ctx.fillRect(x1, y1, (x2 - x1), (maxEn * w.Y - y1));
// store the last point
lastSe = p.second;
lastEn = p.entries;
}
// set the graphic to the end of the video
ctx.lineTo(lastSe * w.X, maxEn * w.Y);
ctx.moveTo(lastSe * w.X, maxEn * w.Y);
ctx.lineTo(duration * w.X, maxEn * w.Y);
ctx.stroke();
// dashed line down
ctx.beginPath();
ctx.dashedLine(0, maxEn * w.Y, duration * w.X, maxEn * w.Y, 8);
ctx.stroke();
// dashed line top
ctx.beginPath();
ctx.dashedLine(0, 0, duration * w.X, 0, 8);
ctx.stroke();
};
videojs.AnStat.prototype._getWeights = function(points){
var weight = {};
var panel = $(this.an.AnDisplay.el_);
var maxSe = this.an.player.duration();
var maxEn = this._getMaxArray(points, 'entries');
var panelW = parseFloat(panel.css('width'));
var panelH = parseFloat(panel.css('height')) - (this.marginTop + this.marginBottom);
weight.X = maxSe != 0 ? (panelW / maxSe) : 0;
weight.Y = maxEn != 0 ? (panelH / maxEn) : 0;
return weight;
};
videojs.AnStat.prototype._getMaxArray = function(points, variable) {
var highest = 0;
var tmp;
for (var index in points) {
tmp = points[index][variable];
if (tmp > highest) highest = tmp;
}
return highest;
};
videojs.AnStat.prototype._getPoints = function() {
var points = [];
var allannotations = this.an.annotator.plugins.Store.annotations;
for (var index in allannotations) {
var an = allannotations[index];
var start, end;
if (this.an._isVideoJS(an)) {
start = an.rangeTime.start;
end = an.rangeTime.end;
// start
if (!this._isFound(points, start)) {
points.push({
second:an.rangeTime.start,
entries:this._getNumberAnnotations(start)
});
if (an.rangeTime.start == an.rangeTime.end){ // is a point
points.push({
second:an.rangeTime.end,
entries:this._getNumberAnnotations(end, true)
});
}
}
// end
if (!this._isFound(points, end)) {
points.push({
second:an.rangeTime.end,
entries:this._getNumberAnnotations(end, true)
});
}
found = false;
}
}
points.sort(function(a, b) {
return parseFloat(a.second) - parseFloat(b.second)
});
return points;
};
videojs.AnStat.prototype._isFound = function(array, elem) {
var found = false;
for (var indexA in array) {
if(typeof array[indexA].second !== 'undefined' && array[indexA].second == elem)
found = true;
}
return found;
};
videojs.AnStat.prototype._getNumberAnnotations = function(time, end) {
var num = (typeof end !== 'undefined' && end) ? -1 : 0;
var allannotations = this.an.annotator.plugins['Store'].annotations;
for (var index in allannotations) {
var an = allannotations[index];
if (this.an._isVideoJS(an)) {
if(an.rangeTime.start <= time && an.rangeTime.end >= time)
num++;
}
}
return num;
};
// -- Player--> ControlBar--> BackAnDisplayScroll
/**
* The background annotations panel
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BackAnDisplayScroll = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
this.UpValue = 0.1;
this.currentValue = 0;
}
});
videojs.BackAnDisplayScroll.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
this.mousedownID = -1;
var self = this;
var direction;
// Firefox
$(this.an.AnDisplay.el_).bind('DOMMouseScroll', function(e) {
if (e.originalEvent.detail > 0)
direction = self.UpValue;
else
direction = -self.UpValue;
self.an.backDSBarSel.setPosition(self.getPercentScroll() + direction);
return false;
});
// IE, Opera, Safari
$(this.an.AnDisplay.el_).bind('mousewheel', function(e) {
if (e.originalEvent.wheelDelta < 0)
direction = self.UpValue;
else
direction = -self.UpValue;
self.an.backDSBarSel.setPosition(self.getPercentScroll() + direction);
return false;
});
};
videojs.BackAnDisplayScroll.prototype.options_ = {
children: {
'BackAnDisplayScrollBar': {},
'BackAnDisplayScrollTime': {},
}
};
videojs.BackAnDisplayScroll.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scroll-anpanel-annotation',
innerHTML: '<div class="vjs-up-scroll-annotation"></div><div class="vjs-down-scroll-annotation"></div>',
});
};
videojs.BackAnDisplayScroll.prototype.onMouseDown = function(event) {
var self = this;
if (event.target.className === 'vjs-scrollbar-anpanel-annotation') {
// change position with a click in the scrollbar
this.an.backDSBarSel.onMouseMove(event);
return false;
} else if (event.target.className === 'vjs-scrollbar-selector') {
// change position with scrollbar
// this event is controlled by this.an.backDSBarSel
return false;
} else {
// change position with arrows
var direction = event.target.className=='vjs-down-scroll-annotation' ? this.UpValue : -this.UpValue;
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
if(parseInt(this.mousedownID, 10) === -1) { // Prevent multimple loops!
this.mousedownID = setInterval(function () {
var pos = Math.max(0, Math.min(1, self.getPercentScroll() + direction));
self.an.backDSBarSel.setPosition(pos);
}, 100);
}
}
};
videojs.BackAnDisplayScroll.prototype.onMouseUp = function(event) {
videojs.off(document, "mouseup", this.onMouseUp, false);
var self = this;
if(parseInt(this.mousedownID, 10) != -1) { // Only stop if exists
clearInterval(this.mousedownID);
self.mousedownID = -1;
}
};
videojs.BackAnDisplayScroll.prototype.getPercentScroll = function() {
var scroll = this.an.AnDisplay.el_;
var maxscroll = scroll.scrollHeight - scroll.offsetHeight;
var currentValue = scroll.scrollTop;
return Math.max(0, Math.min(1, maxscroll !== 0 ? (currentValue / maxscroll) : 0));
};
videojs.BackAnDisplayScroll.prototype.setPercentScroll = function(percent) {
var scroll = this.an.AnDisplay.el_;
var maxscroll = scroll.scrollHeight-scroll.offsetHeight;
percent = Math.max(0, Math.min(1, percent ? percent : 0));
scroll.scrollTop = Math.round(maxscroll * percent);
};
// -- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollBar
/**
* The Scroll bar for the display
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.BackAnDisplayScrollBar = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.BackAnDisplayScrollBar.prototype.init_ = function() {};
videojs.BackAnDisplayScrollBar.prototype.options_ = {
children: {
'ScrollBarSelector': {},
}
};
videojs.BackAnDisplayScrollBar.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scrollbar-anpanel-annotation',
});
};
// -- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollBar--> ScrollBarSelector
/**
* The Scroll bar for the display
* @param {videojs.Player|Object} player
* @param {Object=} options
* @constructor
*/
videojs.ScrollBarSelector = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
this.on('mousedown', this.onMouseDown);
}
});
videojs.ScrollBarSelector.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
videojs.addClass(this.an.backDSBar.el_, 'disable');
};
videojs.ScrollBarSelector.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scrollbar-selector',
});
};
videojs.ScrollBarSelector.prototype.onMouseDown = function(event) {
event.preventDefault();
videojs.on(document, "mousemove", videojs.bind(this, this.onMouseMove));
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
}
videojs.ScrollBarSelector.prototype.onMouseUp = function(event) {
videojs.off(document, "mousemove", this.onMouseMove, false);
videojs.off(document, "mouseup", this.onMouseUp, false);
};
videojs.ScrollBarSelector.prototype.onMouseMove = function(event) {
var top = this.calculateDistance(event);
top = this.parseMaxPercent(top); // set the max value fixing the height of the handle
this.setPosition(top);
}
videojs.ScrollBarSelector.prototype.calculateDistance = function(event) {
var scrollY = this.getscrollY();
var scrollH = this.getscrollHeight();
var handleH = this.getHeight();
// Adjusted X and Width, so handle doesn't go outside the bar
scrollY = scrollY + (handleH);
scrollH = scrollH - (handleH);
// Adjusted X and Width, so handle doesn't go outside the bar
// Percent that the click is through the adjusted area
return Math.max(0, Math.min(1, (event.pageY - scrollY) / scrollH));
};
videojs.ScrollBarSelector.prototype.getscrollHeight = function() {
return this.el_.parentNode.offsetHeight;
};
videojs.ScrollBarSelector.prototype.getscrollY = function() {
return videojs.findPosition(this.el_.parentNode).top;
};
videojs.ScrollBarSelector.prototype.getHeight = function() {
return this.el_.offsetHeight;
};
videojs.ScrollBarSelector.prototype.parseMaxHeight = function(top) {
var scrollH = this.getscrollHeight();
var handleH = this.getHeight();
var percent = handleH / scrollH;
return Math.max(0, Math.min(1 - percent, top));
};
videojs.ScrollBarSelector.prototype.parseMaxPercent = function(top) {
var scrollH = this.getscrollHeight();
var handleH = this.getHeight();
var percent = handleH / scrollH;
var newTop = top;
if (top >= (1 - percent))
newTop = 1;
return newTop;
};
videojs.ScrollBarSelector.prototype.setPosition = function(top, showBar) {
var showBar = typeof showBar !== 'undefined' ? showBar : true;
// Check for invalid position
if (isNaN(top))
return false;
// Check if there is enough annotations to scroll
if (!this.isScrollable())
return false;
// Show the Scrollbar
if (showBar) {
videojs.removeClass(this.an.backDSBar.el_, 'disable')
}
// Alias
var Obj = this.el_;
var scroll = this.an.BackAnDisplayScroll;
var scrollTime = this.an.backDSTime;
Obj.style.top = (this.parseMaxHeight(top) * 100) + '%';
scroll.setPercentScroll(top);
// Set the times in the scroll time panel
scrollTime.setTimes();
// Hide the Scrollbar in 1 sec
if(showBar) {
var _self = this;
if (typeof this.Timeout !== 'undefined')
clearTimeout(this.Timeout);
this.Timeout = window.setTimeout(function () {
videojs.addClass(_self.an.backDSBar.el_, 'disable');
}, 1000);
}
// set current position
this.an.BackAnDisplayScroll.currentValue = top;
return true;
}
videojs.ScrollBarSelector.prototype.isScrollable = function() {
var scroll = this.an.AnDisplay.el_;
var emtoPx = parseFloat($(scroll).find('.annotation').css('height'));
var minTop = parseInt(scroll.offsetHeight/emtoPx);
// Count visible annotations in Panel
var count = this.an.AnDisplay.countVisibles();
return (count > minTop);
}
// -- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollTime
videojs.BackAnDisplayScrollTime = videojs.Component.extend({
/** @constructor */
init: function(player, options) {
videojs.Component.call(this, player, options);
}
});
videojs.BackAnDisplayScrollTime.prototype.init_ = function() {
this.rs = this.player_.rangeslider;
this.an = this.player_.annotations;
};
videojs.BackAnDisplayScrollTime.prototype.createEl = function() {
return videojs.Component.prototype.createEl.call(this, 'div', {
className: 'vjs-scrolltime-anpanel-annotation',
innerHTML: '<div class="vjs-up-scrolltime-annotation"><span class="vjs-time-text"></span></div><div class="vjs-down-scrolltime-annotation"><span class="vjs-time-text"></span></div>',
});
};
videojs.BackAnDisplayScrollTime.prototype.setTimes = function() {
var AnPos = this.getAnnotationPosition();
var AnEl = this.getElements(AnPos);
var AnTimes = this.getTimes(AnEl);
if (AnTimes.top != 'Invalid Date') {
$(this.el_).find('.vjs-up-scrolltime-annotation')[0].style.visibility = '';
$(this.el_).find('.vjs-up-scrolltime-annotation span')[0].innerHTML = AnTimes.top;
} else {
$(this.el_).find('.vjs-up-scrolltime-annotation')[0].style.visibility = 'hidden';
}
if (AnTimes.bottom != 'Invalid Date') {
$(this.el_).find('.vjs-down-scrolltime-annotation')[0].style.visibility = '';
$(this.el_).find('.vjs-down-scrolltime-annotation span')[0].innerHTML = AnTimes.bottom;
} else {
$(this.el_).find('.vjs-down-scrolltime-annotation')[0].style.visibility = 'hidden';
}
};
videojs.BackAnDisplayScrollTime.prototype.getAnnotationPosition = function() {
var backDSBarSel = this.an.backDSBarSel;
var percent = backDSBarSel.parseMaxPercent(parseFloat(backDSBarSel.el_.style.top) / 100);
var scroll = this.an.AnDisplay.el_;
var maxTop = scroll.scrollHeight;
var minTop = scroll.offsetHeight;
var maxBottom = maxTop - minTop;
var minBottom = 0;
var pos = {};
percent = percent || 0;
pos.top = Math.max(minTop, Math.min(maxTop, maxBottom * percent + scroll.offsetHeight));
pos.bottom = Math.max(minBottom, Math.min(maxBottom, maxBottom * percent));
return pos;
};
videojs.BackAnDisplayScrollTime.prototype.getElements = function(AnPos) {
var AnPos = AnPos || {};
var scroll = this.an.AnDisplay.el_;
var emtoPx = parseFloat($(scroll).find('.annotation').css('height'));
var maxTop = parseInt(scroll.scrollHeight / emtoPx);
var minTop = parseInt(scroll.offsetHeight / emtoPx);
var maxBottom = (maxTop - minTop);
var minBottom = 0;
var AnEl = {};
AnEl.top = Math.max(minTop, Math.min(maxTop, parseInt(AnPos.top / emtoPx)));
AnEl.bottom = Math.max(minBottom, Math.min(maxBottom, parseInt(AnPos.bottom / emtoPx)));
return AnEl;
};
videojs.BackAnDisplayScrollTime.prototype.getTimes = function(AnEl) {
var AnEl = AnEl || {};
var AnTimes = {};
var TopEl, BottomEl, AnTop, AnBottom;
var AnArray = $.makeArray(this.an.AnDisplay.el_.children);
AnEl.top = AnEl.top || 0;
AnEl.bottom = AnEl.bottom || 0;
// Get HTML Elements
var count = 0;
var lastEl;
for (var index in AnArray) {
var an = AnArray[index];
if (an.style.display !== 'none') {
if (count == AnEl.bottom) {
TopEl = an;
} else if (count == AnEl.top) {
BottomEl = an;
}
lastEl = an;
count++;
}
}
if (typeof BottomEl === 'undefined')
BottomEl = lastEl;
// Annotation Element
AnTop = typeof TopEl !== 'undefined' ? $.data(TopEl, 'annotation') : undefined;
AnBottom = typeof BottomEl !== 'undefined' ? $.data(BottomEl, 'annotation') : undefined;
// Update of the element
AnTimes.top = (typeof AnTop !== 'undefined' && typeof AnTop.updated !== 'undefined') ? AnTop.updated : '';
AnTimes.bottom = (typeof AnBottom !=='undefined' && typeof AnBottom.updated !== 'undefined') ? AnBottom.updated : '';
// Format
AnTimes.top = new Date(AnTimes.top !== '' ? createDateFromISO8601(AnTimes.top) : '');
AnTimes.bottom = new Date(AnTimes.bottom != '' ? createDateFromISO8601(AnTimes.bottom) : '');
return AnTimes;
};
}) ();
// ----------------Plugin for Annotator to setup videojs---------------- //
Annotator.Plugin.VideoJS = (function(_super) {
__extends(VideoJS, _super);
__extends(VideoJS, _super);
//constructor
function VideoJS() {
this.pluginSubmit = __bind(this.pluginSubmit, this);
_ref = VideoJS.__super__.constructor.apply(this, arguments);
this.__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }
return _ref;
}
// constructor
function VideoJS() {
this.pluginSubmit = __bind(this.pluginSubmit, this);
_ref = VideoJS.__super__.constructor.apply(this, arguments);
this.__indexOf = [].indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (i in this && this[i] === item)
return i;
}
return -1;
};
return _ref;
};
VideoJS.prototype.field = null;
VideoJS.prototype.input = null;
VideoJS.prototype.field = null;
VideoJS.prototype.input = null;
VideoJS.prototype.pluginInit = function() {
console.log("VideoJS-pluginInit");
//Check that annotator is working
if (!Annotator.supported()) {
return;
}
//-- Editor
this.field = this.annotator.editor.addField({
id: 'vjs-input-rangeTime-annotations',
type: 'input', //options (textarea,input,select,checkbox)
submit: this.pluginSubmit,
EditVideoAn: this.EditVideoAn
});
//Modify the element created with annotator to be an invisible span
var select = '<li><span id="vjs-input-rangeTime-annotations"></span></li>',
newfield = Annotator.$(select);
Annotator.$(this.field).replaceWith(newfield);
this.field=newfield[0];
//-- Listener for Open Video Annotator
this.initListeners();
return this.input = $(this.field).find(':input');
};
VideoJS.prototype.pluginInit = function() {
console.log("VideoJS-pluginInit");
// Check that annotator is working
if (!Annotator.supported()) {
return;
}
// -- Editor
this.field = this.annotator.editor.addField({
id: 'vjs-input-rangeTime-annotations',
type: 'input', // options (textarea, input, select, checkbox)
submit: this.pluginSubmit,
EditVideoAn: this.EditVideoAn
});
// Modify the element created with annotator to be an invisible span
var select = '<li><span id="vjs-input-rangeTime-annotations"></span></li>';
var newfield = Annotator.$(select);
Annotator.$(this.field).replaceWith(newfield);
this.field = newfield[0];
// -- Listener for Open Video Annotator
this.initListeners();
return this.input = $(this.field).find(':input');
};
// New JSON for the database
VideoJS.prototype.pluginSubmit = function(field, annotation) {
console.log("Plug-pluginSubmit");
//Select the new JSON for the Object to save
if (this.EditVideoAn()){
var annotator = this.annotator,
index = annotator.editor.VideoJS,
player = annotator.mplayer[index],
rs = player.rangeslider,
time = rs.getValues(),
isYoutube = (player && typeof player.techName!='undefined')?(player.techName == 'Youtube'):false,
isNew = typeof annotation.media=='undefined',
ext,
type = player.options_.sources[0].type.split("/") || "";
if (typeof annotation.media == 'undefined') annotation.media = typeof type[0]!='undefined'?type[0]:"video"; // - media (by default: video)
annotation.target = annotation.target || {}; // - target
annotation.target.container = player.id_ || ""; // - target.container
annotation.target.src = player.options_.sources[0].src || ""; // - target.src (media source)
ext = (player.options_.sources[0].src.substring(player.options_.sources[0].src.lastIndexOf("."))).toLowerCase();
ext = isYoutube?'Youtube':ext; //The extension for youtube
annotation.target.ext = ext || ""; // - target.ext (extension)
annotation.rangeTime = annotation.rangeTime || {}; // - rangeTime
annotation.rangeTime.start = time.start || 0; // - rangeTime.start
annotation.rangeTime.end = time.end || 0; // - rangeTime.end
annotation.updated = new Date().toISOString(); // - updated
if (typeof annotation.created == 'undefined')
annotation.created = annotation.updated; // - created
//show the new annotation
var eventAn = isNew?"annotationCreated":"annotationUpdated";
function afterFinish(){
player.annotations.showAnnotation(annotation);
annotator.unsubscribe(eventAn, afterFinish);
};
annotator.subscribe(eventAn, afterFinish);//show after the annotation is in the back-end
}else{
if (typeof annotation.media == 'undefined')
annotation.media = "text"; // - media
annotation.updated = new Date().toISOString(); // - updated
if (typeof annotation.created == 'undefined')
annotation.created = annotation.updated; // - created
}
return annotation.media;
};
//------ Methods ------//
//Detect if we are creating or editing a video-js annotation
VideoJS.prototype.EditVideoAn = function (){
var wrapper = $('.annotator-wrapper').parent()[0],
annotator = window.annotator = $.data(wrapper, 'annotator'),
isOpenVideojs = (typeof annotator.mplayer != 'undefined'),
VideoJS = annotator.editor.VideoJS;
return (isOpenVideojs && typeof VideoJS!='undefined' && VideoJS!==-1);
};
//Detect if the annotation is a video-js annotation
VideoJS.prototype.isVideoJS = function (an){
var wrapper = $('.annotator-wrapper').parent()[0],
annotator = window.annotator = $.data(wrapper, 'annotator'),
rt = an.rangeTime,
isOpenVideojs = (typeof annotator.mplayer != 'undefined'),
isVideo = (typeof an.media!='undefined' && (an.media=='video' || an.media=='audio')),
isNumber = (typeof rt!='undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
return (isOpenVideojs && isVideo && isNumber);
};
//Delete Video Annotation
VideoJS.prototype._deleteAnnotation = function(an){
var target = an.target || {},
container = target.container || {},
player = this.annotator.mplayer[container];
var annotator = this.annotator,
annotations = annotator.plugins['Store'].annotations,
tot = typeof annotations !='undefined'?annotations.length:0,
attempts = 0; // max 100
// New JSON for the database
VideoJS.prototype.pluginSubmit = function(field, annotation) {
console.log("Plug-pluginSubmit");
// Select the new JSON for the Object to save
if (this.EditVideoAn()) {
var annotator = this.annotator;
var index = annotator.editor.VideoJS;
var player = annotator.mplayer[index];
var rs = player.rangeslider;
var time = rs.getValues();
var isYoutube = (player && typeof player.techName !== 'undefined') ? (player.techName === 'Youtube') : false;
var isNew = typeof annotation.media === 'undefined';
var ext;
var type = player.options_.sources[0].type.split("/") || "";
//This is to watch the annotations object, to see when is deleted the annotation
var ischanged = function(){
var new_tot = annotator.plugins['Store'].annotations.length;
if (attempts<100)
setTimeout(function(){
if (new_tot != tot){
player.annotations.refreshDisplay(); //Reload the display of annotation
}else{
if (isNew)
annotation.media = typeof type[0] !== 'undefined' ? type[0] : "video"; // - media (by default: video)
annotation.target = annotation.target || {}; // - target
annotation.target.container = player.id_ || ""; // - target.container
annotation.target.src = player.options_.sources[0].src || ""; // - target.src (media source)
ext = (player.options_.sources[0].src.substring(player.options_.sources[0].src.lastIndexOf("."))).toLowerCase();
ext = isYoutube ? 'Youtube' : ext; // The extension for youtube
annotation.target.ext = ext || ""; // - target.ext (extension)
annotation.rangeTime = annotation.rangeTime || {}; // - rangeTime
annotation.rangeTime.start = time.start || 0; // - rangeTime.start
annotation.rangeTime.end = time.end || 0; // - rangeTime.end
annotation.updated = new Date().toISOString(); // - updated
if (typeof annotation.created === 'undefined')
annotation.created = annotation.updated; // - created
// show the new annotation
var eventAn = isNew ? "annotationCreated" : "annotationUpdated";
function afterFinish(){
player.annotations.showAnnotation(annotation);
annotator.unsubscribe(eventAn, afterFinish);
};
annotator.subscribe(eventAn, afterFinish); // show after the annotation is in the back-end
} else {
if (typeof annotation.media === 'undefined')
annotation.media = "text"; // - media
annotation.updated = new Date().toISOString(); // - updated
if (typeof annotation.created === 'undefined')
annotation.created = annotation.updated; // - created
}
return annotation.media;
};
// ------ Methods ------ //
// Detect if we are creating or editing a video-js annotation
VideoJS.prototype.EditVideoAn = function () {
var wrapper = $('.annotator-wrapper').parent()[0];
var annotator = window.annotator = $.data(wrapper, 'annotator');
var isOpenVideojs = (typeof annotator.mplayer !== 'undefined');
var VideoJS = annotator.editor.VideoJS;
return (isOpenVideojs && typeof VideoJS !== 'undefined' && VideoJS !== -1);
};
// Detect if the annotation is a video-js annotation
VideoJS.prototype.isVideoJS = function (an) {
var wrapper = $('.annotator-wrapper').parent()[0];
var annotator = window.annotator = $.data(wrapper, 'annotator');
var rt = an.rangeTime;
var isOpenVideojs = (typeof annotator.mplayer !== 'undefined');
var isVideo = (typeof an.media !== 'undefined' && (an.media === 'video' || an.media === 'audio'));
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
return (isOpenVideojs && isVideo && isNumber);
};
// Delete Video Annotation
VideoJS.prototype._deleteAnnotation = function(an) {
var target = an.target || {};
var container = target.container || {};
var player = this.annotator.mplayer[container];
var annotator = this.annotator;
var annotations = annotator.plugins.Store.annotations;
var tot = typeof annotations !== 'undefined' ? annotations.length : 0;
var attempts = 0; // max 100
// This is to watch the annotations object, to see when is deleted the annotation
var ischanged = function() {
var new_tot = annotator.plugins.Store.annotations.length;
if (attempts < 100)
setTimeout(function() {
if (new_tot !== tot) {
player.annotations.refreshDisplay(); // Reload the display of annotation
} else {
attempts++;
ischanged();
}
},100); //wait for the change in the annotations
}, 100); // wait for the change in the annotations
};
ischanged();
player.rangeslider.hide(); //Hide Range Slider
};
//--Listeners
VideoJS.prototype.initListeners = function (){
var wrapper = $('.annotator-wrapper').parent()[0],
annotator = $.data(wrapper, 'annotator');
var EditVideoAn = this.EditVideoAn,
isVideoJS = this.isVideoJS,
self = this;
//local functions
//-- Editor
function annotationEditorHidden(editor) {
console.log("annotationEditorHidden");
if (EditVideoAn()){
var index = annotator.editor.VideoJS;
annotator.mplayer[index].rangeslider.hide(); //Hide Range Slider
annotator.an[index].refreshDisplay(); //Reload the display of annotations
}
annotator.editor.VideoJS=-1;
annotator.unsubscribe("annotationEditorHidden", annotationEditorHidden);
};
function annotationEditorShown(editor,annotation) {
console.log("annotationEditorShown");
for (var index in annotator.an){
annotator.an[index].editAnnotation(annotation,editor);
}
annotator.subscribe("annotationEditorHidden", annotationEditorHidden);
};
//-- Annotations
function annotationDeleted(annotation) {
console.log("annotationDeleted");
if (isVideoJS(annotation))
self._deleteAnnotation(annotation);
};
//-- Viewer
function hideViewer(){
for (var index in annotator.an){
annotator.an[index].AnDisplay.onCloseViewer();
}
annotator.viewer.unsubscribe("hide", hideViewer);
};
function annotationViewerShown(viewer,annotations) {
console.log("annotationViewerShown");
var separation = viewer.element.hasClass(viewer.classes.invert.y)?5:-5,
newpos = {
top: parseFloat(viewer.element[0].style.top)+separation,
left: parseFloat(viewer.element[0].style.left)
};
viewer.element.css(newpos);
//Remove the time to wait until disapear, to be more faster that annotator by default
viewer.element.find('.annotator-controls').removeClass(viewer.classes.showControls);
annotator.viewer.subscribe("hide", hideViewer);
};
//subscribe to Annotator
annotator.subscribe("annotationEditorShown", annotationEditorShown)
.subscribe("annotationDeleted", annotationDeleted)
.subscribe("annotationViewerShown", annotationViewerShown);
};
return VideoJS;
player.rangeslider.hide(); // Hide Range Slider
};
// --Listeners
VideoJS.prototype.initListeners = function () {
var wrapper = $('.annotator-wrapper').parent()[0];
var annotator = $.data(wrapper, 'annotator');
var EditVideoAn = this.EditVideoAn;
var isVideoJS = this.isVideoJS;
var self = this;
// local functions
// -- Editor
function annotationEditorHidden(editor) {
if (EditVideoAn()){
var index = annotator.editor.VideoJS;
annotator.mplayer[index].rangeslider.hide(); // Hide Range Slider
annotator.an[index].refreshDisplay(); // Reload the display of annotations
}
annotator.editor.VideoJS=-1;
annotator.unsubscribe("annotationEditorHidden", annotationEditorHidden);
};
function annotationEditorShown(editor, annotation) {
for (var index in annotator.an){
annotator.an[index].editAnnotation(annotation, editor);
}
annotator.subscribe("annotationEditorHidden", annotationEditorHidden);
};
// -- Annotations
function annotationDeleted(annotation) {
if (isVideoJS(annotation))
self._deleteAnnotation(annotation);
};
// -- Viewer
function hideViewer(){
for (var index in annotator.an) {
annotator.an[index].AnDisplay.onCloseViewer();
}
annotator.viewer.unsubscribe("hide", hideViewer);
};
function annotationViewerShown(viewer, annotations) {
var separation = viewer.element.hasClass(viewer.classes.invert.y) ? 5 : -5;
var newpos = {
top: parseFloat(viewer.element[0].style.top)+separation,
left: parseFloat(viewer.element[0].style.left)
};
viewer.element.css(newpos);
// Remove the time to wait until disapear, to be more faster that annotator by default
viewer.element.find('.annotator-controls').removeClass(viewer.classes.showControls);
annotator.viewer.subscribe("hide", hideViewer);
};
// subscribe to Annotator
annotator.subscribe("annotationEditorShown", annotationEditorShown)
.subscribe("annotationDeleted", annotationDeleted)
.subscribe("annotationViewerShown", annotationViewerShown);
};
return VideoJS;
})(Annotator.Plugin);
//----------------PUBLIC OBJECT TO CONTROL THE ANNOTATIONS----------------//
// ----------------PUBLIC OBJECT TO CONTROL THE ANNOTATIONS---------------- //
//The name of the plugin that the user will write in the html
// The name of the plugin that the user will write in the html
OpenVideoAnnotation = ("OpenVideoAnnotation" in window) ? OpenVideoAnnotation : {};
OpenVideoAnnotation.Annotator = function (element, options) {
//local variables
var $ = jQuery,
options = options || {};
options.optionsAnnotator = options.optionsAnnotator || {};
options.optionsVideoJS = options.optionsVideoJS || {};
options.optionsRS = options.optionsRS || {};
options.optionsOVA = options.optionsOVA || {};
//if there isn't store optinos it will create a uri and limit variables for the Back-end of Annotations
if (typeof options.optionsAnnotator.store=='undefined')
options.optionsAnnotator.store = {};
var store = options.optionsAnnotator.store;
if (typeof store.annotationData=='undefined')
store.annotationData = {};
if (typeof store.annotationData.uri=='undefined'){
var uri = location.protocol + '//' + location.host + location.pathname;
store.annotationData.store = {uri:uri};
}
if (typeof store.loadFromSearch=='undefined')
store.loadFromSearch={};
if (typeof store.loadFromSearch.uri=='undefined')
store.loadFromSearch.uri = uri;
if (typeof store.loadFromSearch.limit=='undefined')
store.loadFromSearch.limit = 10000;
//global variables
this.currentUser = null;
// local variables
var $ = jQuery;
var options = options || {};
options.optionsAnnotator = options.optionsAnnotator || {};
options.optionsVideoJS = options.optionsVideoJS || {};
options.optionsRS = options.optionsRS || {};
options.optionsOVA = options.optionsOVA || {};
// if there isn't store optinos it will create a uri and limit variables for the Back-end of Annotations
if (typeof options.optionsAnnotator.store === 'undefined')
options.optionsAnnotator.store = {};
var store = options.optionsAnnotator.store;
if (typeof store.annotationData === 'undefined')
store.annotationData = {};
if (typeof store.annotationData.uri === 'undefined'){
var uri = location.protocol + '//' + location.host + location.pathname;
store.annotationData.store = {uri: uri};
}
if (typeof store.loadFromSearch === 'undefined')
store.loadFromSearch = {};
if (typeof store.loadFromSearch.uri === 'undefined')
store.loadFromSearch.uri = uri;
if (typeof store.loadFromSearch.limit === 'undefined')
store.loadFromSearch.limit = 10000;
// global variables
this.currentUser = null;
//-- Init all the classes --/
//Annotator
this.annotator = $(element).annotator(options.optionsAnnotator.annotator).data('annotator');
options.optionsOVA.optionsAnnotator = options.optionsAnnotator.annotator; //send the Annotator's options to OVA
//Video-JS
/*
mplayers -> Array with the html of all the video-js
mplayer -> Array with all the video-js that will be in the plugin
*/
// -- Init all the classes --/
// Annotator
this.annotator = $(element).annotator(options.optionsAnnotator.annotator).data('annotator');
options.optionsOVA.optionsAnnotator = options.optionsAnnotator.annotator; // send the Annotator's options to OVA
// Video-JS
/*
mplayers -> Array with the html of all the video-js
mplayer -> Array with all the video-js that will be in the plugin
*/
var mplayers = $(element).find('div .video-js').toArray();
var mplayer = this.mplayer = {};
for (var index in mplayers){
var id = mplayers[index].id;
var mplayer_ = videojs(mplayers[index],options.optionsVideoJS);
//solve a problem with firefox. In Firefox the src() function is loaded before charge the optionsVideoJS, and the techOrder are not loaded
if (vjs.IS_FIREFOX && typeof options.optionsVideoJS.techOrder !='undefined'){
mplayer_.options_.techOrder = options.optionsVideoJS.techOrder;
mplayer_.src(mplayer_.options_['sources']);
}
this.mplayer[id] = mplayer_;
for (var index in mplayers) {
var id = mplayers[index].id;
var mplayer_ = videojs(mplayers[index], options.optionsVideoJS);
// solve a problem with firefox. In Firefox the src() function is loaded before charge the optionsVideoJS, and the techOrder are not loaded
if (vjs.IS_FIREFOX && typeof options.optionsVideoJS.techOrder !== 'undefined'){
mplayer_.options_.techOrder = options.optionsVideoJS.techOrder;
mplayer_.src(mplayer_.options_['sources']);
}
this.mplayer[id] = mplayer_;
}
// Video-JS
this.annotator.an = {}; // annotations video-js plugin to annotator
for (var index in this.mplayer) {
// to be their own options is necessary to extend deeply the options with all the childrens
this.mplayer[index].rangeslider($.extend(true, {}, options.optionsRS));
this.mplayer[index].annotations($.extend(true, {}, options.optionsOVA));
this.annotator.an[index]=this.mplayer[index].annotations;
}
//Video-JS
this.annotator.an = {}; //annotations video-js plugin to annotator
for (var index in this.mplayer){
//to be their own options is necessary to extend deeply the options with all the childrens
this.mplayer[index].rangeslider($.extend(true, {}, options.optionsRS));
this.mplayer[index].annotations($.extend(true, {}, options.optionsOVA));
this.annotator.an[index]=this.mplayer[index].annotations;
}
//-- Experimental Global function for Open Video Annotator --//
this.setCurrentUser = function (user) {
this.currentUser = user;
this.annotator.plugins["Permissions"].setUser(user);
}
//Local function to setup the keyboard listener
var focusedPlayer = this.focusedPlayer = '',//variable to know the focused player
lastfocusPlayer = this.lastfocusPlayer = '';
function onKeyUp(e){
//skip the text areas
if (e.target.nodeName.toLowerCase()!='textarea')
mplayer[focusedPlayer].annotations.pressedKey(e.which);
};
;(this._setupKeyboard = function(){
$(document).mousedown(function(e) {
focusedPlayer = '';
//Detects if a player was click
for (var index in mplayer){
if($(mplayer[index].el_).find(e.target).length)
focusedPlayer = mplayer[index].id_;
/* Could Fix keyboard Problem in full-screen mode
if ($(e.target).hasClass('vjs-fullscreen-control'))
mplayer[index].el_.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
}*/
}
//Enter if we change the focus between player or go out of the player
if(lastfocusPlayer != focusedPlayer){
$(document).off("keyup", onKeyUp);//Remove the last listener
//set the key listener
if(focusedPlayer!='')
$(document).on("keyup", onKeyUp);
}
lastfocusPlayer = focusedPlayer;
});
})(this);
//-- Activate all the plugins --//
// Annotator
if (typeof options.optionsAnnotator.auth!='undefined')
this.annotator.addPlugin('Auth', options.optionsAnnotator.auth);
if (typeof options.optionsAnnotator.permissions!='undefined')
this.annotator.addPlugin("Permissions", options.optionsAnnotator.permissions);
if (typeof options.optionsAnnotator.store!='undefined')
this.annotator.addPlugin("Store", options.optionsAnnotator.store);
if (typeof options.optionsAnnotator.highlightTags!='undefined')
this.annotator.addPlugin("HighlightTags", options.optionsAnnotator.highlightTags);
// -- Experimental Global function for Open Video Annotator -- //
this.setCurrentUser = function (user) {
this.currentUser = user;
this.annotator.plugins["Permissions"].setUser(user);
}
// Local function to setup the keyboard listener
var focusedPlayer = this.focusedPlayer = ''; // variable to know the focused player
var lastfocusPlayer = this.lastfocusPlayer = '';
function onKeyUp(e) {
// skip the text areas
if (e.target.nodeName.toLowerCase() !== 'textarea')
mplayer[focusedPlayer].annotations.pressedKey(e.which);
};
(this._setupKeyboard = function() {
$(document).mousedown(function(e) {
focusedPlayer = '';
// Detects if a player was click
for (var index in mplayer) {
if ($(mplayer[index].el_).find(e.target).length)
focusedPlayer = mplayer[index].id_;
}
// Enter if we change the focus between player or go out of the player
if (lastfocusPlayer !== focusedPlayer) {
$(document).off("keyup", onKeyUp); // Remove the last listener
// set the key listener
if (focusedPlayer !== '')
$(document).on("keyup", onKeyUp);
}
lastfocusPlayer = focusedPlayer;
});
}) (this);
// -- Activate all the plugins -- //
// Annotator
if (typeof options.optionsAnnotator.auth !== 'undefined')
this.annotator.addPlugin('Auth', options.optionsAnnotator.auth);
if (typeof options.optionsAnnotator.permissions !== 'undefined')
this.annotator.addPlugin("Permissions", options.optionsAnnotator.permissions);
if (typeof options.optionsAnnotator.store !== 'undefined')
this.annotator.addPlugin("Store", options.optionsAnnotator.store);
if (typeof options.optionsAnnotator.diacriticMarks != 'undefined' && typeof Annotator.Plugin["Diacritics"] === 'function')
this.annotator.addPlugin("Diacritics", options.optionsAnnotator.diacriticMarks);
if (typeof options.optionsAnnotator.diacriticMarks !== 'undefined' && typeof Annotator.Plugin["Diacritics"] === 'function')
this.annotator.addPlugin("Diacritics", options.optionsAnnotator.diacriticMarks);
if (typeof Annotator.Plugin["Geolocation"] === 'function')
this.annotator.addPlugin("Geolocation",options.optionsAnnotator.geolocation);
if (typeof Annotator.Plugin["Share"] === 'function')
this.annotator.addPlugin("Share",options.optionsAnnotator.share);
this.annotator.addPlugin("VideoJS"); //it is obligatory to have
if (typeof Annotator.Plugin["RichText"] === 'function')
this.annotator.addPlugin("RichText",options.optionsAnnotator.richText);
if (typeof Annotator.Plugin["Reply"] === 'function')
this.annotator.addPlugin("Reply");
this.annotator.addPlugin("Geolocation", options.optionsAnnotator.geolocation);
if (typeof Annotator.Plugin["Share"] === 'function')
this.annotator.addPlugin("Share", options.optionsAnnotator.share);
this.annotator.addPlugin("VideoJS"); // it is obligatory to have
if (typeof Annotator.Plugin["RichText"] === 'function')
this.annotator.addPlugin("RichText", options.optionsAnnotator.richText);
if (typeof Annotator.Plugin["Reply"] === 'function')
this.annotator.addPlugin("Reply");
if (typeof Annotator.Plugin["Flagging"] === 'function')
this.annotator.addPlugin("Flagging");
//Will be add the player and the annotations plugin for video-js in the annotator
this.annotator.mplayer = this.mplayer;
this.annotator.editor.VideoJS=-1;
this.options = options;
return this;
this.annotator.addPlugin("Flagging");
if (typeof options.optionsAnnotator.highlightTags !== 'undefined')
this.annotator.addPlugin("HighlightTags", options.optionsAnnotator.highlightTags);
// Will be add the player and the annotations plugin for video-js in the annotator
this.annotator.mplayer = this.mplayer;
this.annotator.editor.VideoJS = -1;
this.options = options;
return this;
}
//----------------Local Functions for Open Video Annotator----------------//
// ----------------Local Functions for Open Video Annotator---------------- //
//--local functions
//if the annotation is a video return true
OpenVideoAnnotation.Annotator.prototype._isVideo = function(an){
//Detect if the annotation is a Open Video Annotation
var an = an || {}
rt = an.rangeTime,
isVideo = (typeof an.media!='undefined' && (an.media=='video' || an.media=='audio')),
hasContainer = (typeof an.target!='undefined' && typeof an.target.container!='undefined' ),
isNumber = (typeof rt!='undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
return (isVideo && hasContainer && isNumber);
// --local functions
// if the annotation is a video return true
OpenVideoAnnotation.Annotator.prototype._isVideo = function(an) {
// Detect if the annotation is a Open Video Annotation
var an = an || {};
var rt = an.rangeTime;
var isVideo = (typeof an.media !== 'undefined' && (an.media === 'video' || an.media === 'audio'));
var hasContainer = (typeof an.target !== 'undefined' && typeof an.target.container !== 'undefined');
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
return (isVideo && hasContainer && isNumber);
}
//if the ova has been loaded and the video is opened return true
OpenVideoAnnotation.Annotator.prototype._isloaded = function(idElem){
var loaded = typeof this.mplayer[idElem].annotations.loaded!='undefined'?true:false;
return loaded;
// if the ova has been loaded and the video is opened return true
OpenVideoAnnotation.Annotator.prototype._isloaded = function(idElem) {
return typeof this.mplayer[idElem].annotations.loaded !== 'undefined';
}
//----------------Public Functions for Open Video Annotator----------------//
// ----------------Public Functions for Open Video Annotator---------------- //
//Create a new video annotation
OpenVideoAnnotation.Annotator.prototype.newVideoAn = function(idElem){
var player = this.mplayer[idElem];
if (typeof player.play!='undefined'){
player.play();
player.one('playing',function(){
player.annotations.newan();
$('html,body').animate({
scrollTop: $("#"+player.id_).offset().top},
'slow');
player.pause();
});
}
// Create a new video annotation
OpenVideoAnnotation.Annotator.prototype.newVideoAn = function(idElem) {
var player = this.mplayer[idElem];
if (typeof player.play !== 'undefined') {
player.play();
player.one('playing', function() {
player.annotations.newan();
$('html, body').animate({
scrollTop: $("#" + player.id_).offset().top
}, 'slow');
player.pause();
});
}
};
//Show the annotation display
OpenVideoAnnotation.Annotator.prototype.showDisplay = function(idElem){
if(this._isloaded(idElem))
return this.mplayer[idElem].annotations.showDisplay();
// Show the annotation display
OpenVideoAnnotation.Annotator.prototype.showDisplay = function(idElem) {
if (this._isloaded(idElem))
return this.mplayer[idElem].annotations.showDisplay();
};
//Hide the annotation display
OpenVideoAnnotation.Annotator.prototype.hideDisplay = function(idElem){
if(this._isloaded(idElem))
return this.mplayer[idElem].annotations.hideDisplay();
// Hide the annotation display
OpenVideoAnnotation.Annotator.prototype.hideDisplay = function(idElem) {
if (this._isloaded(idElem))
return this.mplayer[idElem].annotations.hideDisplay();
};
//Refresh the annotation display
OpenVideoAnnotation.Annotator.prototype.refreshDisplay = function(idElem){
if(this._isloaded(idElem))
return this.mplayer[idElem].annotations.hideDisplay();
// Refresh the annotation display
OpenVideoAnnotation.Annotator.prototype.refreshDisplay = function(idElem) {
if (this._isloaded(idElem))
return this.mplayer[idElem].annotations.hideDisplay();
};
//Set the position of the big new annotation button
OpenVideoAnnotation.Annotator.prototype.setposBigNew = function(idElem,position){
if(this._isloaded(idElem))
return this.mplayer[idElem].annotations.setposBigNew(position);
// Set the position of the big new annotation button
OpenVideoAnnotation.Annotator.prototype.setposBigNew = function(idElem, position) {
if (this._isloaded(idElem))
return this.mplayer[idElem].annotations.setposBigNew(position);
};
OpenVideoAnnotation.Annotator.prototype.playTarget = function (annotationId){
var allannotations = this.annotator.plugins['Store'].annotations,
ovaId = annotationId,
mplayer = this.mplayer;
for (var item in allannotations) {
var an = allannotations[item];
if (typeof an.id!='undefined' && an.id == ovaId){//this is the annotation
if(this._isVideo(an)){//It is a video
for (var index in mplayer){
var player = mplayer[index];
if (player.id_ == an.target.container && player.tech.options_.source.src == an.target.src){
var anFound = an;
var playFunction = function(){
//Fix problem with youtube videos in the first play. The plugin don't have this trigger
if (player.techName == 'Youtube'){
var startAPI = function(){
player.annotations.showAnnotation(anFound);
}
if (player.annotations.loaded)
startAPI();
else
player.one('loadedRangeSlider', startAPI);//show Annotations once the RangeSlider is loaded
}else{
player.annotations.showAnnotation(anFound);
}
$('html,body').animate({
scrollTop: $("#"+player.id_).offset().top},
'slow');
};
if (player.paused()) {
player.play();
player.one('playing',playFunction);
}else{
playFunction();
}
return false;//this will stop the code to not set a new player.one.
}
}
}else{//It is a text
var hasRanges = typeof an.ranges!='undefined' && typeof an.ranges[0] !='undefined',
startOffset = hasRanges?an.ranges[0].startOffset:'',
endOffset = hasRanges?an.ranges[0].endOffset:'';
if(typeof startOffset!='undefined' && typeof endOffset!='undefined'){
$(an.highlights).parent().find('.annotator-hl').removeClass('api');
//change the color
$(an.highlights).addClass('api');
//animate to the annotation
$('html,body').animate({
scrollTop: $(an.highlights[0]).offset().top},
'slow');
}
}
}
}
OpenVideoAnnotation.Annotator.prototype.playTarget = function (annotationId) {
var allannotations = this.annotator.plugins.Store.annotations;
var ovaId = annotationId;
var mplayer = this.mplayer;
for (var item in allannotations) {
var an = allannotations[item];
if (typeof an.id != 'undefined' && an.id == ovaId) { // this is the annotation
if (this._isVideo(an)) { // It is a video
for (var index in mplayer) {
var player = mplayer[index];
if (player.id_ == an.target.container && player.tech.options_.source.src === an.target.src){
var anFound = an;
var playFunction = function() {
// Fix problem with youtube videos in the first play. The plugin don't have this trigger
if (player.techName === 'Youtube') {
var startAPI = function() {
player.annotations.showAnnotation(anFound);
}
if (player.annotations.loaded)
startAPI();
else
player.one('loadedRangeSlider', startAPI); // show Annotations once the RangeSlider is loaded
} else {
player.annotations.showAnnotation(anFound);
}
$('html, body').animate({
scrollTop: $("#"+player.id_).offset().top
}, 'slow');
};
if (player.paused()) {
player.play();
player.one('playing', playFunction);
} else {
playFunction();
}
return false; // this will stop the code to not set a new player.one.
}
}
} else { // It is a text
var hasRanges = typeof an.ranges !== 'undefined' && typeof an.ranges[0] !== 'undefined';
var startOffset = hasRanges ? an.ranges[0].startOffset : '';
var endOffset = hasRanges ? an.ranges[0].endOffset : '';
if (typeof startOffset !== 'undefined' && typeof endOffset !== 'undefined') {
$(an.highlights).parent().find('.annotator-hl').removeClass('api');
// change the color
$(an.highlights).addClass('api');
// animate to the annotation
$('html, body').animate({
scrollTop: $(an.highlights[0]).offset().top
}, 'slow');
}
}
}
}
}