IriSP.hc_messages = {
Duration_ : "Durée :",
duration_ : "durée :",
edit_segment: "Éditer le segment",
segment_down: "Descendre le segment",
segment_up: "Remonter le segment",
delete_segment: "Supprimer le segment",
clone_segment: "Cloner le segment",
From_: "De :",
to_: "à :",
segment_title_placeholder: "Segment sans titre",
mashup_title_placeholder: "Hashcut sans titre"
}
IriSP.editor = function(options) {
/* Load Media List */
var directory = new IriSP.Model.Directory(),
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 %>"><img src="<%= thumbnail %>" alt="<%= title %>" />'
+ '<span class="video-info"><span class="title-video"><%= title %></span><span class="author"><%= description %></span>'
+ '<span class="time-length"><%= IriSP.hc_messages.Duration_ %> <span><%= duration.toString() %></span></span></span></li>'),
segmenttemplate = _.template('<li class="item-video annotation" data-segment-id="<%= annotation.id %>" data-media-id="<%= annotation.getMedia().id %>">'
+ '<img src="<%= annotation.getMedia().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><span class="video-info"><span class="title-video"><%= annotation.getMedia().title %></span>'
+ '<span class="subtitle"><%= annotation.title %></span><span class="duration"><%= annotation.begin.toString() %> - <%= annotation.end.toString() %> (<%= annotation.getDuration().toString() %>)</span>'
+ '<ul class="tools"><li><a class="edit" href="#" title="<%= IriSP.hc_messages.edit_segment %>"></a></li><li><a class="bottom" href="#" title="<%= IriSP.hc_messages.segment_down %>"></a></li>'
+ '<li><a class="top" href="#" title="<%= IriSP.hc_messages.segment_up %>"></a></li><li><a class="delete" href="#" title="<%= IriSP.hc_messages.delete_segment %>"></a></li></ul></span></li>'),
mediasegmenttemplate = _.template('<div class="media-segments-list"><div class="media-segment">'
+ '<div class="media-section media-segment-section" style="left:<%= left %>px; width:<%= width %>px; background:<%= annotation.color %>"></div>'
+ '<div class="media-section media-current-section" style="left:<%= currentleft %>px; width:<%= currentwidth %>px;"><div class="media-current-section-inner"></div></div>'
+ '<div class="popin media-segment-popin" style="left:<%= popleft %>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.hc_messages.clone_segment %></a>'
+ '<p><%= IriSP.hc_messages.From_ %> <span><%= annotation.begin.toString() %></span> <%= IriSP.hc_messages.to_ %> <span><%= annotation.end.toString() %></span> (<%= IriSP.hc_messages.duration_ %> <span><%= annotation.getDuration().toString() %></span>)</p>'
+ '</div></div></div></div>'),
addMode, currentMedia, currentSegment;
IriSP.mashupcore(project, mashup);
/* Validation of segments and mashup */
var segmentcritical = [
{
validate: function(_s) {
return (_s.getDuration() >= 1000);
},
message: "Le segment doit durer au moins une seconde"
},
{
validate: function(_s) {
return (_s.getDuration() < 180000);
},
message: "Le segment doit durer moins de trois minutes"
},
{
validate: function(_s) {
return (!!_s.title && _s.title !== IriSP.hc_messages.segment_title_placeholder);
},
message: "Le segment doit avoir un titre"
}
];
var segmentwarning = [
{
validate: function(_s) {
return (!!_s.description);
},
message: "Il est recommandé de donner une description au segment"
},
{
validate: function(_s) {
return (!!_s.keywords.length);
},
message: "Il est recommandé de tagguer le segment"
}
];
var mashupcritical = [
{
validate: function(_m) {
return _m.segments.length > 2;
},
message: "Un hashcut doit être composé d'au moins trois segments"
},
{
validate: function(_m) {
return (!!_m.title && _m.title !== IriSP.hc_messages.mashup_title_placeholder);
},
message: "Un titre doit être donné au hashcut"
}
];
var mashupwarning = [
{
validate: function(_m) {
return !!_m.description
},
message: "Il est recommandé de donner une description au hashcut"
}
];
/* 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);
});
/* 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),
title = $(this).find(".title-video"),
titletext = title.text();
if (val && find.test(titletext)) {
title.html(titletext.replace(replace, '<span style="background: yellow;">$1</span>'));
li.show();
} else {
title.text(titletext);
if (val) {
li.hide();
} else {
li.show();
}
}
})
});
/* 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("Certains segments ne sont pas valides");
}
_(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("Le hashcut est valide !");
}
$(".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("Le segment est valide !")
}
currentSegment.status_messages = messages;
$(".segmentation .validate").removeClass("critical warning valid").addClass(currentSegment.status);
$(".segmentation .validate-tooltip").html("<ul><li>" + currentSegment.status_messages.join("</li><li>")+"</li></ul>");
}
}
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(0);
currentSegment.setEnd(currentMedia.duration);
currentSegment.title = IriSP.hc_messages.segment_title_placeholder;
currentSegment.color = currentMedia.color;
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(addMode ? "Ajouter au Hashcut" : "Sauvegarder");
$(".create-or-edit").text(addMode ? "Créer un nouveau segment" : "Modifier le 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;
});
var html = "";
if (relatedSegments.length) {
var k = $(".Ldt-Slider").width() / currentSegment.getMedia().duration,
currentleft = k * currentSegment.begin,
currentwidth = k * currentSegment.getDuration();
relatedSegments.forEach(function(_s) {
var pos = k * (_s.annotation.begin + _s.annotation.end) / 2,
corrpos = Math.max(145, Math.min(305, pos));
vizdata = {
annotation : _s.annotation,
currentleft : currentleft,
currentwidth : currentwidth,
popleft : corrpos,
left : k * _s.annotation.begin,
width : k * _s.annotation.getDuration(),
pointerpos : (pos - corrpos)
}
html += mediasegmenttemplate(vizdata);
});
$(".self-media-segments").show();
} else {
$(".self-media-segments").hide();
}
//TODO: Show Related Segments from http://capsicum/pf/ldtplatform/api/ldt/1.0/segments/bytimecode/f72aa2f4-29bb-11e2-a193-08002791f1b7/0/674000?format=json
}
$(".self-media-segments .media-segments-list").html(html);
if (currentMedia.elementType === "mashup") {
showPreview();
}
}
/* Segment Form interaction */
$("#segment-title").on("keyup change input paste", function() {
if (currentMedia && currentSegment) {
currentSegment.title = $(this).val();
updateSegmentUI();
mashup.trigger("change");
}
});
$("#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);
} 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(annotation) {
$(".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 (mashupCurrentAnnotation) {
currentSegment = mashupCurrentAnnotation.annotation;
setMedia(mashupCurrentAnnotation.getMedia());
}
});
/* Handling related segments */
$(".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() {
var s = project.getElement($(this).attr("data-segment-id"));
currentSegment.title = s.title;
currentSegment.description = s.description;
$("#segment-title").val(s.title);
$("#segment-description").val(s.description);
currentSegment.setBegin(s.begin);
currentSegment.setEnd(s.end);
return false;
});
/* Changing Hashcut Title and description */
$("#hashcut-tags").tagit({
onTagRemoved: updateSegmentTags,
onTagAdded: updateSegmentTags
});
mashup.title = IriSP.hc_messages.mashup_title_placeholder;
$(".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-description").on("keyup change input paste", function() {
mashup.description = $(this).val();
mashup.trigger("change");
});
function updateMashupTags() {
window.setTimeout(function() {
mashup.keywords = $("#segment-tags").tagit("assignedTags");
}, 0);
}
mashup.trigger("change");
}