--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hashcut/static/hashcut/js/hashcut.js Tue Nov 27 13:51:57 2012 +0100
@@ -0,0 +1,3411 @@
+/*
+ * Copyright 2012 Institut de recherche et d'innovation
+ * contributor(s) : Raphael Velt, Karim Hamidou, Samuel Huron, Thibaut Cavalie, Anthony Ly
+ *
+ * contact@iri.centrepompidou.fr
+ * http://www.iri.centrepompidou.fr
+ *
+ * This software is a computer program whose purpose is to show and add annotations on a video .
+ * This software is governed by the CeCILL-C license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-C
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+*/
+
+var IriSP = {
+ serializers: {}
+};
+
+IriSP._ = _;
+
+IriSP.jQuery = jQuery;
+
+/* COLOR SCHEMES
+ * Color Brewer Set1 (9 classes): [ "#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999" ]
+ * Color Brewer Set3 (12 classes): ["#8DD3C7", "#FFFFB3", "#BEBADA", "#FB8072", "#80B1D3", "#FDB462", "#B3DE69", "#FCCDE5", "#D9D9D9", "#BC80BD", "#CCEBC5", "#FFED6F"]
+ * Color Brewer Paired (11 classes): ["#A6CEE3", "#1F78B4", "#B2DF8A", "#33A02C", "#FB9A99", "#E31A1C", "#FDBF6F", "#FF7F00", "#CAB2D6", "#6A3D9A", "#FFFF99" ]
+ * d3 Category10: ["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];
+ * d3 Category20: ["#1f77b4 ", "#aec7e8 ", "#ff7f0e ", "#ffbb78 ", "#2ca02c ", "#98df8a ", "#d62728 ", "#ff9896 ", "#9467bd ", "#c5b0d5 ", "#8c564b ", "#c49c94 ", "#e377c2 ", "#f7b6d2 ", "#7f7f7f ", "#c7c7c7 ", "#bcbd22 ", "#dbdb8d ", "#17becf ", "#9edae5"];
+ * d3 Category20b: ["#393b79 ", "#5254a3 ", "#6b6ecf ", "#9c9ede ", "#637939 ", "#8ca252 ", "#b5cf6b ", "#cedb9c ", "#8c6d31 ", "#bd9e39 ", "#e7ba52 ", "#e7cb94 ", "#843c39 ", "#ad494a ", "#d6616b ", "#e7969c ", "#7b4173 ", "#a55194 ", "#ce6dbd ", "#de9ed6"];
+ * d3 Category20c: ["#3182bd ", "#6baed6 ", "#9ecae1 ", "#c6dbef ", "#e6550d ", "#fd8d3c ", "#fdae6b ", "#fdd0a2 ", "#31a354 ", "#74c476 ", "#a1d99b ", "#c7e9c0 ", "#756bb1 ", "#9e9ac8 ", "#bcbddc ", "#dadaeb ", "#636363 ", "#969696 ", "#bdbdbd ", "#d9d9d9"];
+ */
+
+IriSP.vizcolors = ["#1f77b4 ", "#aec7e8 ", "#ff7f0e ", "#ffbb78 ", "#2ca02c ", "#98df8a ", "#d62728 ", "#ff9896 ", "#9467bd ", "#c5b0d5 ", "#8c564b ", "#c49c94 ", "#e377c2 ", "#f7b6d2 ", "#7f7f7f ", "#c7c7c7 ", "#bcbd22 ", "#dbdb8d ", "#17becf ", "#9edae5"];
+
+/* END init.js */
+IriSP.messages = {
+ fr: {
+ "Duration:" : "Durée :",
+ "duration:" : "durée :",
+ "Edit segment": "Éditer le segment",
+ "Move segment down": "Descendre le segment",
+ "Move segment up": "Remonter le segment",
+ "Delete segment": "Supprimer le segment",
+ "Clone segment": "Cloner le segment",
+ "From:": "De :",
+ "to:": "à :",
+ "Untitled segment": "Segment sans titre",
+ "Untitled Hashcut": "Hashcut sans titre",
+ "Copy of ": "Copie de ",
+ "A segment must be at least one second long": "Le segment doit durer au moins une seconde",
+ "A segment must be at most three minutes long": "Le segment doit durer moins de trois minutes",
+ "A segment must have a title": "Le segment doit avoir un titre",
+ "A segment should have a description": "Il est recommandé de donner une description au segment",
+ "A segment should have tags": "Il est recommandé de taguer le segment",
+ "A hashcut must be made from at least three segments": "Un hashcut doit être composé d'au moins trois segments",
+ "A hashcut must have a title": "Un titre doit être donné au hashcut",
+ "A hashcut should have a description": "Il est recommandé de donner une description au hashcut",
+ "One or more segments are invalid": "Un ou plusieurs segments ne sont pas valides",
+ "Your hashcut is valid!": "Votre hashcut est valide !",
+ "This segment is valid!": "Ce segment est valide !",
+ "Add segment to hashcut": "Ajouter au Hashcut",
+ "Save segment": "Sauvegarder",
+ "Create new segment": "Créer un nouveau segment",
+ "Edit existing segment": "Modifier le segment",
+ "The hashcut can't be published because:": "Le Hashcut ne peut pas être publié pour les raisons suivantes :",
+ "Server error\nYour hashcut couldn't be published": "Erreur serveur\nVotre hashcut n'a pas pu être publié",
+ "You haven't published your hashcut yet.\nIf you leave this page, it will be lost": "Vous n'avez pas encore publié votre Hashcut.\nSi vous quittez cette page, il sera perdu.",
+ "From hashcut:": "Du hashcut :"
+ }
+};
+
+((function() {
+ var lang = IriSP.language || navigator.language || navigator.userLanguage || "en",
+ srcs = [ ];
+ if (typeof IriSP.messages[lang] === "object") {
+ srcs.push(IriSP.messages[lang])
+ }
+ if (lang.substr(0,2) !== lang && typeof IriSP.messages[lang.substr(0,2)] === "object") {
+ srcs.push(IriSP.messages[lang.substr(0,2)])
+ }
+ srcs.push({});
+ var l = srcs.length;
+
+ IriSP.translate = function(_str) {
+ for (var i = 0; i < l; i++) {
+ if (typeof srcs[i][_str] !== "undefined") {
+ return srcs[i][_str];
+ }
+ }
+ return _str;
+ }
+
+}) ());
+
+/* END i18n.js */
+/* TODO: Separate Project-specific data from Source */
+
+/* model.js is where data is stored in a standard form, whatever the serializer */
+IriSP.Model = (function (ns) {
+
+ function pad(n, x, b) {
+ b = b || 10;
+ var s = (x).toString(b);
+ while (s.length < n) {
+ s = "0" + s;
+ }
+ return s;
+ }
+
+ function rand16(n) {
+ return pad(n, Math.floor(Math.random()*Math.pow(16,n)), 16);
+ }
+
+ var uidbase = rand16(8) + "-" + rand16(4) + "-", uidincrement = Math.floor(Math.random()*0x10000);
+
+var Model = {
+ _SOURCE_STATUS_EMPTY : 0,
+ _SOURCE_STATUS_WAITING : 1,
+ _SOURCE_STATUS_READY : 2,
+ getUID : function() {
+ return uidbase + pad(4, (++uidincrement % 0x10000), 16) + "-" + rand16(4) + "-" + rand16(6) + rand16(6);
+ },
+ isLocalURL : function(url) {
+ var matches = url.match(/^(\w+:)\/\/([^/]+)/);
+ if (matches) {
+ return(matches[1] === document.location.protocol && matches[2] === document.location.host)
+ }
+ return true;
+ },
+ regexpFromTextOrArray : function(_textOrArray, _testOnly, _iexact) {
+ var _testOnly = _testOnly || false,
+ _iexact = _iexact || false;
+ function escapeText(_text) {
+ return _text.replace(/([\\\*\+\?\|\{\[\}\]\(\)\^\$\.\#\/])/gm, '\\$1');
+ }
+ var _source =
+ typeof _textOrArray === "string"
+ ? escapeText(_textOrArray)
+ : ns._(_textOrArray).map(escapeText).join("|"),
+ _flags = 'im';
+ if (!_testOnly) {
+ _source = '(' + _source + ')';
+ _flags += 'g';
+ }
+ if (_iexact) {
+ _source = '^' + _source + '$';
+ }
+ return new RegExp( _source, _flags);
+ },
+ isoToDate : function(_str) {
+ // http://delete.me.uk/2005/03/iso8601.html
+ var 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})))?)?)?)?";
+ var d = _str.match(new RegExp(regexp));
+
+ var offset = 0;
+ var date = new Date(d[1], 0, 1);
+
+ if (d[3]) { date.setMonth(d[3] - 1); }
+ if (d[5]) { date.setDate(d[5]); }
+ if (d[7]) { date.setHours(d[7]); }
+ if (d[8]) { date.setMinutes(d[8]); }
+ if (d[10]) { date.setSeconds(d[10]); }
+ if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
+ if (d[14]) {
+ offset = (Number(d[16]) * 60) + Number(d[17]);
+ offset *= ((d[15] == '-') ? 1 : -1);
+ }
+
+ offset -= date.getTimezoneOffset();
+ time = (Number(date) + (offset * 60 * 1000));
+ var _res = new Date();
+ _res.setTime(Number(time));
+ return _res;
+ },
+ dateToIso : function(_d) {
+ var d = _d ? new Date(_d) : new Date();
+ return d.getUTCFullYear()+'-'
+ + pad(2, d.getUTCMonth()+1)+'-'
+ + pad(2, d.getUTCDate())+'T'
+ + pad(2, d.getUTCHours())+':'
+ + pad(2, d.getUTCMinutes())+':'
+ + pad(2, d.getUTCSeconds())+'Z'
+ }
+}
+
+/*
+ * Model.List is a class for a list of elements (e.g. annotations, medias, etc. that each have a distinct ID)
+ */
+Model.List = function(_directory) {
+ Array.call(this);
+ this.directory = _directory;
+ this.idIndex = [];
+ this.__events = {};
+ if (typeof _directory == "undefined") {
+ console.trace();
+ throw "Error : new Model.List(directory): directory is undefined";
+ }
+}
+
+Model.List.prototype = new Array();
+
+Model.List.prototype.hasId = function(_id) {
+ return ns._(this.idIndex).include(_id);
+}
+
+/* On recent browsers, forEach and map are defined and do what we want.
+ * Otherwise, we'll use the Underscore.js functions
+ */
+if (typeof Array.prototype.forEach === "undefined") {
+ Model.List.prototype.forEach = function(_callback) {
+ var _this = this;
+ ns._(this).forEach(function(_value, _key) {
+ _callback(_value, _key, _this);
+ });
+ }
+}
+
+if (typeof Array.prototype.map === "undefined") {
+ Model.List.prototype.map = function(_callback) {
+ var _this = this;
+ return ns._(this).map(function(_value, _key) {
+ return _callback(_value, _key, _this);
+ });
+ }
+}
+
+Model.List.prototype.pluck = function(_key) {
+ return this.map(function(_value) {
+ return _value[_key];
+ });
+}
+
+/* We override Array's filter function because it doesn't return an Model.List
+ */
+Model.List.prototype.filter = function(_callback) {
+ var _this = this,
+ _res = new Model.List(this.directory);
+ _res.addElements(ns._(this).filter(function(_value, _key) {
+ return _callback(_value, _key, _this);
+ }));
+ return _res;
+}
+
+Model.List.prototype.slice = function(_start, _end) {
+ var _res = new Model.List(this.directory);
+ _res.addElements(Array.prototype.slice.call(this, _start, _end));
+ return _res;
+}
+
+Model.List.prototype.splice = function(_start, _end) {
+ var _res = new Model.List(this.directory);
+ _res.addElements(Array.prototype.splice.call(this, _start, _end));
+ this.idIndex.splice(_start, _end);
+ return _res;
+}
+
+/* Array has a sort function, but it's not as interesting as Underscore.js's sortBy
+ * and won't return a new Model.List
+ */
+Model.List.prototype.sortBy = function(_callback) {
+ var _this = this,
+ _res = new Model.List(this.directory);
+ _res.addElements(ns._(this).sortBy(function(_value, _key) {
+ return _callback(_value, _key, _this);
+ }));
+ return _res;
+}
+
+/* Title and Description are basic information for (almost) all element types,
+ * here we can search by these criteria
+ */
+Model.List.prototype.searchByTitle = function(_text, _iexact) {
+ var _iexact = _iexact || false,
+ _rgxp = Model.regexpFromTextOrArray(_text, true);
+ return this.filter(function(_element) {
+ return _rgxp.test(_element.title);
+ });
+}
+
+Model.List.prototype.searchByDescription = function(_text, _iexact) {
+ var _iexact = _iexact || false,
+ _rgxp = Model.regexpFromTextOrArray(_text, true);
+ return this.filter(function(_element) {
+ return _rgxp.test(_element.description);
+ });
+}
+
+Model.List.prototype.searchByTextFields = function(_text, _iexact) {
+ var _iexact = _iexact || false,
+ _rgxp = Model.regexpFromTextOrArray(_text, true);
+ return this.filter(function(_element) {
+ return _rgxp.test(_element.description) || _rgxp.test(_element.title);
+ });
+}
+
+Model.List.prototype.getTitles = function() {
+ return this.map(function(_el) {
+ return _el.title;
+ });
+}
+
+Model.List.prototype.addId = function(_id) {
+ var _el = this.directory.getElement(_id)
+ if (!this.hasId(_id) && typeof _el !== "undefined") {
+ this.idIndex.push(_id);
+ Array.prototype.push.call(this, _el);
+ }
+}
+
+Model.List.prototype.push = function(_el) {
+ if (typeof _el === "undefined") {
+ return;
+ }
+ var _index = (ns._(this.idIndex).indexOf(_el.id));
+ if (_index === -1) {
+ this.idIndex.push(_el.id);
+ Array.prototype.push.call(this, _el);
+ } else {
+ this[_index] = _el;
+ }
+}
+
+Model.List.prototype.addIds = function(_array) {
+ var _l = _array.length,
+ _this = this;
+ ns._(_array).forEach(function(_id) {
+ _this.addId(_id);
+ });
+}
+
+Model.List.prototype.addElements = function(_array) {
+ var _this = this;
+ ns._(_array).forEach(function(_el) {
+ _this.push(_el);
+ });
+}
+
+Model.List.prototype.removeId = function(_id, _deleteFromDirectory) {
+ var _deleteFromDirectory = _deleteFromDirectory || false,
+ _index = (ns._(this.idIndex).indexOf(_id));
+ if (_index !== -1) {
+ this.splice(_index,1);
+ }
+ if (_deleteFromDirectory) {
+ delete this.directory.elements[_id];
+ }
+}
+
+Model.List.prototype.removeElement = function(_el, _deleteFromDirectory) {
+ var _deleteFromDirectory = _deleteFromDirectory || false;
+ this.removeId(_el.id);
+}
+
+Model.List.prototype.removeIds = function(_list, _deleteFromDirectory) {
+ var _deleteFromDirectory = _deleteFromDirectory || false,
+ _this = this;
+ ns._(_list).forEach(function(_id) {
+ _this.removeId(_id);
+ });
+}
+
+Model.List.prototype.removeElements = function(_list, _deleteFromDirectory) {
+ var _deleteFromDirectory = _deleteFromDirectory || false,
+ _this = this;
+ ns._(_list).forEach(function(_el) {
+ _this.removeElement(_el);
+ });
+}
+
+Model.List.prototype.on = function(_event, _callback) {
+ if (typeof this.__events[_event] === "undefined") {
+ this.__events[_event] = [];
+ }
+ this.__events[_event].push(_callback);
+}
+
+Model.List.prototype.off = function(_event, _callback) {
+ if (typeof this.__events[_event] !== "undefined") {
+ this.__events[_event] = ns._(this.__events[_event]).reject(function(_fn) {
+ return _fn === _callback;
+ });
+ }
+}
+
+Model.List.prototype.trigger = function(_event, _data) {
+ var _list = this;
+ ns._(this.__events[_event]).each(function(_callback) {
+ _callback.call(_list, _data);
+ });
+}
+
+/* A simple time management object, that helps converting millisecs to seconds and strings,
+ * without the clumsiness of the original Date object.
+ */
+
+Model.Time = function(_milliseconds) {
+ this.milliseconds = 0;
+ this.setMilliseconds(_milliseconds);
+}
+
+Model.Time.prototype.setMilliseconds = function(_milliseconds) {
+ var _ante = this.milliseconds;
+ switch(typeof _milliseconds) {
+ case "string":
+ this.milliseconds = parseInt(_milliseconds);
+ break;
+ case "number":
+ this.milliseconds = Math.floor(_milliseconds);
+ break;
+ case "object":
+ this.milliseconds = parseInt(_milliseconds.valueOf());
+ break;
+ default:
+ this.milliseconds = 0;
+ }
+ if (this.milliseconds === NaN) {
+ this.milliseconds = _ante;
+ }
+}
+
+Model.Time.prototype.setSeconds = function(_seconds) {
+ this.milliseconds = 1000 * _seconds;
+}
+
+Model.Time.prototype.getSeconds = function() {
+ return this.milliseconds / 1000;
+}
+
+Model.Time.prototype.getHMS = function() {
+ var _totalSeconds = Math.abs(Math.floor(this.getSeconds()));
+ return {
+ hours : Math.floor(_totalSeconds / 3600),
+ minutes : (Math.floor(_totalSeconds / 60) % 60),
+ seconds : _totalSeconds % 60,
+ milliseconds: this.milliseconds % 1000
+ }
+}
+
+Model.Time.prototype.add = function(_milliseconds) {
+ this.milliseconds += new Model.Time(_milliseconds).milliseconds;
+}
+
+Model.Time.prototype.valueOf = function() {
+ return this.milliseconds;
+}
+
+Model.Time.prototype.toString = function(showCs) {
+ var _hms = this.getHMS(),
+ _res = '';
+ if (_hms.hours) {
+ _res += _hms.hours + ':'
+ }
+ _res += pad(2, _hms.minutes) + ':' + pad(2, _hms.seconds);
+ if (showCs) {
+ _res += "." + Math.round(_hms.milliseconds / 100)
+ }
+ return _res;
+}
+
+/* Model.Reference handles references between elements
+ */
+
+Model.Reference = function(_source, _idRef) {
+ this.source = _source;
+ this.id = _idRef;
+ if (typeof _idRef === "object") {
+ this.isList = true;
+ } else {
+ this.isList = false;
+ }
+ this.refresh();
+}
+
+Model.Reference.prototype.refresh = function() {
+ if (this.isList) {
+ this.contents = new Model.List(this.source.directory);
+ this.contents.addIds(this.id);
+ } else {
+ this.contents = this.source.getElement(this.id);
+ }
+
+}
+
+Model.Reference.prototype.getContents = function() {
+ if (typeof this.contents === "undefined" || (this.isList && this.contents.length != this.id.length)) {
+ this.refresh();
+ }
+ return this.contents;
+}
+
+Model.Reference.prototype.isOrHasId = function(_idRef) {
+ if (this.isList) {
+ return (ns._(this.id).indexOf(_idRef) !== -1)
+ } else {
+ return (this.id == _idRef);
+ }
+}
+
+/* */
+
+Model.Element = function(_id, _source) {
+ this.elementType = 'element';
+ this.title = "";
+ this.description = "";
+ this.__events = {}
+ if (typeof _source === "undefined") {
+ return;
+ }
+ if (typeof _id === "undefined" || !_id) {
+ _id = Model.getUID();
+ }
+ this.id = _id;
+ this.source = _source;
+ if (_source !== this) {
+ this.source.directory.addElement(this);
+ }
+}
+
+Model.Element.prototype.toString = function() {
+ return this.elementType + (this.elementType !== 'element' ? ', id=' + this.id + ', title="' + this.title + '"' : '');
+}
+
+Model.Element.prototype.setReference = function(_elementType, _idRef) {
+ this[_elementType] = new Model.Reference(this.source, _idRef);
+}
+
+Model.Element.prototype.getReference = function(_elementType) {
+ if (typeof this[_elementType] !== "undefined") {
+ return this[_elementType].getContents();
+ }
+}
+
+Model.Element.prototype.getRelated = function(_elementType, _global) {
+ _global = (typeof _global !== "undefined" && _global);
+ var _this = this;
+ return this.source.getList(_elementType, _global).filter(function(_el) {
+ var _ref = _el[_this.elementType];
+ return _ref && _ref.isOrHasId(_this.id);
+ });
+}
+
+Model.Element.prototype.on = function(_event, _callback) {
+ if (typeof this.__events[_event] === "undefined") {
+ this.__events[_event] = [];
+ }
+ this.__events[_event].push(_callback);
+}
+
+Model.Element.prototype.off = function(_event, _callback) {
+ if (typeof this.__events[_event] !== "undefined") {
+ this.__events[_event] = ns._(this.__events[_event]).reject(function(_fn) {
+ return _fn === _callback;
+ });
+ }
+}
+
+Model.Element.prototype.trigger = function(_event, _data) {
+ var _element = this;
+ ns._(this.__events[_event]).each(function(_callback) {
+ _callback.call(_element, _data);
+ });
+}
+
+/* */
+
+Model.Playable = function(_id, _source) {
+ Model.Element.call(this, _id, _source);
+ if (typeof _source === "undefined") {
+ return;
+ }
+ this.elementType = 'playable';
+ this.currentTime = new Model.Time();
+ this.volume = .5;
+ this.paused = true;
+ this.muted = false;
+ var _this = this;
+ this.on("play", function() {
+ _this.paused = false;
+ });
+ this.on("pause", function() {
+ _this.paused = true;
+ });
+ this.on("timeupdate", function(_time) {
+ _this.currentTime = _time;
+ _this.getAnnotations().filter(function(_a) {
+ return (_a.end <= _time || _a.begin > _time) && _a.playing
+ }).forEach(function(_a) {
+ _a.playing = false;
+ _a.trigger("leave");
+ _this.trigger("leave-annotation",_a);
+ });
+ _this.getAnnotations().filter(function(_a) {
+ return _a.begin <= _time && _a.end > _time && !_a.playing
+ }).forEach(function(_a) {
+ _a.playing = true;
+ _a.trigger("enter");
+ _this.trigger("enter-annotation",_a);
+ });
+ });
+}
+
+Model.Playable.prototype = new Model.Element();
+
+Model.Playable.prototype.getCurrentTime = function() {
+ return this.currentTime;
+}
+
+Model.Playable.prototype.getVolume = function() {
+ return this.volume;
+}
+
+Model.Playable.prototype.getPaused = function() {
+ return this.paused;
+}
+
+Model.Playable.prototype.getMuted = function() {
+ return this.muted;
+}
+
+Model.Playable.prototype.setCurrentTime = function(_time) {
+ this.trigger("setcurrenttime",_time);
+}
+
+Model.Playable.prototype.setVolume = function(_vol) {
+ this.trigger("setvolume",_vol);
+}
+
+Model.Playable.prototype.setMuted = function(_muted) {
+ this.trigger("setmuted",_muted);
+}
+
+Model.Playable.prototype.play = function() {
+ this.trigger("setplay");
+}
+
+Model.Playable.prototype.pause = function() {
+ this.trigger("setpause");
+}
+
+Model.Playable.prototype.show = function() {}
+
+Model.Playable.prototype.hide = function() {}
+
+/* */
+
+Model.Media = function(_id, _source) {
+ Model.Playable.call(this, _id, _source);
+ this.elementType = 'media';
+ this.duration = new Model.Time();
+ this.video = '';
+ var _this = this;
+}
+
+Model.Media.prototype = new Model.Playable();
+
+/* Default functions to be overriden by players */
+
+Model.Media.prototype.setDuration = function(_durationMs) {
+ this.duration.setMilliseconds(_durationMs);
+}
+
+Model.Media.prototype.getAnnotations = function() {
+ return this.getRelated("annotation");
+}
+
+Model.Media.prototype.getAnnotationsByTypeTitle = function(_title) {
+ var _annTypes = this.source.getAnnotationTypes().searchByTitle(_title).pluck("id");
+ if (_annTypes.length) {
+ return this.getAnnotations().filter(function(_annotation) {
+ return ns._(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1;
+ });
+ } else {
+ return new Model.List(this.source.directory)
+ }
+}
+
+/* */
+
+Model.Tag = function(_id, _source) {
+ Model.Element.call(this, _id, _source);
+ this.elementType = 'tag';
+}
+
+Model.Tag.prototype = new Model.Element();
+
+Model.Tag.prototype.getAnnotations = function() {
+ return this.getRelated("annotation");
+}
+
+/* */
+Model.AnnotationType = function(_id, _source) {
+ Model.Element.call(this, _id, _source);
+ this.elementType = 'annotationType';
+}
+
+Model.AnnotationType.prototype = new Model.Element();
+
+Model.AnnotationType.prototype.getAnnotations = function() {
+ return this.getRelated("annotation");
+}
+
+/* Annotation
+ * */
+
+Model.Annotation = function(_id, _source) {
+ Model.Element.call(this, _id, _source);
+ this.elementType = 'annotation';
+ this.begin = new Model.Time();
+ this.end = new Model.Time();
+ this.tag = new Model.Reference(_source, []);
+ this.playing = false;
+ var _this = this;
+ this.on("click", function() {
+ _this.getMedia().setCurrentTime(_this.begin);
+ });
+}
+
+Model.Annotation.prototype = new Model.Element();
+
+Model.Annotation.prototype.setBegin = function(_beginMs) {
+ this.begin.setMilliseconds(Math.max(0,_beginMs));
+ this.trigger("change-begin");
+ if (this.end < this.begin) {
+ this.setEnd(this.begin);
+ }
+}
+
+Model.Annotation.prototype.setEnd = function(_endMs) {
+ this.end.setMilliseconds(Math.min(_endMs, this.getMedia().duration.milliseconds));
+ this.trigger("change-end");
+ if (this.end < this.begin) {
+ this.setBegin(this.end);
+ }
+}
+
+Model.Annotation.prototype.setDuration = function(_durMs) {
+ this.setEnd(_durMs + this.begin.milliseconds);
+}
+
+Model.Annotation.prototype.setMedia = function(_idRef) {
+ this.setReference("media", _idRef);
+}
+
+Model.Annotation.prototype.getMedia = function() {
+ return this.getReference("media");
+}
+
+Model.Annotation.prototype.setAnnotationType = function(_idRef) {
+ this.setReference("annotationType", _idRef);
+}
+
+Model.Annotation.prototype.getAnnotationType = function() {
+ return this.getReference("annotationType");
+}
+
+Model.Annotation.prototype.setTags = function(_idRefs) {
+ this.setReference("tag", _idRefs);
+}
+
+Model.Annotation.prototype.getTags = function() {
+ return this.getReference("tag");
+}
+
+Model.Annotation.prototype.getTagTexts = function() {
+ return this.getTags().getTitles();
+}
+
+Model.Annotation.prototype.getDuration = function() {
+ return new Model.Time(this.end.milliseconds - this.begin.milliseconds)
+}
+
+/* */
+
+Model.MashedAnnotation = function(_mashup, _annotation) {
+ Model.Element.call(this, _mashup.id + "_" + _annotation.id, _annotation.source);
+ this.elementType = 'mashedAnnotation';
+ this.annotation = _annotation;
+ this.begin = new Model.Time();
+ this.end = new Model.Time();
+ this.duration = new Model.Time();
+ this.title = this.annotation.title;
+ this.description = this.annotation.description;
+ this.color = this.annotation.color;
+ var _this = this;
+ this.on("click", function() {
+ _mashup.setCurrentTime(_this.begin);
+ });
+ this.on("enter", function() {
+ _this.annotation.trigger("enter");
+ });
+ this.on("leave", function() {
+ _this.annotation.trigger("leave");
+ });
+}
+
+Model.MashedAnnotation.prototype = new Model.Element(null);
+
+Model.MashedAnnotation.prototype.getMedia = function() {
+ return this.annotation.getReference("media");
+}
+
+Model.MashedAnnotation.prototype.getAnnotationType = function() {
+ return this.annotation.getReference("annotationType");
+}
+
+Model.MashedAnnotation.prototype.getTags = function() {
+ return this.annotation.getReference("tag");
+}
+
+Model.MashedAnnotation.prototype.getTagTexts = function() {
+ return this.annotation.getTags().getTitles();
+}
+
+Model.MashedAnnotation.prototype.getDuration = function() {
+ return this.annotation.getDuration();
+}
+
+Model.MashedAnnotation.prototype.setBegin = function(_begin) {
+ this.begin.setMilliseconds(_begin);
+ this.duration.setMilliseconds(this.annotation.getDuration());
+ this.end.setMilliseconds(_begin + this.duration);
+}
+
+/* */
+
+Model.Mashup = function(_id, _source) {
+ Model.Playable.call(this, _id, _source);
+ this.elementType = 'mashup';
+ this.duration = new Model.Time();
+ this.segments = new Model.List(_source.directory);
+ this.loaded = false;
+ var _this = this;
+ this._updateTimes = function() {
+ _this.updateTimes();
+ _this.trigger("change");
+ }
+ this.on("add", this._updateTimes);
+ this.on("remove", this._updateTimes);
+}
+
+Model.Mashup.prototype = new Model.Playable();
+
+Model.Mashup.prototype.checkLoaded = function() {
+ var loaded = !!this.segments.length;
+ this.getMedias().forEach(function(_m) {
+ loaded = loaded && _m.loaded;
+ });
+ this.loaded = loaded;
+ if (loaded) {
+ this.trigger("loadedmetadata");
+ }
+}
+
+Model.Mashup.prototype.updateTimes = function() {
+ var _time = 0;
+ this.segments.forEach(function(_segment) {
+ _segment.setBegin(_time);
+ _time = _segment.end;
+ });
+ this.duration.setMilliseconds(_time);
+}
+
+Model.Mashup.prototype.addAnnotation = function(_annotation, _defer) {
+ var _mashedAnnotation = new Model.MashedAnnotation(this, _annotation),
+ _defer = _defer || false;
+ this.segments.push(_mashedAnnotation);
+ _annotation.on("change-begin", this._updateTimes);
+ _annotation.on("change-end", this._updateTimes);
+ if (!_defer) {
+ this.trigger("add");
+ }
+}
+
+Model.Mashup.prototype.addAnnotationById = function(_elId, _defer) {
+ var _annotation = this.source.getElement(_elId),
+ _defer = _defer || false;
+ if (typeof _annotation !== "undefined") {
+ this.addAnnotation(_annotation, _defer);
+ }
+}
+
+Model.Mashup.prototype.addAnnotations = function(_segments) {
+ var _this = this;
+ ns._(_segments).forEach(function(_segment) {
+ _this.addAnnotation(_segment, true);
+ });
+ this.trigger("add");
+}
+
+Model.Mashup.prototype.addAnnotationsById = function(_segments) {
+ var _this = this;
+ ns._(_segments).forEach(function(_segment) {
+ _this.addAnnotationById(_segment, true);
+ });
+ this.trigger("add");
+}
+
+Model.Mashup.prototype.removeAnnotation = function(_annotation, _defer) {
+ var _defer = _defer || false;
+ _annotation.off("change-begin", this._updateTimes);
+ _annotation.off("change-end", this._updateTimes);
+ this.segments.removeId(this.id + "_" + _annotation.id);
+ if (!_defer) {
+ this.trigger("remove");
+ }
+}
+
+Model.Mashup.prototype.removeAnnotationById = function(_annId, _defer) {
+ var _defer = _defer || false;
+ var _annotation = this.source.getElement(_annId);
+
+ if (_annotation) {
+ this.removeAnnotation(_annotation, _defer);
+ }
+ if (!_defer) {
+ this.trigger("remove");
+ }
+}
+
+Model.Mashup.prototype.setAnnotations = function(_segments) {
+ while (this.segments.length) {
+ this.removeAnnotation(this.segments[0].annotation, true);
+ }
+ this.addAnnotations(_segments);
+}
+
+Model.Mashup.prototype.setAnnotationsById = function(_segments) {
+ while (this.segments.length) {
+ this.removeAnnotation(this.segments[0].annotation, true);
+ }
+ this.addAnnotationsById(_segments);
+}
+
+Model.Mashup.prototype.hasAnnotation = function(_annotation) {
+ return !!ns._(this.segments).find(function(_s) {
+ return _s.annotation === _annotation
+ });
+}
+
+Model.Mashup.prototype.getAnnotation = function(_annotation) {
+ return ns._(this.segments).find(function(_s) {
+ return _s.annotation === _annotation
+ });
+}
+
+Model.Mashup.prototype.getAnnotationById = function(_id) {
+ return ns._(this.segments).find(function(_s) {
+ return _s.annotation.id === _id
+ });
+}
+
+Model.Mashup.prototype.getAnnotations = function() {
+ return this.segments;
+}
+
+Model.Mashup.prototype.getOriginalAnnotations = function() {
+ var annotations = new Model.List(this.source.directory);
+ this.segments.forEach(function(_s) {
+ annotations.push(_s.annotation);
+ });
+ return annotations;
+}
+
+Model.Mashup.prototype.getMedias = function() {
+ var medias = new Model.List(this.source.directory);
+ this.segments.forEach(function(_annotation) {
+ medias.push(_annotation.getMedia())
+ })
+ return medias;
+}
+
+Model.Mashup.prototype.getAnnotationsByTypeTitle = function(_title) {
+ var _annTypes = this.source.getAnnotationTypes().searchByTitle(_title).pluck("id");
+ if (_annTypes.length) {
+ return this.getAnnotations().filter(function(_annotation) {
+ return ns._(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1;
+ });
+ } else {
+ return new Model.List(this.source.directory)
+ }
+}
+
+Model.Mashup.prototype.getAnnotationAtTime = function(_time) {
+ var _list = this.segments.filter(function(_annotation) {
+ return _annotation.begin <= _time && _annotation.end > _time;
+ });
+ if (_list.length) {
+ return _list[0];
+ } else {
+ return undefined;
+ }
+}
+
+Model.Mashup.prototype.getMediaAtTime = function(_time) {
+ var _annotation = this.getAnnotationAtTime(_time);
+ if (typeof _annotation !== "undefined") {
+ return _annotation.getMedia();
+ } else {
+ return undefined;
+ }
+}
+
+/* */
+
+Model.Source = function(_config) {
+ Model.Element.call(this, false, this);
+ this.status = Model._SOURCE_STATUS_EMPTY;
+ this.elementType = "source";
+ if (typeof _config !== "undefined") {
+ var _this = this;
+ ns._(_config).forEach(function(_v, _k) {
+ _this[_k] = _v;
+ })
+ this.callbackQueue = [];
+ this.contents = {};
+ this.get();
+ }
+}
+
+Model.Source.prototype = new Model.Element();
+
+Model.Source.prototype.addList = function(_listId, _contents) {
+ if (typeof this.contents[_listId] === "undefined") {
+ this.contents[_listId] = new Model.List(this.directory);
+ }
+ this.contents[_listId].addElements(_contents);
+}
+
+Model.Source.prototype.getList = function(_listId, _global) {
+ _global = (typeof _global !== "undefined" && _global);
+ if (_global || typeof this.contents[_listId] === "undefined") {
+ return this.directory.getGlobalList().filter(function(_e) {
+ return (_e.elementType === _listId);
+ });
+ } else {
+ return this.contents[_listId];
+ }
+}
+
+Model.Source.prototype.forEach = function(_callback) {
+ var _this = this;
+ ns._(this.contents).forEach(function(_value, _key) {
+ _callback.call(_this, _value, _key);
+ })
+}
+
+Model.Source.prototype.getElement = function(_elId) {
+ return this.directory.getElement(_elId);
+}
+
+Model.Source.prototype.get = function() {
+ this.status = Model._SOURCE_STATUS_WAITING;
+ this.handleCallbacks();
+}
+
+/* We defer the callbacks calls so they execute after the queue is cleared */
+Model.Source.prototype.deferCallback = function(_callback) {
+ var _this = this;
+ ns._.defer(function() {
+ _callback.call(_this);
+ });
+}
+
+Model.Source.prototype.handleCallbacks = function() {
+ this.status = Model._SOURCE_STATUS_READY;
+ while (this.callbackQueue.length) {
+ this.deferCallback(this.callbackQueue.splice(0,1)[0]);
+ }
+}
+Model.Source.prototype.onLoad = function(_callback) {
+ if (this.status === Model._SOURCE_STATUS_READY) {
+ this.deferCallback(_callback);
+ } else {
+ this.callbackQueue.push(_callback);
+ }
+}
+
+Model.Source.prototype.serialize = function() {
+ return this.serializer.serialize(this);
+}
+
+Model.Source.prototype.deSerialize = function(_data) {
+ this.serializer.deSerialize(_data, this);
+}
+
+Model.Source.prototype.getAnnotations = function(_global) {
+ _global = (typeof _global !== "undefined" && _global);
+ return this.getList("annotation", _global);
+}
+
+Model.Source.prototype.getMedias = function(_global) {
+ _global = (typeof _global !== "undefined" && _global);
+ return this.getList("media", _global);
+}
+
+Model.Source.prototype.getTags = function(_global) {
+ _global = (typeof _global !== "undefined" && _global);
+ return this.getList("tag", _global);
+}
+
+Model.Source.prototype.getMashups = function(_global) {
+ _global = (typeof _global !== "undefined" && _global);
+ return this.getList("mashup", _global);
+}
+
+Model.Source.prototype.getAnnotationTypes = function(_global) {
+ _global = (typeof _global !== "undefined" && _global);
+ return this.getList("annotationType", _global);
+}
+
+Model.Source.prototype.getAnnotationsByTypeTitle = function(_title, _global) {
+ _global = (typeof _global !== "undefined" && _global);
+ var _res = new Model.List(this.directory),
+ _annTypes = this.getAnnotationTypes(_global).searchByTitle(_title);
+ _annTypes.forEach(function(_annType) {
+ _res.addElements(_annType.getAnnotations(_global));
+ })
+ return _res;
+}
+
+Model.Source.prototype.getDuration = function() {
+ var _m = this.currentMedia;
+ if (typeof _m !== "undefined") {
+ return this.currentMedia.duration;
+ }
+}
+
+Model.Source.prototype.getCurrentMedia = function(_opts) {
+ if (typeof this.currentMedia === "undefined") {
+ if (_opts.is_mashup) {
+ var _mashups = this.getMashups();
+ if (_mashups.length) {
+ this.currentMedia = _mashups[0];
+ }
+ } else {
+ var _medias = this.getMedias();
+ if (_medias.length) {
+ this.currentMedia = _medias[0];
+ }
+ }
+ }
+ return this.currentMedia;
+}
+
+Model.Source.prototype.merge = function(_source) {
+ var _this = this;
+ _source.forEach(function(_value, _key) {
+ _this.getList(_key).addElements(_value);
+ });
+}
+
+/* */
+
+Model.RemoteSource = function(_config) {
+ Model.Source.call(this, _config);
+}
+
+Model.RemoteSource.prototype = new Model.Source();
+
+Model.RemoteSource.prototype.get = function() {
+ this.status = Model._SOURCE_STATUS_WAITING;
+ var _this = this,
+ urlparams = this.url_params || {},
+ dataType = (Model.isLocalURL(this.url) ? "json" : "jsonp");
+ urlparams.format = dataType;
+ ns.jQuery.ajax({
+ url: this.url,
+ dataType: dataType,
+ data: urlparams,
+ traditional: true,
+ success: function(_result) {
+ _this.deSerialize(_result);
+ _this.handleCallbacks();
+ }
+ });
+}
+
+/* */
+
+Model.Directory = function() {
+ this.remoteSources = {};
+ this.elements = {};
+}
+
+Model.Directory.prototype.remoteSource = function(_properties) {
+ if (typeof _properties !== "object" || typeof _properties.url === "undefined") {
+ throw "Error : Model.Directory.remoteSource(configuration): configuration.url is undefined";
+ }
+ var _config = ns._({ directory: this }).extend(_properties);
+ _config.url_params = _config.url_params || {};
+ var _hash = _config.url + "?" + ns.jQuery.param(_config.url_params);
+ if (typeof this.remoteSources[_hash] === "undefined") {
+ this.remoteSources[_hash] = new Model.RemoteSource(_config);
+ }
+ return this.remoteSources[_hash];
+}
+
+Model.Directory.prototype.newLocalSource = function(_properties) {
+ var _config = ns._({ directory: this }).extend(_properties),
+ _res = new Model.Source(_config);
+ return _res;
+}
+
+Model.Directory.prototype.getElement = function(_id) {
+ return this.elements[_id];
+}
+
+Model.Directory.prototype.addElement = function(_element) {
+ this.elements[_element.id] = _element;
+}
+
+Model.Directory.prototype.getGlobalList = function() {
+ var _res = new Model.List(this);
+ _res.addIds(ns._(this.elements).keys());
+ return _res;
+}
+
+return Model;
+
+})(IriSP);
+
+/* END model.js */
+
+/* LDT Platform Serializer */
+
+if (typeof IriSP.serializers === "undefined") {
+ IriSP.serializers = {}
+}
+
+IriSP.serializers.ldt = {
+ types : {
+ media : {
+ serialized_name : "medias",
+ deserializer : function(_data, _source) {
+ var _res = new IriSP.Model.Media(_data.id, _source);
+ _res.video = (
+ typeof _data.url !== "undefined"
+ ? _data.url
+ : (
+ typeof _data.href !== "undefined"
+ ? _data.href
+ : null
+ )
+ );
+ if (typeof _data.meta.item !== "undefined" && _data.meta.item.name === "streamer") {
+ _res.streamer = _data.meta.item.value;
+ }
+ _res.title = _data.meta["dc:title"];
+ _res.description = _data.meta["dc:description"];
+ _res.setDuration(_data.meta["dc:duration"]);
+ _res.url = _data.meta.url;
+ if (typeof _data.meta.img !== "undefined" && _data.meta.img.src !== "undefined") {
+ _res.thumbnail = _data.meta.img.src;
+ }
+ return _res;
+ },
+ serializer : function(_data, _source, _dest) {
+ var _res = {
+ id : _data.id,
+ url : _data.video,
+ meta : {
+ "dc:title": _data.title || "",
+ "dc:description": _data.description || "",
+ "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified),
+ "dc:creator" : _data.creator || _source.creator,
+ "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator,
+ "dc:duration" : _data.duration.milliseconds
+ }
+ }
+ _dest.medias.push(_res);
+ var _list = {
+ id: IriSP.Model.getUID(),
+ meta : {
+ "dc:title": _data.title || "",
+ "dc:description": _data.description || "",
+ "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified),
+ "dc:creator" : _data.creator || _source.creator,
+ "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator,
+ "id-ref": _data.id
+ },
+ items: _source.getAnnotationTypes().filter(function(_at) {
+ return _at.media === _data;
+ }).map(function(_at) {
+ return {
+ "id-ref": _at.id
+ }
+ })
+ }
+ _dest.lists.push(_list);
+ _dest.views[0].contents.push(_data.id);
+ }
+ },
+ tag : {
+ serialized_name : "tags",
+ model_name : "tag",
+ deserializer : function(_data, _source) {
+ var _res = new IriSP.Model.Tag(_data.id, _source);
+ _res.title = _data.meta["dc:title"];
+ return _res;
+ },
+ serializer : function(_data, _source, _dest) {
+ var _res = {
+ id : _data.id,
+ meta : {
+ "dc:title": _data.title || "",
+ "dc:description": _data.description || "",
+ "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified),
+ "dc:creator" : _data.creator || _source.creator,
+ "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator,
+ }
+ }
+ _dest.tags.push(_res);
+ }
+ },
+ annotationType : {
+ serialized_name : "annotation-types",
+ deserializer : function(_data, _source) {
+ var _res = new IriSP.Model.AnnotationType(_data.id, _source);
+ _res.title = _data["dc:title"];
+ _res.description = _data["dc:description"];
+ return _res;
+ },
+ serializer : function(_data, _source, _dest) {
+ var _res = {
+ id : _data.id,
+ "dc:title": _data.title || "",
+ "dc:description": _data.description || "",
+ "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified),
+ "dc:creator" : _data.creator || _source.creator,
+ "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator,
+ }
+ _dest["annotation-types"].push(_res);
+ _dest.views[0].annotation_types.push(_data.id);
+ }
+ },
+ annotation : {
+ serialized_name : "annotations",
+ deserializer : function(_data, _source) {
+ var _res = new IriSP.Model.Annotation(_data.id, _source);
+ _res.title = _data.content.title || "";
+ _res.description = _data.content.description || "";
+ if (typeof _data.content.img !== "undefined" && _data.content.img.src !== "undefined") {
+ _res.thumbnail = _data.content.img.src;
+ }
+ _res.created = IriSP.Model.isoToDate(_data.meta["dc:created"]);
+ if (typeof _data.color !== "undefined") {
+ var _c = parseInt(_data.color).toString(16);
+ while (_c.length < 6) {
+ _c = '0' + _c;
+ }
+ _res.color = '#' + _c;
+ }
+ _res.setMedia(_data.media);
+ _res.setAnnotationType(_data.meta["id-ref"]);
+ _res.setTags(IriSP._(_data.tags).pluck("id-ref"));
+ _res.keywords = _res.getTagTexts();
+ _res.setBegin(_data.begin);
+ _res.setEnd(_data.end);
+ _res.creator = _data.meta["dc:creator"] || "";
+ _res.project = _data.meta.project || "";
+ if (typeof _data.meta["dc:source"] !== "undefined" && typeof _data.meta["dc:source"].content !== "undefined") {
+ _res.source = JSON.parse(_data.meta["dc:source"].content);
+ }
+ if (typeof _data.content.audio !== "undefined" && _data.content.audio.href) {
+ _res.audio = _data.content.audio;
+ }
+ return _res;
+ },
+ serializer : function(_data, _source, _dest) {
+ var _color = parseInt(_data.color.replace(/^#/,''),16).toString();
+ var _res = {
+ id : _data.id,
+ begin : _data.begin.milliseconds,
+ end : _data.end.milliseconds,
+ content : {
+ title : _data.title || "",
+ description : _data.description || "",
+ audio : _data.audio,
+ img: {
+ src: _data.thumbnail
+ }
+ },
+ color: _color,
+ media : _data.media.id,
+ meta : {
+ "id-ref" : _data.getAnnotationType().id,
+ "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified),
+ "dc:creator" : _data.creator || _source.creator,
+ "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator,
+// project : _source.projectId
+ },
+ tags : IriSP._(_data.tag.id).map(function(_id) {
+ return {
+ "id-ref" : _id
+ }
+ })
+ }
+ _dest.annotations.push(_res);
+ }
+ },
+ mashup : {
+ serialized_name : "lists",
+ deserializer : function(_data, _source) {
+ if (typeof _data.meta !== "object" || typeof _data.meta.listtype !== "string" || _data.meta.listtype !== "mashup") {
+ return undefined;
+ }
+ var _res = new IriSP.Model.Mashup(_data.id, _source);
+ _res.title = _data.meta["dc:title"];
+ _res.description = _data.meta["dc:description"];
+ _res.creator = _data.meta["dc:creator"];
+ _res.setAnnotationsById(_data.items);
+ return _res;
+ },
+ serializer : function(_data, _source, _dest) {
+ var _res = {
+ meta : {
+ "dc:title": _data.title || "",
+ "dc:description": _data.description || "",
+ "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified),
+ "dc:creator" : _data.creator || _source.creator,
+ "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator,
+ listtype: "mashup"
+ },
+ items: _data.segments.map(function(_annotation) {
+ return _annotation.annotation.id;
+ }),
+ id: _data.id
+ }
+ _dest.lists.push(_res);
+ }
+ }
+ },
+ serialize : function(_source) {
+ var _res = {
+ meta: {
+ "dc:creator": _source.creator,
+ "dc:contributor" : _source.contributor || _source.creator,
+ "dc:created": IriSP.Model.dateToIso(_source.created),
+ "dc:modified" : IriSP.Model.dateToIso(_source.modified),
+ "dc:title": _source.title || "",
+ "dc:description": _source.description || "",
+ id: _source.projectId || _source.id
+ },
+ views: [
+ {
+ id: IriSP.Model.getUID(),
+ contents: [],
+ annotation_types: []
+ }
+ ],
+ lists: [],
+ "annotation-types": [],
+ medias: [],
+ tags: [],
+ annotations: []
+ },
+ _this = this;
+ _source.forEach(function(_list, _typename) {
+ if (typeof _this.types[_typename] !== "undefined") {
+ _list.forEach(function(_el) {
+ _this.types[_typename].serializer(_el, _source, _res);
+ });
+ }
+ });
+ return JSON.stringify(_res);
+ },
+ deSerialize : function(_data, _source) {
+ if (typeof _data !== "object" || _data === null) {
+ return;
+ }
+ IriSP._(this.types).forEach(function(_type, _typename) {
+ var _listdata = _data[_type.serialized_name],
+ _list = new IriSP.Model.List(_source.directory);
+ if (typeof _listdata !== "undefined" && _listdata !== null) {
+ if (_listdata.hasOwnProperty("length")) {
+ var _l = _listdata.length;
+ for (var _i = 0; _i < _l; _i++) {
+ var _element = _type.deserializer(_listdata[_i], _source);
+ if (typeof _element !== "undefined" && _element) {
+ _list.push(_element);
+ }
+ }
+ } else {
+ var _element = _type.deserializer(_listdata, _source);
+ if (typeof _element !== "undefined" && _element) {
+ _list.push(_element);
+ }
+ }
+ }
+ _source.addList(_typename, _list);
+ });
+
+ if (typeof _data.meta !== "undefined") {
+ _source.projectId = _data.meta.id;
+ }
+
+ if (typeof _data.meta !== "undefined" && typeof _data.meta.main_media !== "undefined" && typeof _data.meta.main_media["id-ref"] !== "undefined") {
+ _source.currentMedia = _source.getElement(_data.meta.main_media["id-ref"]);
+ }
+ }
+}
+
+/* END ldt-serializer.js */
+
+IriSP.serializers.segmentapi = {
+ deSerialize : function(_data, _source) {
+ var _annotationlist = new IriSP.Model.List(_source.directory),
+ _medialist = new IriSP.Model.List(_source.directory);
+ _source.addList("media", _medialist);
+
+ function deserializeObject(_s) {
+ var _ann = new IriSP.Model.Annotation(_s.element_id, _source),
+ _media = _source.getElement(_s.iri_id);
+ if (!_media) {
+ _media = new IriSP.Model.Media(_s.iri_id, _source);
+ _source.getMedias().push(_media);
+ }
+ _ann.setMedia(_s.iri_id);
+ _ann.title = _s.title;
+ _ann.description = _s.abstract;
+ _ann.begin = new IriSP.Model.Time(_s.start_ts);
+ _ann.end = new IriSP.Model.Time(_s.start_ts + _s.duration);
+ _ann.keywords = _s.tags.split(",");
+ _ann.project_id = _s.project_id;
+ _annotationlist.push(_ann);
+ }
+
+ if (typeof _data.objects !== "undefined") {
+ IriSP._(_data.objects).each(deserializeObject);
+ } else {
+ deserializeObject(_data);
+ }
+ _source.addList("annotation", _annotationlist);
+ }
+}
+
+/* END segmentapi-serializer.js */
+IriSP.serializers.content = {
+ deSerialize : function(_data, _source) {
+ var _medialist = new IriSP.Model.List(_source.directory);
+
+ function deserializeObject(_m, i) {
+ var _media = new IriSP.Model.Media(_m.iri_id, _source);
+ _media.video = _m.media_url;
+ _media.title = _m.title;
+ _media.description = _m.description;
+ _media.setDuration(_m.duration);
+ _media.thumbnail = _m.image;
+ _media.color = IriSP.vizcolors[i % IriSP.vizcolors.length];
+ _media.keywords = _m.tags;
+ _medialist.push(_media);
+ }
+
+ if (typeof _data.objects !== "undefined") {
+ IriSP._(_data.objects).each(deserializeObject);
+ } else {
+ deserializeObject(_data, 0);
+ }
+
+ _source.addList("media", _medialist);
+ }
+};
+
+/* END contentapi-serializer.js */
+IriSP.mashupcore = function(project, mashup) {
+
+ var currentMedia,
+ intervaltemplate = _.template('<span class="frise-indication" style="left:<%= left %>%;"><%= time.toString() %></span>'),
+ viztemplate = _.template('<div class="frise-segment annotation" data-segment-id="<%= segmentid %>" style="background-color:<%= color %>; left:<%= left %>%; width:<%= width %>%;"></div>');
+
+ function updateMashupUI() {
+ var vizhtml = '', t = 0, k = mashup.duration ? (100 / mashup.duration) : 0;
+ mashup.segments.forEach(function(_s) {
+ var vizdata = {
+ left: k * t,
+ width: k * _s.duration,
+ color: _s.color,
+ segmentid: _s.annotation.id
+ }
+ vizhtml += viztemplate(vizdata);
+ t += _s.duration.milliseconds;
+ });
+
+ var intervals = [ 1000, 2000, 5000, 10000, 30000, 60000, 120000, 300000, 600000, 900000, 1800000, 3600000, 7200000 ];
+
+ function createIntervals(maxn) {
+ for (var i = 0; i < intervals.length; i++) {
+ if (mashup.duration / intervals[i] <= maxn) {
+ var html = '';
+ for (var j = intervals[i]; j < mashup.duration; j += intervals[i]) {
+ html += intervaltemplate({ left: k * j, time: new IriSP.Model.Time(j) });
+ }
+ return html;
+ }
+ }
+ return "";
+ }
+
+ $(".mashup-total-duration").text(mashup.duration.toString());
+ $(".mashup-frise .frise-segments").html(vizhtml);
+ $(".mashup-frise .frise-indications").html(createIntervals(6));
+
+ if (currentMedia === mashup) {
+ $(".Ldt-Ctrl-Time-Total").text(currentMedia.duration.toString());
+ if (mashupTimecode > mashup.duration) {
+ mashup.setCurrentTime(mashup.duration);
+ }
+ changeCurrentAnnotation();
+ mashup.trigger("enter-annotation",mashup.currentAnnotation);
+ }
+
+ }
+
+ /* Slider */
+
+ var timeSlider = $(".Ldt-Slider"),
+ timeSliderContainer = $(".Ldt-Slider-Container"),
+ slidersRange = 920;
+ timeSlider.slider({
+ range: "min",
+ value: 0,
+ min: 0,
+ max: slidersRange,
+ slide: function(event, ui) {
+ if (currentMedia) {
+ var t = currentMedia.duration * ui.value / slidersRange;
+ currentMedia.setCurrentTime(t);
+ }
+ }
+ });
+
+ var timeSliderHandle = timeSlider.find('.ui-slider-handle'),
+ timeSliderMaximized = false,
+ timeSliderTimeoutId = false,
+ timeSliderMinimizedHeight = 4,
+ timeSliderMaximizedHeight = 10,
+ timeSliderTimeoutDuration = 1500,
+ timeTooltip = $(".Ldt-Slider-Time");
+
+ timeSliderContainer.css(calculateSliderCss(timeSliderMinimizedHeight));
+ timeSliderHandle.css(calculateHandleCss(timeSliderMinimizedHeight));
+
+ function timeSliderMouseOver() {
+ if (timeSliderTimeoutId) {
+ window.clearTimeout(timeSliderTimeoutId);
+ timeSliderTimeoutId = false;
+ }
+ if (!timeSliderMaximized) {
+ timeSliderAnimateToHeight(timeSliderMaximizedHeight);
+ timeSliderMaximized = true;
+ }
+ }
+
+ function timeSliderMouseOut() {
+ timeTooltip.hide();
+ if (timeSliderTimeoutId) {
+ clearTimeout(timeSliderTimeoutId);
+ timeSliderTimeoutId = false;
+ }
+ timeSliderTimeoutId = setTimeout(function() {
+ if (timeSliderMaximized) {
+ timeSliderAnimateToHeight(timeSliderMinimizedHeight);
+ timeSliderMaximized = false;
+ }
+ timeSliderTimeoutId = false;
+ }, timeSliderTimeoutDuration);
+ }
+
+ timeSliderContainer
+ .mouseover(function() {
+ timeTooltip.show();
+ timeSliderMouseOver();
+ })
+ .mouseout(timeSliderMouseOut);
+ timeSlider.mousemove(function(_e) {
+ if (!currentMedia) {
+ return;
+ }
+ var _x = _e.pageX - timeSlider.offset().left,
+ _t = new IriSP.Model.Time(
+ Math.max(0, currentMedia.duration * Math.min(1, _x / timeSlider.width()))
+ );
+ timeTooltip.text(_t.toString()).css("left",_x);
+ });
+
+ $(".Ldt-Ctrl").mouseover(timeSliderMouseOver).mouseout(timeSliderMouseOut);
+
+ function timeSliderAnimateToHeight(_height) {
+ timeSliderContainer.stop().animate(
+ calculateSliderCss(_height),
+ 500,
+ function() {
+ IriSP.jQuery(this).css("overflow","visible");
+ });
+ timeSliderHandle.stop().animate(
+ calculateHandleCss(_height),
+ 500,
+ function() {
+ IriSP.jQuery(this).css("overflow","visible");
+ });
+ }
+
+ function calculateSliderCss(_size) {
+ return {
+ height: _size + "px",
+ "margin-top": (timeSliderMinimizedHeight - _size) + "px"
+ };
+ }
+
+ function calculateHandleCss(_size) {
+ return {
+ height: (2 + _size) + "px",
+ width: (2 + _size) + "px",
+ "margin-left": -Math.ceil(2 + _size / 2) + "px"
+ }
+ }
+
+ /* Controller Widget */
+
+ var volBlock = $(".Ldt-Ctrl-Volume-Control");
+
+ $('.Ldt-Ctrl-Sound')
+ .click(function() {
+ if (currentMedia) {
+ currentMedia.setMuted(!currentMedia.getMuted());
+ }
+ })
+ .mouseover(function() {
+ volBlock.show();
+ })
+ .mouseout(function() {
+ volBlock.hide();
+ });
+ volBlock.mouseover(function() {
+ volBlock.show();
+ }).mouseout(function() {
+ volBlock.hide();
+ });
+
+ var volBar = $(".Ldt-Ctrl-Volume-Bar");
+
+ function ctrlVolumeUpdater() {
+ if (currentMedia) {
+ var _muted = currentMedia.getMuted(),
+ _vol = currentMedia.getVolume();
+ if (_vol === false) {
+ _vol = .5;
+ }
+ var _soundCtl = $(".Ldt-Ctrl-Sound");
+ _soundCtl.removeClass("Ldt-Ctrl-Sound-Mute Ldt-Ctrl-Sound-Half Ldt-Ctrl-Sound-Full");
+ if (_muted) {
+ _soundCtl.attr("title", "Activer le son")
+ .addClass("Ldt-Ctrl-Sound-Mute");
+ } else {
+ _soundCtl.attr("title", "Couper le son")
+ .addClass(_vol < .5 ? "Ldt-Ctrl-Sound-Half" : "Ldt-Ctrl-Sound-Full" )
+ }
+ volBar.slider("value", _muted ? 0 : 100 * _vol);
+ volBar.attr("title",'Volume : ' + Math.floor(100 * _vol) + '%');
+ }
+ }
+
+ volBar.slider({
+ slide: function(event, ui) {
+ if (currentMedia) {
+ currentMedia.setVolume(ui.value / 100);
+ }
+ }
+ });
+
+ $(".Ldt-Ctrl-Play").click(function() {
+ if (currentMedia) {
+ if (currentMedia.getPaused()) {
+ currentMedia.play();
+ } else {
+ currentMedia.pause();
+ }
+ }
+ });
+
+ /* UI Events */
+
+ function onCurrentMediaPlay() {
+ $(".Ldt-Ctrl-Play")
+ .attr("title", "Pause")
+ .removeClass("Ldt-Ctrl-Play-PlayState")
+ .addClass("Ldt-Ctrl-Play-PauseState")
+ }
+
+ function onCurrentMediaPause() {
+ $(".Ldt-Ctrl-Play")
+ .attr("title", "Lecture")
+ .removeClass("Ldt-Ctrl-Play-PauseState")
+ .addClass("Ldt-Ctrl-Play-PlayState")
+ }
+
+ function onCurrentMediaTimeupdate(_time) {
+ $(".Ldt-Ctrl-Time-Elapsed").text(_time.toString());
+ timeSlider.slider("value",slidersRange * _time / currentMedia.duration);
+ }
+
+ /* Mashup Player */
+
+ mashup.currentMedia = null;
+ mashup.currentAnnotation = null;
+ mashup.seeking = false;
+ var mashupSegmentBegin,
+ mashupSegmentEnd,
+ mashupTimecode = 0,
+ seekdiv = $(".video-wait"),
+ mashupTimedelta;
+
+ function showSeek() {
+ if (currentMedia.seeking) {
+ seekdiv.show();
+ }
+ }
+
+ function changeCurrentAnnotation() {
+ if (mashupTimecode >= mashup.duration) {
+ if (!mashup.paused) {
+ mashup.paused = true;
+ mashup.trigger("pause");
+ }
+ mashupTimecode = 0;
+ }
+ var _annotation = mashup.getAnnotationAtTime( mashupTimecode );
+ if (typeof _annotation === "undefined") {
+ if (mashup.currentMedia) {
+ mashup.currentMedia.pause();
+ if (!mashup.paused) {
+ mashup.paused = true;
+ mashup.trigger("pause");
+ }
+ }
+ return;
+ }
+ mashup.currentAnnotation = _annotation;
+ mashupSegmentBegin = mashup.currentAnnotation.annotation.begin.milliseconds;
+ mashupSegmentEnd = mashup.currentAnnotation.annotation.end.milliseconds;
+ mashupTimedelta = mashupSegmentBegin - mashup.currentAnnotation.begin.milliseconds;
+ mashup.currentMedia = mashup.currentAnnotation.getMedia();
+
+ project.getMedias().forEach(function(_media) {
+ if (_media !== mashup.currentMedia) {
+ _media.hide();
+ _media.pause();
+ } else {
+ _media.show();
+ }
+ });
+
+ mashup.currentMedia.setCurrentTime( mashupTimecode + mashupTimedelta);
+ mashup.currentMedia.seeking = true;
+
+ if (!mashup.paused) {
+ mashup.currentMedia.play();
+ mashup.seeking = true;
+ setTimeout(showSeek,200);
+ }
+ mashup.trigger("timeupdate", new IriSP.Model.Time(mashupTimecode));
+
+ }
+
+ function addMedia(media) {
+ if (media.has_player) {
+ return;
+ }
+ media.has_player = true;
+ var videoid = "video_" + media.id,
+ videoEl = $('<video>'),
+ width = $(".video").width(),
+ height = $(".video").height(),
+ mp4_file = media.video.replace(/\.webm$/i,'.mp4'),
+ webm_file = media.video.replace(/\.mp4$/i,'.webm'),
+ mp4_src = $('<source>'),
+ webm_src = $('<source>');
+ mp4_src.attr({
+ src: mp4_file,
+ type: "video/mp4"
+ });
+ webm_src.attr({
+ src: webm_file,
+ type: "video/webm"
+ });
+ videoEl.attr({
+ id : videoid,
+ width : width,
+ height : height
+ }).css({
+ position : "absolute",
+ left: 0,
+ top: 0,
+ width : width,
+ height : height
+ });
+ videoEl.append(mp4_src).append(webm_src);
+ $(".video").append(videoEl);
+
+ media.show = function() {
+ videoEl.show();
+ }
+ media.hide = function() {
+ videoEl.hide();
+ }
+
+ var popcorn = Popcorn("#" + videoid);
+
+ // Binding functions to Popcorn
+
+ media.on("setcurrenttime", function(_milliseconds) {
+ if (media.loaded) {
+ popcorn.currentTime(_milliseconds / 1000);
+ media.seeking = true;
+ setTimeout(showSeek,200);
+ }
+ });
+
+ media.on("setvolume", function(_vol) {
+ media.volume = _vol;
+ if (media.loaded) {
+ popcorn.volume(_vol);
+ }
+ });
+
+ media.on("setmuted", function(_muted) {
+ media.muted = _muted;
+ if (media.loaded) {
+ popcorn.muted(_muted);
+ }
+ });
+
+ media.on("setplay", function() {
+ if (media.loaded) {
+ popcorn.play();
+ }
+ });
+
+ media.on("setpause", function() {
+ if (media.loaded) {
+ popcorn.pause();
+ }
+ });
+
+ // Binding Popcorn events to media
+
+ function getVolume() {
+ media.muted = popcorn.muted();
+ media.volume = popcorn.volume();
+ }
+
+ popcorn.on("loadedmetadata", function() {
+ getVolume();
+ media.loaded = true;
+ media.trigger("loadedmetadata");
+ media.trigger("volumechange");
+ })
+
+ popcorn.on("timeupdate", function() {
+ media.trigger("timeupdate", new IriSP.Model.Time(1000*popcorn.currentTime()));
+ });
+
+ popcorn.on("volumechange", function() {
+ getVolume();
+ media.trigger("volumechange");
+ })
+
+ popcorn.on("play", function() {
+ media.trigger("play");
+ });
+
+ popcorn.on("pause", function() {
+ media.trigger("pause");
+ });
+
+ popcorn.on("seeked", function() {
+ media.trigger("seeked");
+ });
+
+ // Binding UI Events and Mashup Playing to Media
+
+ media.on("loadedmetadata", function() {
+ if (media === currentMedia) {
+ seekdiv.hide();
+ }
+ mashup.checkLoaded();
+ });
+
+ media.on("play", function() {
+ if (media === currentMedia) {
+ onCurrentMediaPlay();
+ }
+ if (mashup === currentMedia && media === mashup.currentMedia) {
+ mashup.trigger("play");
+ }
+ });
+
+ media.on("pause", function() {
+ if (media === currentMedia) {
+ onCurrentMediaPause();
+ }
+ if (mashup === currentMedia && media === mashup.currentMedia) {
+ mashup.trigger("pause");
+ }
+ });
+
+ media.on("timeupdate", function(_time) {
+ if (media === currentMedia) {
+ $(".frise-position").css("left",(100*_time/media.duration)+"%");
+ onCurrentMediaTimeupdate(_time);
+ }
+ if (mashup === currentMedia && !mashup.paused && media === mashup.currentMedia && !media.seeking) {
+ if ( _time < mashupSegmentEnd ) {
+ if ( _time >= mashupSegmentBegin ) {
+ mashupTimecode = _time - mashupTimedelta;
+ } else {
+ mashupTimecode = mashupSegmentBegin - mashupTimedelta;
+ media.setCurrentTime(mashupSegmentBegin);
+ }
+ } else {
+ mashupTimecode = mashupSegmentEnd - mashupTimedelta;
+ media.pause();
+ changeCurrentAnnotation();
+ }
+ mashup.trigger("timeupdate", new IriSP.Model.Time(mashupTimecode));
+ }
+ });
+
+ media.on("seeked", function() {
+ media.seeking = false;
+ if (mashup === currentMedia && media === mashup.currentMedia && mashup.seeking) {
+ mashup.seeking = false;
+ }
+ seekdiv.hide();
+ });
+
+ media.on("volumechange", function() {
+ if (media === currentMedia) {
+ ctrlVolumeUpdater();
+ }
+ mashup.muted = media.muted;
+ mashup.volume = media.volume;
+ mashup.trigger("volumechange");
+ });
+
+ project.on("set-current", function(_m) {
+ if (_m !== media) {
+ media.hide();
+ }
+ });
+
+ }
+
+ // Mashup Events
+
+ mashup.on("setcurrenttime", function(_milliseconds) {
+ mashupTimecode = _milliseconds;
+ changeCurrentAnnotation();
+ });
+
+ mashup.on("setvolume", function(_vol) {
+ mashup.getMedias().forEach(function(_media) {
+ _media.setVolume(_vol);
+ });
+ mashup.volume = _vol;
+ });
+
+ mashup.on("setmuted", function(_muted) {
+ mashup.getMedias().forEach(function(_media) {
+ _media.setMuted(_muted);
+ });
+ mashup.muted = _muted;
+ });
+
+ mashup.on("setplay", function() {
+ mashup.paused = false;
+ changeCurrentAnnotation();
+ });
+
+ mashup.on("setpause", function() {
+ mashup.paused = true;
+ if (mashup.currentMedia) {
+ mashup.currentMedia.pause();
+ }
+ });
+
+ mashup.on("loadedmetadata", function() {
+ if (mashup === currentMedia) {
+ changeCurrentAnnotation();
+ }
+ });
+
+ mashup.on("volumechange", function() {
+ if (mashup === currentMedia) {
+ ctrlVolumeUpdater();
+ }
+ });
+ /* Mashup Events to UI */
+
+ mashup.on("play", function() {
+ if (mashup === currentMedia) {
+ onCurrentMediaPlay();
+ }
+ });
+
+ mashup.on("pause", function() {
+ if (mashup === currentMedia) {
+ onCurrentMediaPause();
+ }
+ });
+
+ mashup.on("timeupdate", function(_time) {
+ if (mashup === currentMedia) {
+ $(".frise-position").css("left",(100*_time/mashup.duration)+"%");
+ onCurrentMediaTimeupdate(_time);
+ }
+ });
+
+ mashup.on("add", function() {
+ mashup.getMedias().forEach(addMedia);
+ })
+
+ mashup.on("change",updateMashupUI);
+
+ mashup.on("enter-annotation", function(segment) {
+ var a = segment.annotation;
+ $(".annotation-title").text(a.title);
+ $(".annotation-begin").text(a.begin.toString());
+ $(".annotation-end").text(a.end.toString());
+ $(".annotation-tags").text(a.keywords.join(", "));
+ $(".annotation-media-title").text(a.getMedia().title);
+ $(".annotation-description").text(a.description);
+ var p = (segment.begin + segment.end) / (2 * mashup.duration);
+ $(".mashup-description .pointer").css("left", (100 * p) + "%");
+ project.trigger("mouseout-annotation");
+ });
+
+ project.on("mouseover-annotation", function(annotation) {
+ $(".annotation").removeClass("active");
+ if (!annotation) {
+ return;
+ }
+ var segment = mashup.getAnnotation(annotation);
+ $(".annotation[data-segment-id='" + annotation.id + "']").addClass("active");
+ $(".mashup-tooltip").show().css({
+ left: (100 * ( segment.begin + segment.end ) / ( 2 * mashup.duration ) ) + "%"
+ });
+ $(".mashup-tooltip .segment-tooltip").text(annotation.title);
+ });
+
+ project.on("mouseout-annotation", function() {
+ if (currentMedia === mashup && mashup.currentAnnotation) {
+ $(".annotation").removeClass("active");
+ $(".item-video.annotation[data-segment-id='" + mashup.currentAnnotation.annotation.id + "']").addClass("active");
+ }
+ $(".mashup-tooltip").hide();
+ });
+
+ project.on("click-annotation", function(annotation) {
+ if (!annotation) {
+ return;
+ }
+ var segment = mashup.getAnnotation(annotation);
+ project.trigger("set-current", mashup);
+ if (segment) {
+ mashup.setCurrentTime(segment.begin);
+ }
+ })
+
+ project.on("set-current", function(media) {
+ currentMedia = media;
+ if (currentMedia.elementType === "media") {
+ if (!media.has_player) {
+ addMedia(media);
+ }
+ media.show();
+ if (!currentMedia.loaded) {
+ seekdiv.show();
+ }
+ }
+ if (currentMedia.elementType === "mashup") {
+ mashup.checkLoaded();
+ }
+ $(".Ldt-Ctrl-Time-Total").text(currentMedia.duration.toString());
+ currentMedia.trigger("timeupdate",currentMedia.getCurrentTime());
+ currentMedia.trigger("pause");
+ });
+
+ var mouseoverSegment;
+
+ $(".mashup-frise")
+ .mousemove(function(evt) {
+ if (!mashup.duration.milliseconds) {
+ return;
+ }
+ var el = $(this), t = ( evt.pageX - el.offset().left ) * mashup.duration / el.width(), segment = mashup.getAnnotationAtTime(t);
+ if (segment) {
+ if (segment !== mouseoverSegment) {
+ project.trigger("mouseover-annotation", segment.annotation);
+ }
+ } else {
+ if (mouseoverSegment) {
+ project.trigger("mouseout-annotation");
+ }
+ }
+ mouseoverSegment = segment;
+ })
+ .mouseleave(function() {
+ project.trigger("mouseout-annotation");
+ mouseoverSegment = undefined;
+ })
+ .click(function(evt) {
+ if (!mashup.duration.milliseconds) {
+ return;
+ }
+ var el = $(this), t = ( evt.pageX - el.offset().left ) * mashup.duration / el.width(), segment = mashup.getAnnotationAtTime(t);
+ if (segment) {
+ project.trigger("click-annotation", segment.annotation);
+ }
+ });
+
+ mashup.trigger("add");
+
+}
+
+/* END mashupcore.js */
+
+IriSP.editor = function(options) {
+
+ /* Load Media List */
+
+ var directory = new IriSP.Model.Directory(),
+ apidirectory = new IriSP.Model.Directory(),
+ project = directory.remoteSource({
+ url: IriSP.endpoints.content,
+ url_params: _({}).extend(options.filter),
+ serializer: IriSP.serializers.content
+ }),
+/* project = directory.remoteSource({
+ url: options.url,
+ serializer: IriSP.serializers.medialist
+ }),
+*/
+ mashup = new IriSP.Model.Mashup(false, project),
+ mediatemplate = _.template(
+ '<li class="item-video media" data-media-id="<%= id %>"><div class="media-count-wrap"><span class="media-count"></span></div>'
+ + '<img class="thumbnail" src="<%= thumbnail %>" alt="<%= title %>" />'
+ + '<div class="video-info"><h3 class="title-video"><%= title %></h3><p class="description"><%= description %></p>'
+ + '<p class="time-length"><%= IriSP.translate("Duration:") %> <span><%= duration.toString() %></span></p></div><div class="media-found-segments"></div></li>'
+ ),
+ segmenttemplate = _.template(
+ '<li class="item-video annotation" data-segment-id="<%= annotation.id %>" data-media-id="<%= annotation.getMedia().id %>">'
+ + '<img class="thumbnail" src="<%= annotation.thumbnail %>" alt="<%= annotation.getMedia().title %>" />'
+ + '<div class="validate <%= annotation.status %>"><div class="validate-tooltip"><ul><li><%= annotation.status_messages.join("</li><li>") %></li></ul></div></div><div class="video-info"><h3 class="title-video"><%= annotation.getMedia().title %></h3>'
+ + '<p class="subtitle"><%= annotation.title %></p><p class="duration"><%= annotation.begin.toString() %> - <%= annotation.end.toString() %> (<%= annotation.getDuration().toString() %>)</p>'
+ + '<ul class="tools"><li><a class="edit" href="#" title="<%= IriSP.translate("Edit segment") %>"></a></li><li><a class="bottom" href="#" title="<%= IriSP.translate("Move segment down") %>"></a></li>'
+ + '<li><a class="top" href="#" title="<%= IriSP.translate("Move segment up") %>"></a></li><li><a class="delete" href="#" title="<%= IriSP.translate("Delete segment") %>"></a></li></ul></div></li>'
+ ),
+ mediasegmenttemplate = _.template(
+ '<div class="media-segment">'
+ + '<div class="media-segment-section" style="left:<%= left %>px; width:<%= width %>px; background:<%= color %>; top: <%= top %>px;" data-segment-id="<%= annotation.id %>"></div>'
+ + '<div class="popin media-segment-popin" style="left:<%= popleft %>px; top: <%= 5+top %>px;"><img style="left:<%= pointerpos %>px;" class="pointer" src="img/popin-triangle.png" alt="" /><div class="popin-content">'
+ + '<h3><%= annotation.title %></h3><a href="#" class="button reprendre-segment" data-segment-id="<%= annotation.id %>"><%= IriSP.translate("Clone segment") %></a>'
+ + '<p><%= IriSP.translate("From:") %> <span><%= annotation.begin.toString() %></span> <%= IriSP.translate("to:") %> <span><%= annotation.end.toString() %></span> (<%= IriSP.translate("duration:") %> <span><%= annotation.getDuration().toString() %></span>)</p>'
+ + '</div></div></div>'
+ ),
+ mediasegmentlisttemplate = _.template(
+ '<div class="media-segment-list" style="height: <%= height %>px"><div class="media-current-section" style="left: <%= left %>px; width: <%= width %>px;"></div><div class="media-segment-list-inner"></div><%= segments %></div>'
+ ),
+ mediafoundtemplate = _.template(
+ '<div class="media-segment"><div class="media-segment-section" style="left:<%= left %>px; width:<%= width %>px; background:<%= color %>; top: <%= top %>px;"></div>'
+ + '<div class="popin media-found-popin" style="left:<%= popleft %>px; top: <%= 5+top %>px;"><img style="left:<%= pointerpos %>px;" class="pointer" src="img/popin-triangle.png" alt="" /><div class="popin-content">'
+ + '<h3><%= title %></h3><a href="#" class="button clone-segment" data-segment-id="<%= annotation.id %>"><%= IriSP.translate("Clone segment") %></a>'
+ + '</div></div></div>'
+ ),
+ mediafoundlisttemplate = _.template(
+ '<div class="media-found-list" style="height: <%= height %>px"><div class="media-segment-list-inner"></div><%= segments %></div>'
+ ),
+ mashupstatus = '',
+ addMode, currentMedia, currentSegment;
+
+ IriSP.mashupcore(project, mashup);
+
+ /* Validation of segments and mashup */
+
+ var segmentcritical = [
+ {
+ validate: function(_s) {
+ return (_s.getDuration() >= 1000);
+ },
+ message: "A segment must be at least one second long"
+ },
+ {
+ validate: function(_s) {
+ return (_s.getDuration() < 180000);
+ },
+ message: "A segment must be at most three minutes long"
+ },
+ {
+ validate: function(_s) {
+ return (!!_s.title && _s.title !== IriSP.translate("Untitled segment"));
+ },
+ message: "A segment must have a title"
+ }
+ ];
+ var segmentwarning = [
+ {
+ validate: function(_s) {
+ return (!!_s.description);
+ },
+ message: "A segment should have a description"
+ },
+ {
+ validate: function(_s) {
+ return (!!_s.keywords.length);
+ },
+ message: "A segment should have tags"
+ }
+ ];
+
+ var mashupcritical = [
+ {
+ validate: function(_m) {
+ return _m.segments.length > 2;
+ },
+ message: "A hashcut must be made from at least three segments"
+ },
+ {
+ validate: function(_m) {
+ return (!!_m.title && _m.title !== IriSP.translate("Untitled Hashcut"));
+ },
+ message: "A hashcut must have a title"
+ }
+ ];
+ var mashupwarning = [
+ {
+ validate: function(_m) {
+ return !!_m.description
+ },
+ message: "A hashcut should have a description"
+ }
+ ];
+
+ /* Fill left column with Media List */
+
+ project.onLoad(function() {
+ var html = '';
+ project.getMedias().forEach(function(_m) {
+ html += mediatemplate(_m);
+ });
+ $(".col-left .list-video").html(html);
+ project.getMedias().forEach(function(_m) {
+ apidirectory.remoteSource({
+ url: IriSP.endpoints.segment,
+ url_params: {
+ iri_id: _m.id,
+ limit: 0
+ },
+ serializer: IriSP.serializers.segmentapi
+ }).onLoad(function() {
+ var medias = this.getMedias(),
+ annotations = this.getAnnotations();
+ if (medias && medias.length) {
+ var mediaid = medias[0].id;
+ el = $(".item-video[data-media-id='" + mediaid + "'] .media-count");
+ el.text(annotations.length).parent().show();
+ mediasegmentscache[mediaid] = annotations;
+ if (currentMedia && mediaid === currentMedia.id && currentSegment) {
+ showOtherSegments();
+ }
+ }
+ });
+ });
+ });
+
+ /* Search Media with left column form */
+
+ $(".col-left input").on("keyup change input paste", function() {
+ var val = $(this).val();
+ if (val) {
+ var find = IriSP.Model.regexpFromTextOrArray(val, true),
+ replace = IriSP.Model.regexpFromTextOrArray(val, false);
+ }
+ $(".col-left .item-video").each(function() {
+ var li = $(this),
+ mediaid = li.attr("data-media-id"),
+ media = directory.getElement(mediaid);
+ if (!val) {
+ li.find(".title-video").text(media.title);
+ li.find(".description").text(media.description);
+ li.find(".media-found-segments").html("");
+ li.show();
+ } else {
+ var apimedia = apidirectory.getElement(mediaid);
+ if (apimedia) {
+ var annotations = apimedia.getAnnotations().searchByTextFields(val);
+ } else {
+ var annotations = [];
+ }
+ var found = find.test(media.title) || find.test(media.description) || annotations.length;
+ if (found) {
+ li.find(".title-video").html(media.title.replace(replace, '<span style="background: #fc00ff; color: #ffffff;">$1</span>'));
+ li.find(".description").html(media.description.replace(replace, '<span style="background: #fc00ff; color: #ffffff;">$1</span>'));
+ var html = '',
+ k = 230 / media.duration,
+ lines = [];
+ _(annotations).each(function(_a, i) {
+ var pos = k * (_a.begin + _a.end) / 2,
+ corrpos = Math.max(76, Math.min(156, pos)),
+ line = IriSP._(lines).find(function(line) {
+ return !IriSP._(line.annotations).find(function(ann) {
+ return ann.begin < _a.end && ann.end > _a.begin
+ });
+ });
+ if (!line) {
+ line = { index: lines.length, annotations: []};
+ lines.push(line);
+ }
+ line.annotations.push(_a);
+ vizdata = {
+ annotation : _a,
+ left : k * _a.begin,
+ width : k * _a.getDuration(),
+ top: 8 * line.index,
+ color: IriSP.vizcolors[i % IriSP.vizcolors.length],
+ title: _a.title.replace(replace, '<span style="background: #fc00ff; color: #ffffff;">$1</span>'),
+ popleft : corrpos,
+ pointerpos : (pos - corrpos),
+ }
+ html += mediafoundtemplate(vizdata);
+ });
+ html = mediafoundlisttemplate({
+ height: 8 * lines.length,
+ segments: html
+ });
+ li.find(".media-found-segments").html(html);
+ li.show();
+ } else {
+ li.hide();
+ }
+ }
+ })
+ });
+
+ /* Fill right column when mashup is updated */
+
+ function updateMashupUI() {
+ var listhtml = '', critical = false, warning = false, messages = [];
+ mashup.segments.forEach(function(_s) {
+ listhtml += segmenttemplate(_s);
+ if (_s.annotation.status === "critical") {
+ critical = true;
+ }
+ });
+ if (critical) {
+ messages.push("One or more segments are invalid");
+ }
+
+ _(mashupcritical).each(function(sc) {
+ if (!sc.validate(mashup)) {
+ critical = true;
+ messages.push(sc.message);
+ }
+ });
+ _(mashupwarning).each(function(sc) {
+ if (!sc.validate(mashup)) {
+ warning = true;
+ messages.push(sc.message);
+ }
+ });
+ mashup.status = critical ? "critical" : (warning ? "warning" : "valid");
+ if (!messages.length) {
+ messages.push("Your hashcut is valid!");
+ }
+ mashupstatus = ' - ' + _(messages).map(IriSP.translate).join('\n - ');
+
+ $(".publier-button").toggleClass("disable", critical);
+
+ $(".liste-segment .validate").removeClass("critical warning valid").addClass(mashup.status);
+ $(".liste-segment .validate-tooltip").html("<ul><li>" + messages.join("</li><li>")+"</li></ul>");
+
+ $(".col-right .list-video").html(listhtml).find(".item-video:last-child .bottom, .item-video:first-child .top").addClass("disable");
+
+ project.trigger("mouseout-annotation");
+ }
+
+ mashup.on("setcurrent", function() {
+ currentMedia = mashup;
+ });
+
+ mashup.on("change",updateMashupUI);
+
+ /* Slice Widget */
+
+ var sliceSlider = $(".Ldt-Slice"),
+ sliceStartTime,
+ slidersRange = 920;
+
+ sliceSlider.slider({
+ range: true,
+ values: [0, slidersRange],
+ min: 0,
+ max: slidersRange,
+ start: function() {
+ if (currentMedia) {
+ if (!currentMedia.getPaused()) {
+ currentMedia.pause();
+ }
+ }
+ },
+ slide: function(event, ui) {
+ if (currentMedia && currentSegment) {
+ var t = currentMedia.duration * ui.value / slidersRange;
+ if (ui.value === ui.values[0]) {
+ currentSegment.setBegin(t);
+ } else {
+ currentSegment.setEnd(t);
+ }
+ }
+ }
+ });
+
+ sliceSlider.find(".ui-slider-handle:first")
+ .addClass("Ldt-Slice-left-handle")
+ .click(function() {
+ if (currentMedia && currentSegment) {
+ currentMedia.setCurrentTime(currentSegment.begin);
+ }
+ });
+ sliceSlider.find(".ui-slider-handle:last")
+ .addClass("Ldt-Slice-right-handle")
+ .click(function() {
+ if (currentMedia && currentSegment) {
+ currentMedia.setCurrentTime(currentSegment.end);
+ }
+ });
+
+
+ /* Update Segment UI */
+
+ function updateSegmentUI() {
+ if (currentMedia && currentSegment) {
+ var start = currentSegment.begin,
+ end = currentSegment.end,
+ dur = currentSegment.getDuration(),
+ f = slidersRange / currentMedia.duration,
+ tangleStart = $(".tangle-start"),
+ tangleEnd = $(".tangle-end"),
+ tangleDuration = $(".tangle-duration"),
+ k = 100 / currentMedia.duration,
+ p = k * (start + end) / 2;
+ sliceSlider.slider( "values", [ f * start, f * end ] );
+ tangleStart.text(start.toString(tangleStart.hasClass("active"))).attr("data-milliseconds",start.milliseconds);
+ tangleEnd.text(end.toString(tangleEnd.hasClass("active"))).attr("data-milliseconds",end.milliseconds);
+ tangleDuration.text(dur.toString(tangleDuration.hasClass("active"))).attr("data-milliseconds",dur.milliseconds);
+ $(".segmentation .pointer").css("left", p + "%");
+ $(".media-current-section").css({
+ left: (k * start) + "%",
+ width: (k * dur) + "%"
+ });
+ var messages = [],
+ critical = false,
+ warning = false;
+ _(segmentcritical).each(function(sc) {
+ if (!sc.validate(currentSegment)) {
+ critical = true;
+ messages.push(sc.message);
+ }
+ });
+ _(segmentwarning).each(function(sc) {
+ if (!sc.validate(currentSegment)) {
+ warning = true;
+ messages.push(sc.message);
+ }
+ });
+ currentSegment.status = critical ? "critical" : (warning ? "warning" : "valid");
+ if (!messages.length) {
+ messages.push("This segment is valid!")
+ }
+ currentSegment.status_messages = _(messages).map(IriSP.translate);
+
+ $(".segmentation .validate").removeClass("critical warning valid").addClass(currentSegment.status);
+ $(".segmentation .validate-tooltip").html("<ul><li>" + currentSegment.status_messages.join("</li><li>")+"</li></ul>");
+ }
+ }
+
+ var mediasegmentscache = {};
+
+ function setMedia(media) {
+ if (currentMedia) {
+ currentMedia.pause();
+ }
+ currentMedia = media;
+ project.trigger("set-current", media);
+ if (currentMedia.elementType == "media") {
+ showSegmentation();
+ $(".tab-media-title").text(currentMedia.title);
+
+ addMode = !(currentSegment && mashup.hasAnnotation(currentSegment));
+
+ if (!currentSegment) {
+ currentSegment = new IriSP.Model.Annotation(false, project);
+ currentSegment.setMedia(currentMedia.id);
+ currentSegment.setBegin(currentMedia.getCurrentTime());
+ currentSegment.setEnd(Math.min(currentMedia.getCurrentTime() + 180000, currentMedia.duration));
+ currentSegment.title = IriSP.translate("Untitled segment");
+ currentSegment.color = currentMedia.color;
+ currentSegment.thumbnail = currentMedia.thumbnail;
+ currentSegment.created = new Date();
+ currentSegment.keywords = [];
+ currentSegment.description = "";
+ currentSegment.on("change-begin", function() {
+ if (currentMedia && currentSegment === this) {
+ currentMedia.setCurrentTime(this.begin);
+ updateSegmentUI();
+ }
+ });
+ currentSegment.on("change-end", function() {
+ if (currentMedia && currentSegment === this) {
+ currentMedia.setCurrentTime(this.end);
+ updateSegmentUI();
+ }
+ });
+ }
+ if (currentMedia.loaded) {
+ currentMedia.setCurrentTime(currentSegment.begin);
+ }
+ $(".add-segment").val(IriSP.translate(addMode ? "Add segment to hashcut" : "Save segment"));
+ $(".create-or-edit").text(IriSP.translate(addMode ? "Create new segment" : "Edit existing segment"));
+ media.show();
+ $("#segment-title").val(currentSegment.title);
+ $("#segment-description").val(currentSegment.description);
+ var segment_tags = $("#segment-tags");
+ segment_tags.tagit("option","onTagRemoved",function(){});
+ segment_tags.tagit("option","onTagAdded",function(){});
+ segment_tags.tagit("removeAll");
+ _(currentSegment.keywords).each(function(tag) {
+ segment_tags.tagit("createTag",tag);
+ });
+ segment_tags.tagit("option","onTagRemoved",updateSegmentTags);
+ segment_tags.tagit("option","onTagAdded",updateSegmentTags);
+ updateSegmentUI();
+ var relatedSegments = mashup.segments.filter(function(_s) {
+ return _s.getMedia() === currentMedia && _s.annotation !== currentSegment;
+ });
+ if (relatedSegments.length) {
+ $(".self-media-segments").show();
+ } else {
+ $(".self-media-segments").hide();
+ }
+ $(".self-media-segments .media-segments-list").html(mediaSegmentList(_(relatedSegments).pluck("annotation")));
+ showOtherSegments();
+ project.trigger("mouseout-annotation");
+ }
+ if (currentMedia.elementType === "mashup") {
+ showPreview();
+ }
+ }
+
+ function mediaSegmentList(_annotations) {
+ var html = '',
+ k = $(".Ldt-Slider").width() / currentMedia.duration,
+ lines = [];
+ _(_annotations).each(function(_a, i) {
+ var pos = k * (_a.begin + _a.end) / 2,
+ corrpos = Math.max(145, Math.min(305, pos)),
+ line = IriSP._(lines).find(function(line) {
+ return !IriSP._(line.annotations).find(function(ann) {
+ return ann.begin < _a.end && ann.end > _a.begin
+ });
+ });
+ if (!line) {
+ line = { index: lines.length, annotations: []};
+ lines.push(line);
+ }
+ line.annotations.push(_a);
+ vizdata = {
+ annotation : _a,
+ popleft : corrpos,
+ left : k * _a.begin,
+ width : k * _a.getDuration(),
+ height: 8,
+ top: 8 * line.index,
+ pointerpos : (pos - corrpos),
+ color: IriSP.vizcolors[i % IriSP.vizcolors.length]
+ }
+ html += mediasegmenttemplate(vizdata);
+ });
+ return mediasegmentlisttemplate({
+ height: 8 * lines.length,
+ left: k * currentSegment.begin,
+ width: k * currentSegment.getDuration(),
+ segments: html
+ });
+ }
+
+ /* Show Related Segments */
+
+ function showOtherSegments() {
+ var annotations = mediasegmentscache[currentMedia.id];
+ $(".other-media-segments .media-segments-list").html(mediaSegmentList(annotations));
+ if (annotations && annotations.length) {
+ $(".other-media-segments").show();
+ }
+ else {
+ $(".other-media-segments").hide();
+ }
+ }
+ /* Set In, Out */
+
+ $(".Ldt-Ctrl-SetIn").click(function() {
+ if (currentMedia && currentSegment) {
+ currentSegment.setBegin(currentMedia.getCurrentTime());
+ }
+ });
+ $(".Ldt-Ctrl-SetOut").click(function() {
+ if (currentMedia && currentSegment) {
+ currentSegment.setEnd(currentMedia.getCurrentTime());
+ }
+ });
+
+ /* Segment Form interaction */
+
+ $("#segment-title").on("keyup change input paste", function() {
+ if (currentMedia && currentSegment) {
+ currentSegment.title = $(this).val();
+ updateSegmentUI();
+ mashup.trigger("change");
+ }
+ });
+ $("#segment-title").on("focus click", function() {
+ if ($(this).val() === IriSP.translate("Untitled segment")) {
+ $(this).val("");
+ }
+ });
+ $("#segment-description").on("keyup change input paste", function() {
+ if (currentMedia && currentSegment) {
+ currentSegment.description = $(this).val();
+ mashup.trigger("change");
+ }
+ });
+ $("#segment-form").submit(function() {
+ if (addMode) {
+ mashup.addAnnotation(currentSegment);
+ currentSegment = undefined;
+ setMedia(currentMedia);
+ } else {
+ mashup.trigger("change");
+ var segment = mashup.getAnnotation(currentSegment);
+ currentSegment = undefined;
+ setMedia(mashup);
+ if (segment) {
+ mashup.setCurrentTime(segment.begin);
+ mashup.trigger("enter-annotation",segment);
+ }
+ }
+ return false;
+ });
+
+ $("#segment-tags").tagit();
+
+
+ /* We have to defer this function because the tagit events
+ * are triggered before the data are updated */
+ function updateSegmentTags() {
+ window.setTimeout(function() {
+ if (currentMedia && currentSegment) {
+ currentSegment.keywords = $("#segment-tags").tagit("assignedTags");
+ }
+ }, 0);
+ }
+
+ /* Click on media items */
+
+ $(".col-left").on("click", ".item-video", function() {
+ currentSegment = undefined;
+ setMedia(project.getElement($(this).attr("data-media-id")));
+ });
+
+ /* Click on Tabs */
+
+ function showSegmentation() {
+ $(".col-middle").removeClass("empty-mode pvw-mode").addClass("segment-mode");
+ return false;
+ }
+ function showPreview() {
+ $(".col-middle").removeClass("empty-mode segment-mode").addClass("pvw-mode");
+ return false;
+ }
+ function showEmpty() {
+ $("video").hide();
+ $(".col-middle").removeClass("pvw-mode segment-mode").addClass("empty-mode");
+ return false;
+ }
+
+ $(".tab-pvw").click(function() {
+ if (mashup.segments.length) {
+ setMedia(mashup);
+ }
+ });
+
+ /* Click on segments */
+
+ function reorganizeMashup() {
+ var ids = $(".organize-segments .item-video").map(function(){return $(this).attr("data-segment-id")});
+ mashup.setAnnotationsById(ids);
+ }
+
+ project.on("mouseover-annotation", function(annotation) {
+ var mediaid = annotation.getMedia().id;
+ $(".media").removeClass("active");
+ $(".media[data-media-id='" + mediaid + "']").addClass("active");
+ });
+
+ project.on("mouseout-annotation", function() {
+ $(".media").removeClass("active");
+ var mediaid = undefined;
+ if (currentMedia && currentMedia.elementType === "media") {
+ mediaid = currentMedia.id;
+ if (currentSegment) {
+ $(".annotation").removeClass("active");
+ $(".annotation[data-segment-id='" + currentSegment.id + "']").addClass("active");
+ }
+ }
+ if (currentMedia === mashup && mashup.currentMedia) {
+ mediaid = mashup.currentMedia.id
+ }
+ $(".media[data-media-id='" + mediaid + "']").addClass("active");
+ });
+
+ $(".organize-segments")
+ .sortable({
+ stop : reorganizeMashup
+ })
+ .on("mouseover", ".item-video", function() {
+ project.trigger("mouseover-annotation", project.getElement($(this).attr("data-segment-id")));
+ })
+ .on("mouseout", ".item-video", function() {
+ project.trigger("mouseout-annotation");
+ })
+ .on("click", ".item-video", function() {
+ project.trigger("click-annotation", project.getElement($(this).attr("data-segment-id")));
+ })
+ .on("click", ".edit", function(e) {
+ var currentItem = $(this).parents(".item-video"),
+ media = project.getElement(currentItem.attr("data-media-id")),
+ segment = project.getElement(currentItem.attr("data-segment-id"));
+ currentSegment = segment;
+ setMedia(media);
+ return false;
+ })
+ .on("click", ".top", function(e){
+ var currentItem = $(this).parents(".item-video");
+ currentItem.insertBefore(currentItem.prev());
+ reorganizeMashup();
+ return false;
+ })
+ .on("click", ".bottom", function(e){
+ var currentItem = $(this).parents(".item-video");
+ currentItem.insertAfter(currentItem.next());
+ reorganizeMashup();
+ return false;
+ })
+ .on("click", ".delete", function(e){
+ var id = $(this).parents(".item-video").attr("data-segment-id");
+ mashup.removeAnnotationById(id);
+ if (!mashup.segments.length) {
+ showEmpty();
+ }
+ return false;
+ });
+
+ /* Tangles */
+ var tangleMsPerPixel = 100,
+ activeTangle,
+ tangleStartX,
+ tangleStartVal,
+ tangleHasMoved;
+
+ $(".time-tangle").mousedown(function(evt) {
+ activeTangle = $(this);
+ activeTangle.addClass("active");
+ tangleStartVal = +activeTangle.attr("data-milliseconds");
+ tangleStartX = evt.pageX;
+ tangleHasMoved = false;
+ $(this).siblings(".time-tangle").addClass("deactivate");
+ return false;
+ });
+ $(document)
+ .mousemove(function(evt) {
+ if (activeTangle) {
+ tangleHasMoved = true;
+ var newval = new IriSP.Model.Time(tangleMsPerPixel * (evt.pageX - tangleStartX) + tangleStartVal);
+ activeTangle.trigger("valuechange", newval);
+ return false;
+ }
+ })
+ .mouseup(function() {
+ if (activeTangle) {
+ activeTangle.text(activeTangle.text().replace(/\.\d+$/,''));
+ $(".time-tangle").removeClass("active deactivate");
+ activeTangle = undefined;
+ }
+ });
+
+ $(".tangle-start")
+ .mouseup(function(evt) {
+ if (!tangleHasMoved && currentMedia && currentSegment) {
+ currentMedia.setCurrentTime(currentSegment.begin);
+ }
+ })
+ .on("valuechange", function(evt, val) {
+ if (currentMedia && currentSegment) {
+ currentSegment.setBegin(val);
+ }
+ });
+ $(".tangle-end")
+ .mouseup(function(evt) {
+ if (!tangleHasMoved && currentMedia && currentSegment) {
+ currentMedia.setCurrentTime(currentSegment.end);
+ }
+ })
+ .on("valuechange", function(evt, val) {
+ if (currentMedia && currentSegment) {
+ currentSegment.setEnd(val);
+ }
+ });
+ $(".tangle-duration").on("valuechange", function(evt, val) {
+ if (currentMedia && currentSegment) {
+ currentSegment.setDuration(val);
+ }
+ });
+
+ /* Click on current segment in Preview */
+
+ $(".mashup-description .edit").click(function() {
+ if (mashup.currentAnnotation) {
+ currentSegment = mashup.currentAnnotation.annotation;
+ setMedia(mashup.currentAnnotation.getMedia());
+ }
+ return false;
+ });
+
+ /* Handling related segments */
+
+ function cloneSegment(sid) {
+ var s = directory.getElement(sid) || apidirectory.getElement(sid),
+ media = directory.getElement(s.getMedia().id);
+
+ currentSegment = new IriSP.Model.Annotation(false, project);
+ currentSegment.setMedia(media.id);
+ currentSegment.setBegin(s.begin);
+ currentSegment.setEnd(s.end);
+ currentSegment.title = IriSP.translate("Copy of ") + s.title;
+ currentSegment.description = s.description;
+ currentSegment.keywords = s.keywords;
+ currentSegment.color = media.color;
+ currentSegment.thumbnail = media.thumbnail;
+ currentSegment.created = new Date();
+ currentSegment.on("change-begin", function() {
+ if (currentMedia && currentSegment === this) {
+ currentMedia.setCurrentTime(this.begin);
+ updateSegmentUI();
+ }
+ });
+ currentSegment.on("change-end", function() {
+ if (currentMedia && currentSegment === this) {
+ currentMedia.setCurrentTime(this.end);
+ updateSegmentUI();
+ }
+ });
+ setMedia(media);
+ }
+
+ $(".media-segments-list").on("mouseover", ".media-segment", function() {
+ $(this).find(".media-segment-popin").show();
+ }).on("mouseout", ".media-segment", function() {
+ $(this).find(".media-segment-popin").hide();
+ }).on("click", ".reprendre-segment", function() {
+ cloneSegment($(this).attr("data-segment-id"));
+ return false;
+ }).on("click", ".media-segment-section", function() {
+ var sid = $(this).attr("data-segment-id"),
+ s = directory.getElement(sid) || apidirectory.getElement(sid);
+ if (s.media.id === currentMedia.id) {
+ currentMedia.setCurrentTime(s.begin);
+ }
+ });
+
+ $(".col-left").on("mouseover", ".media-segment", function() {
+ $(this).find(".media-found-popin").show();
+ }).on("mouseout", ".media-segment", function() {
+ $(this).find(".media-found-popin").hide();
+ }).on("click", ".clone-segment", function() {
+ cloneSegment($(this).attr("data-segment-id"));
+ return false;
+ });
+ /* Changing Hashcut Title and description */
+
+ mashup.title = IriSP.translate("Untitled Hashcut");
+ $(".title-video-wrap a").text(mashup.title);
+ $("#hashcut-title").val(mashup.title);
+
+ $("#hashcut-title").on("keyup change input paste", function() {
+ mashup.title = $(this).val();
+ $(".title-video-wrap a").text(mashup.title);
+ mashup.trigger("change");
+ });
+ $("#hashcut-title").on("focus click", function() {
+ if ($(this).val() === IriSP.translate("Untitled Hashcut")) {
+ $(this).val("");
+ }
+ });
+
+ $("#hashcut-description").on("keyup change input paste", function() {
+ mashup.description = $(this).val();
+ mashup.trigger("change");
+ });
+
+ $("#hashcut-form").submit(function() {
+ $(".update-title").hide();
+ return false;
+ })
+
+ /* Publication */
+
+ function onLeave() {
+ return IriSP.translate("You haven't published your hashcut yet.\nIf you leave this page, it will be lost");
+ }
+
+ $(window).on("beforeunload", onLeave);
+
+ $(".publier-button").click(function() {
+ if ($(this).hasClass("disable")) {
+ alert(IriSP.translate("The mashup can't be published because:")+"\n\n"+mashupstatus);
+ return false;
+ }
+ var postproject = directory.newLocalSource(),
+ medias = mashup.getMedias()
+ annotations = mashup.getOriginalAnnotations();
+ postproject.addList("annotationType");
+ postproject.addList("tag");
+ medias.forEach(function(_m) {
+ var anntype = new IriSP.Model.AnnotationType(false, postproject);
+ anntype.title = "Segments from " + _m.title;
+ anntype.media = _m;
+ postproject.getAnnotationTypes().push(anntype);
+ });
+ annotations.forEach(function(_a) {
+ _a.setAnnotationType(
+ postproject.getAnnotationTypes().filter(
+ function(_at) { return _at.media === _a.getMedia() }
+ )[0].id);
+ var tagids = [];
+ _(_a.keywords).each(function(keyword) {
+ var tags = postproject.getTags().searchByTitle(keyword);
+ if (tags.length) {
+ tagids.push(tags[0].id);
+ } else {
+ var tag = new IriSP.Model.Tag(false, postproject);
+ tag.title = tag.description = keyword;
+ postproject.getTags().push(tag);
+ tagids.push(tag.id);
+ }
+ });
+ _a.setTags(tagids);
+ });
+ postproject.addList("annotation",annotations);
+ postproject.addList("media",medias);
+ postproject.addList("mashup",[mashup]);
+ postproject.creator = "admin";
+ postproject.created = new Date();
+ postproject.modified = new Date();
+ postproject.title = mashup.title;
+ postproject.description = mashup.description;
+ $.ajax({
+ type: "POST",
+ url: IriSP.endpoints.project,
+ data: IriSP.serializers.ldt.serialize(postproject),
+ contentType: "application/cinelab",
+// headers: {"X-CSRFToken": "{{csrf_token}}"},
+ success: function(data, status, request){
+ var location = request.getResponseHeader("Location"),
+ projid = location.match(/([^/]+)\/?$/)[1],
+ destination = IriSP.endpoints.hashcut_page + projid;
+ $(window).off("beforeunload", onLeave);
+ document.location.href = destination;
+ },
+ error: function(jqXHR, textStatus, errorThrown){
+ console.log(arguments);
+ alert(IriSP.translate("Server error\nYour hashcut couldn't be published"));
+ }
+ });
+ //TODO: ADD WAITING SCREEN
+
+ return false;
+ });
+
+ mashup.trigger("change");
+}
+
+/* END editor.js */
+IriSP.mashupplayer = function(options) {
+
+ var directory = new IriSP.Model.Directory(),
+ project = directory.remoteSource({
+ url: IriSP.endpoints.ldt + options.id,
+ serializer: IriSP.serializers.ldt
+ }),
+ apidirectory = new IriSP.Model.Directory(),
+ mashup,
+ mediatemplate = _.template('<li class="item-video media" data-media-id="<%= media.id %>">'
+ + '<a href="<%= IriSP.endpoints.media_page + media.id %>"><img class="thumbnail" alt="<%= media.title %>" src="<%= media.thumbnail %>"></a><div class="video-info">'
+ + '<h3 class="title-video"><a href="<%= IriSP.endpoints.media_page + media.id %>"><%= media.title %></a></h3><p class="description"><%= media.description %></p>'
+ + '<p class="time-length">Durée : <span><%= media.duration.toString() %></span></p><div class="frise">'
+ + '<div class="frise-overflow"><div class="frise-segments"><%= segments %></div></div></div></div></li>');
+ segmenttemplate = _.template('<div style="background-color:<%= annotation.color %>; left:<%= left %>%; width: <%= width %>%;"'
+ + ' class="frise-segment annotation" data-segment-id="<%= annotation.id %>" title="<%= annotation.title %>"></div>')
+
+ project.onLoad(function() {
+ mashup = project.getMashups()[0];
+ IriSP.mashupcore(project, mashup);
+ project.trigger("set-current",mashup);
+
+ $(".info-title a").text(mashup.title);
+ $(".title-video-wrap .title-video").text(mashup.title);
+ $(".info-duration td").text(mashup.duration.toString());
+ $(".info-author a").text(mashup.creator);
+ $(".info-description td").text(mashup.description);
+
+ mashup.getMedias().forEach(function(media) {
+ apidirectory.remoteSource({
+ url: IriSP.endpoints.content + media.id,
+ serializer: IriSP.serializers.content
+ }).onLoad(function() {
+ var m = apidirectory.getElement(media.id);
+ if (m) {
+ media.thumbnail = m.thumbnail;
+ }
+ var segments = mashup.segments.filter(function(segment) {
+ return segment.getMedia() === media;
+ });
+ var segmentshtml = '', k = media.duration ? (100 / media.duration) : 0;
+ segments.forEach(function(segment) {
+ var vizdata = {
+ annotation: segment.annotation,
+ left: k * segment.annotation.begin,
+ width: k * segment.annotation.getDuration()
+ }
+ segmentshtml += segmenttemplate(vizdata);
+ });
+ var mediadata = {
+ media: media,
+ segments: segmentshtml
+ }
+
+ $(".list-video").append(mediatemplate(mediadata));
+ });
+ });
+
+
+ project.on("mouseover-annotation", function(annotation) {
+ var mediaid = annotation.getMedia().id;
+ $(".media").removeClass("active");
+ $(".media[data-media-id='" + mediaid + "']").addClass("active");
+ });
+
+ project.on("mouseout-annotation", function(annotation) {
+ $(".media").removeClass("active");
+ var mediaid = mashup.currentMedia.id;
+ $(".media[data-media-id='" + mediaid + "']").addClass("active");
+ });
+
+ $(".list-video")
+ .on("mouseover", ".frise-segment", function() {
+ project.trigger("mouseover-annotation", project.getElement($(this).attr("data-segment-id")));
+ })
+ .on("click", ".frise-segment", function() {
+ project.trigger("click-annotation", project.getElement($(this).attr("data-segment-id")));
+ })
+ .on("mouseover", ".item-video", function() {
+ $(".media").removeClass("active");
+ })
+ .on("mouseout", ".item-video", function() {
+ project.trigger("mouseout-annotation");
+ })
+
+
+ });
+}
+
+/* END mashupplayer.js */
+IriSP.mediaplayer = function(options) {
+
+ var directory = new IriSP.Model.Directory(),
+ content = directory.remoteSource({
+ url: IriSP.endpoints.content + options.id,
+ serializer: IriSP.serializers.content
+ }),
+ apidirectory = new IriSP.Model.Directory(),
+ segmenttemplate = _.template(
+ '<div class="media-segment" data-mashup-id="<%= annotation.project_id %>">'
+ + '<div class="media-segment-section" style="left:<%= left %>px; width:<%= width %>px; background:<%= color %>; top: <%= top %>px;" data-segment-id="<%= annotation.id %>"></div>'
+ + '<div class="popin media-segment-popin" style="left:<%= popleft %>px; top: <%= 5+top %>px;"><img style="left:<%= pointerpos %>px;" class="pointer" src="img/popin-triangle.png" alt="" /><div class="popin-content">'
+ + '<h3><%= annotation.title %></h3>'
+ + '<p><%= IriSP.translate("From:") %> <span><%= annotation.begin.toString() %></span> <%= IriSP.translate("to:") %> <span><%= annotation.end.toString() %></span> (<%= IriSP.translate("duration:") %> <span><%= annotation.getDuration().toString() %></span>)</p>'
+ + '<p class="mashup-link"><%= IriSP.translate("From hashcut:") %> <a href="<%= IriSP.endpoints.hashcut_page + annotation.project_id %>"></a></p>'
+ + '</div></div></div>'
+ ),
+ segmentlisttemplate = _.template(
+ '<div class="media-segment-list" style="height: <%= height %>px"><div class="media-segment-list-inner"></div><%= segments %><div class="frise-position"></div></div>'
+ ),
+ projtemplate = _.template(
+ '<li class="item-video mashup" data-mashup-id="<%= ldt_id %>">'
+ + '<a href="<%= IriSP.endpoints.hashcut_page + ldt_id %>"><img class="thumbnail" alt="<%= title %>" src="<%= image %>"></a><div class="video-info">'
+ + '<h3 class="title-video"><a href="<%= IriSP.endpoints.hashcut_page + ldt_id %>"><%= title %></a></h3><p class="description"><%= description %></p>'
+ + '</p></div></li>'
+ ),
+ media;
+
+ function mediaSegmentList(_annotations) {
+ var html = '',
+ k = $(".Ldt-Slider").width() / media.duration,
+ lines = [];
+ _(_annotations).each(function(_a, i) {
+ var pos = k * (_a.begin + _a.end) / 2,
+ corrpos = Math.max(106, Math.min(516, pos)),
+ line = IriSP._(lines).find(function(line) {
+ return !IriSP._(line.annotations).find(function(ann) {
+ return ann.begin < _a.end && ann.end > _a.begin
+ });
+ });
+ if (!line) {
+ line = { index: lines.length, annotations: []};
+ lines.push(line);
+ }
+ line.annotations.push(_a);
+ vizdata = {
+ annotation : _a,
+ popleft : corrpos,
+ left : k * _a.begin,
+ width : k * _a.getDuration(),
+ height: 8,
+ top: 8 * line.index,
+ pointerpos : (pos - corrpos),
+ color: IriSP.vizcolors[i % IriSP.vizcolors.length]
+ }
+ html += segmenttemplate(vizdata);
+ });
+ return segmentlisttemplate({
+ height: 8 * lines.length,
+ segments: html
+ });
+ }
+
+ content.onLoad(function() {
+
+ IriSP.mashupcore(content, new IriSP.Model.Mashup(false, content));
+
+ media = content.getMedias()[0];
+
+ apidirectory.remoteSource({
+ url: IriSP.endpoints.segment,
+ url_params: {
+ iri_id: options.id,
+ limit: 0
+ },
+ serializer: IriSP.serializers.segmentapi
+ }).onLoad(function() {
+ var medias = this.getMedias(),
+ annotations = this.getAnnotations(),
+ projlist = {};
+ $(".media-segments").html(mediaSegmentList(annotations));
+ annotations.forEach(function(a) {
+ projlist[a.project_id] = 1 + (projlist[a.project_id] || 0);
+ });
+ var projkeys = _(projlist)
+ .chain()
+ .keys()
+ .sortBy(function(v) {
+ return - projlist[v];
+ })
+ .first(8)
+ .value();
+ $.ajax({
+ url: IriSP.endpoints.project,
+ dataType: "json",
+ data: {
+ format: "json",
+ ldt_id__in: projkeys
+ },
+ traditional: true,
+ success: function(data) {
+ var proj = _(data.objects)
+ .filter(function(p) {
+ return /<inst/gm.test(p.ldt);
+ });
+ _(proj).each(function(p) {
+ $(".media-segment[data-mashup-id='" + p.ldt_id + "']").each(function() {
+ $(this)
+ .find(".mashup-link").show()
+ .find("a").text(p.title);
+ });
+ });
+ var html = _(proj)
+ .chain()
+ .sortBy(function(p) {
+ return - projlist[p.ldt_id];
+ })
+ .map(projtemplate)
+ .value()
+ .join("");
+ $(".list-video").html(html);
+ }
+ });
+ });
+
+ content.trigger("set-current", media);
+
+ $(".info-title a").text(media.title);
+ $(".title-video-wrap .title-video").text(media.title);
+ $(".info-duration td").text(media.duration.toString());
+ $(".info-description td").text(media.description);
+ $(".info-tags td").text(media.keywords);
+
+ });
+
+ $(".media-segments").on("mouseover", ".media-segment", function() {
+ var el = $(this);
+ el.find(".media-segment-popin").show();
+ var pid = el.attr("data-mashup-id");
+ $(".item-video[data-mashup-id='" + pid + "']").addClass("active");
+ }).on("mouseout", ".media-segment", function() {
+ $(this).find(".media-segment-popin").hide();
+ $(".item-video").removeClass("active");
+ }).on("click", ".media-segment-section", function() {
+ var sid = $(this).attr("data-segment-id"),
+ s = apidirectory.getElement(sid);
+ media.setCurrentTime(s.begin);
+ });
+
+ $(".list-video").on("mouseover", ".item-video", function() {
+ var pid = $(this).attr("data-mashup-id");
+ $(".media-segment[data-mashup-id='" + pid + "']").addClass("active");
+ }).on("mouseout", ".item-video", function() {
+ $(".media-segment").removeClass("active");
+ });
+}
+
+/* END mediaplayer.js */
+
+IriSP.social = function(sel, url) {
+
+ var sel = sel || $(".Ldt-Social"),
+ url = url || document.location.href,
+ text = sel.find("title").text(),
+ clipId = IriSP.Model.getUID(),
+ clip;
+
+ sel.find(".Ldt-Social-CopyBtn").attr("id", this.clipId);
+
+ sel.find(".Ldt-Social-Url").click(function() {
+ var _pop = sel.find(".Ldt-Social-UrlPop");
+ _pop.toggle();
+ if (_pop.is(":visible")) {
+ if (typeof clip == "undefined") {
+ clip = new ZeroClipboard.Client();
+ clip.setHandCursor( true );
+ clip.glue(clipId);
+
+ clip.addEventListener( 'onMouseUp', function() {
+ _pop.hide();
+ clip.hide();
+ });
+ }
+ clip.show();
+ clip.setText( url );
+ sel.find(".Ldt-Social-Input").val(url).focus();
+ } else {
+ clip.hide();
+ }
+ return false;
+ });
+ sel.find(".Ldt-Social-Input").focus(function() {
+ this.select();
+ });
+ sel.find(".Ldt-Social-Ext").click(function() {
+ window.open(
+ sel.find(this).attr("href"),
+ "_blank",
+ "height=300,width=450,left=100,top=100,toolbar=0,menubar=0,status=0,location=0");
+ return false;
+ });
+
+ sel.find(".Ldt-Social-Fb").attr("href", "http://www.facebook.com/share.php?" + $.param({ u: url, t: text }));
+ sel.find(".Ldt-Social-Twitter").attr("href", "https://twitter.com/intent/tweet?" + $.param({ url: url, text: text }));
+ sel.find(".Ldt-Social-Gplus").attr("href", "https://plus.google.com/share?" + $.param({ url: url, title: text }));
+ sel.find(".Ldt-Social-Mail").attr("href", "mailto:?" + $.param({ subject: text, body: text + ": " + url }));
+}
+
+/* END social.js */