198 lines
7.5 KiB
JavaScript
198 lines
7.5 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
(function($) {
|
||
|
$.fn.padmavideo = function(id, options) {
|
||
|
var opts = $.extend({
|
||
|
'layers': ['transcripts'],
|
||
|
'url': "http://pad.ma/api/",
|
||
|
'time_in': 0,
|
||
|
'time_out': 0,
|
||
|
'padma_base': 'http://pad.ma/',
|
||
|
'resolution': '480p',
|
||
|
'width': '640',
|
||
|
'interval': 400,
|
||
|
'action': 'get' //action POST param to send to url
|
||
|
}, options);
|
||
|
var $this = this;
|
||
|
|
||
|
var keys = ['layers']; //FIXME: add more apt keys
|
||
|
var $loading = $('<div />').addClass("padmaLoading").text("Loading video...").appendTo($this);
|
||
|
var sendData = JSON.stringify({'id': id, 'keys': keys});
|
||
|
//alert("hi");
|
||
|
var deferred = $.post(opts.url, {'action': opts.action, 'data': sendData}, function(response) {
|
||
|
$loading.hide().remove();
|
||
|
var padma = new PadmaVideo(id, response.data, $this, opts);
|
||
|
padma.render();
|
||
|
}, "json");
|
||
|
|
||
|
deferred.error(function(data) {
|
||
|
alert("failed to load video data");
|
||
|
});
|
||
|
};
|
||
|
|
||
|
var PadmaVideo = function(id, data, $el, opts) {
|
||
|
this.id = id;
|
||
|
this.data = data;
|
||
|
this.$el = $el;
|
||
|
this.o = opts;
|
||
|
this.videoURL = opts.padma_base + id + "/" + opts.resolution + ".webm";
|
||
|
this.render = function() {
|
||
|
var that = this;
|
||
|
this.$el.empty();
|
||
|
this.$el.append(that.getWidget());
|
||
|
};
|
||
|
|
||
|
|
||
|
this.getWidget = function() {
|
||
|
var that = this;
|
||
|
var $container = this.$container = $('<div />').addClass("padmaContainer");
|
||
|
var $video = this.$video = $('<video />')
|
||
|
.appendTo($container)
|
||
|
.attr("src", that.videoURL)
|
||
|
.attr("controls", "controls")
|
||
|
.addClass("padmaVideo")
|
||
|
.animate({'width': that.o.width})
|
||
|
.load()
|
||
|
.bind("play", function() {
|
||
|
that.interval = setInterval(function() {
|
||
|
that.updatePlayer();
|
||
|
}, that.o.interval);
|
||
|
})
|
||
|
.bind("pause", function() {
|
||
|
clearInterval(that.interval);
|
||
|
})
|
||
|
.bind("ended", function() {
|
||
|
clearInterval(that.interval);
|
||
|
})
|
||
|
.bind("seeked", function() {
|
||
|
that.updatePlayer();
|
||
|
});
|
||
|
var $annotations = this.$annotations = $('<div />')
|
||
|
.addClass("padmaAnnotations")
|
||
|
.appendTo($container);
|
||
|
return $container;
|
||
|
};
|
||
|
|
||
|
this.updatePlayer = function() {
|
||
|
var that = this;
|
||
|
var currentTime = this.$video[0].currentTime;
|
||
|
|
||
|
//first, handle if video has crossed end-point
|
||
|
if (that.o.time_out != 0) {
|
||
|
if (currentTime > that.o.time_out) {
|
||
|
that.$video[0].currentTime = that.o.time_out;
|
||
|
that.$video[0].pause();
|
||
|
}
|
||
|
if (currentTime < that.o.time_in) {
|
||
|
that.$video[0].currentTime = that.o.time_in;
|
||
|
that.$video[0].pause();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//now get all matching layers at current time code
|
||
|
var layerNames = this.o.layers,
|
||
|
matchedLayers = {};
|
||
|
$.each(layerNames, function(i, layerName) {
|
||
|
matchedLayers[layerName] = that.getLayersAtTimecode(layerName, currentTime)
|
||
|
});
|
||
|
|
||
|
//if layers are the same as last update, return
|
||
|
if (isSameLayers(matchedLayers, that.currentLayers)) return false;
|
||
|
|
||
|
//else, construct DOM elements for currently matched layers, etc.
|
||
|
that.currentLayers = matchedLayers;
|
||
|
that.$annotations.empty();
|
||
|
for (var layer in matchedLayers) {
|
||
|
if (matchedLayers.hasOwnProperty(layer)) {
|
||
|
var theseLayers = matchedLayers[layer];
|
||
|
if (theseLayers.length > 0) {
|
||
|
var $annotsForLayer = getElemForLayer(layer, theseLayers);
|
||
|
$annotsForLayer.appendTo(that.$annotations);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.getLayersAtTimecode = function(layerName, currentTime) {
|
||
|
var ret = [];
|
||
|
var theseLayers = this.data.layers[layerName];
|
||
|
$.each(theseLayers, function(i,layer) {
|
||
|
if (layer['in'] < currentTime && layer.out > currentTime) {
|
||
|
ret.push(layer);
|
||
|
}
|
||
|
});
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
};
|
||
|
|
||
|
function getElemForLayer(layerName, layers) {
|
||
|
var $elem = $('<div />').addClass("padmaLayer");
|
||
|
var title = layerName.substr(0,1).toUpperCase() + layerName.substr(1, layerName.length);
|
||
|
var $title = $('<div />').addClass("padmaLayerTitle").text(title).appendTo($elem);
|
||
|
$.each(layers, function(i,v) {
|
||
|
var $annot = $('<div />').addClass("padmaAnnot");
|
||
|
//TODO: add time-code div
|
||
|
var $annotText = $('<div />')
|
||
|
.addClass("padmaAnnotText")
|
||
|
.html(v.value)
|
||
|
.appendTo($annot);
|
||
|
$annot.appendTo($elem);
|
||
|
});
|
||
|
return $elem;
|
||
|
}
|
||
|
|
||
|
function isSameLayers(layers1, layers2) {
|
||
|
var idString1 = '',
|
||
|
idString2 = '';
|
||
|
for (var l in layers1) {
|
||
|
if (layers1.hasOwnProperty(l)) {
|
||
|
$.each(layers1[l], function(i,v) {
|
||
|
idString1 += v.id;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
for (var l in layers2) {
|
||
|
if (layers2.hasOwnProperty(l)) {
|
||
|
$.each(layers2[l], function(i,v) {
|
||
|
idString2 += v.id;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
return idString1 == idString2
|
||
|
}
|
||
|
|
||
|
//return true or false based on whether the browser can play padma video
|
||
|
function canPlayVideo() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
//loop through all elements with class padmaVideo and automagically instantiate them using optional data- attributes for options
|
||
|
$(document).ready(function() {
|
||
|
$('.padmaVideo').each(function() {
|
||
|
var padmaId = $(this).attr("data-padma-id"),
|
||
|
options = {},
|
||
|
$this = $(this);
|
||
|
|
||
|
if ($this.hasAttr("data-padma-layers")) options.layers = $this.attr("data-padma-layers");
|
||
|
if ($this.hasAttr("data-padma-url")) options.url = $this.attr("data-padma-url");
|
||
|
if ($this.hasAttr("data-padma-in")) options.time_in = $this.attr("data-padma-in");
|
||
|
if ($this.hasAttr("data-padma-out")) options.time_out = $this.attr("data-padma-out");
|
||
|
if ($this.hasAttr("data-padma-base")) options.padma_base = $this.attr("data-padma-base");
|
||
|
if ($this.hasAttr("data-padma-resolution")) options.resolution = $this.attr("data-padma-resolution");
|
||
|
if ($this.hasAttr("data-padma-width")) options.width = $this.attr("data-padma-width");
|
||
|
if ($this.hasAttr("data-padma-interval")) options.interval = $this.attr("data-padma-interval");
|
||
|
// if ($this.hasAttr("data-padma-height")) options.height = $this.attr("data-padma-height");
|
||
|
|
||
|
$this.padmavideo(padmaId, options);
|
||
|
|
||
|
});
|
||
|
});
|
||
|
|
||
|
$.fn.hasAttr = function(attr) {
|
||
|
return this.attr(attr) != undefined;
|
||
|
};
|
||
|
|
||
|
})(jQuery);
|