--- a/src/spel/__init__.py Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/__init__.py Thu May 15 17:55:50 2014 +0200
@@ -1,4 +1,4 @@
-VERSION = (0, 5, 10, "final", 0)
+VERSION = (0, 5, 11, "final", 0)
VERSION_STR = unicode(".".join(map(lambda i:"%02d" % (i,), VERSION[:2])))
--- a/src/spel/static/spel/css/spel.css Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/static/spel/css/spel.css Thu May 15 17:55:50 2014 +0200
@@ -19,7 +19,7 @@
.width100percent{
width: 100%;
}
-.spel-content > .row > .chapters > .row{
+.filter-row{
margin-bottom: 10px;
}
.toggle-text{
--- a/src/spel/static/spel/js/opera.js Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/static/spel/js/opera.js Thu May 15 17:55:50 2014 +0200
@@ -7,7 +7,7 @@
},
onChange: function(element, checked) {
var filter_enabled = false;
- var chbs = $(".chapters input:checkbox");
+ var chbs = $(".spel-content input:checkbox");
for (var i = chbs.length - 1; i >= 0; i--) {
filter_enabled = filter_enabled || $(chbs[i]).is(":checked");
};
@@ -19,14 +19,6 @@
}
}
});
- // Annotations multiselect management
- $('.annotations .multiselect').multiselect({
- buttonText: function(options, select) {
- return $(select).attr("data-title") + ' (' + options.length + ') <b class="caret"></b>';
- },
- buttonContainer: '<div class="btn-group width100percent" />',
- buttonClass: 'btn btn-default width100percent disabled'
- });
// Data 1
var data1 = [
@@ -74,7 +66,7 @@
var n = data.objects.length;
var data4 = [];
for(var i=0;i<n;i++){
- data4.push({label: o[i].name.substr(20), value: o[i].name.substr(12)});
+ data4.push({label: o[i].name.substr(20), value: o[i].name});
}
$("#mulsel4").multiselect('dataprovider', data4);
$("#mulsel4").multiselect('enable');
@@ -97,11 +89,11 @@
var n = data.objects.length;
var data5 = [];
for(var i=0;i<n;i++){
- data5.push({label: parseInt(o[i].name.substr(12)), value: parseInt(o[i].name.substr(12))});
+ data5.push({label: parseInt(o[i].name.substr(12)), value: o[i].name});
}
// Sort
data5.sort(function(a,b){
- return a.value - b.value;
+ return a.label - b.label;
});
$("#mulsel5").multiselect('dataprovider', data5);
$("#mulsel5").multiselect('enable');
@@ -116,17 +108,17 @@
var n = data.objects.length;
var data6 = [];
for(var i=0;i<n;i++){
- data6.push({label: parseInt(o[i].name.substr(13)), value: parseInt(o[i].name.substr(13))});
+ data6.push({label: parseInt(o[i].name.substr(13)), value: o[i].name});
}
// Sort
data6.sort(function(a,b){
- return a.value - b.value;
+ return a.label - b.label;
});
$("#mulsel6").multiselect('dataprovider', data6);
$("#mulsel6").multiselect('enable');
});
- // Data 6 : Mesure
+ // Data 7 : Mesure
$.ajax({
url: urlOM
})
@@ -135,12 +127,12 @@
var n = data.objects.length;
var data7 = [];
for(var i=0;i<n;i++){
- data7.push({label: o[i].name.substr(14), value: o[i].name.substr(14)});
+ data7.push({label: o[i].name.substr(14), value: o[i].name});
}
// Sort
data7.sort(function(a,b){
- var v1 = parseInt(a.value.split(" ")[0]);
- var v2 = parseInt(b.value.split(" ")[0]);
+ var v1 = parseInt(a.label.split(" ")[0]);
+ var v2 = parseInt(b.label.split(" ")[0]);
if(isNaN(v1) || isNaN(v2)){
return false;
}
@@ -169,20 +161,24 @@
// Search chapters management
$("#btn-filter-chapters").click(function(e){
- if($("#mulsel1").val()==null && $("#mulsel2").val()==null && $("#mulsel3").val()==null){
+ if($("#mulsel1").val()==null && $("#mulsel2").val()==null && $("#mulsel3").val()==null && $("#mulsel4").val()==null && $("#mulsel5").val()==null && $("#mulsel6").val()==null && $("#mulsel7").val()==null){
$(".chapter-results").html("<p>Vous devez sélectionner au moins un filtre</p>");
return false;
}
$(".chapter-results").html("<br/><br/>");
$(".chapter-results").addClass("loader");
$.ajax({
- url: urlChapters,
+ url: urlAnnotations,
data:{
start_date: $('input[name=start_date]').val(),
end_date: $('input[name=end_date]').val(),
annotation_types: ( ($("#mulsel1").val()==null) ? [] : $("#mulsel1").val() ).join(","),
modalites_sceniques: ( ($("#mulsel2").val()==null) ? [] : $("#mulsel2").val() ).join(","),
personnages: ( ($("#mulsel3").val()==null) ? [] : $("#mulsel3").val() ).join(","),
+ type_travail: ( ($("#mulsel4").val()==null) ? [] : $("#mulsel4").val() ).join(","),
+ acte: ( ($("#mulsel5").val()==null) ? [] : $("#mulsel5").val() ).join(","),
+ scene: ( ($("#mulsel6").val()==null) ? [] : $("#mulsel6").val() ).join(","),
+ mesure: ( ($("#mulsel7").val()==null) ? [] : $("#mulsel7").val() ).join(","),
start_text: $("#start-text").val(),
end_text: $("#end-text").val()
}
@@ -204,11 +200,23 @@
$("#mulsel1").multiselect('deselect', $(this).parent().text().trim());
}
else if($(this).parent().hasClass("modscen")){
- $("#mulsel2").multiselect('deselect', "modalites_sceniques: " + $(this).parent().text().trim());
+ $("#mulsel2").multiselect('deselect', "opera_modalites_sceniques: " + $(this).parent().text().trim());
}
else if($(this).parent().hasClass("perso")){
- $("#mulsel3").multiselect('deselect', "personnages: " + $(this).parent().text().trim());
+ $("#mulsel3").multiselect('deselect', "opera_personnages: " + $(this).parent().text().trim());
}
+ else if($(this).parent().hasClass("type-travail")){
+ $("#mulsel4").multiselect('deselect', "opera_type_travail: " + $(this).parent().text().trim());
+ }
+ else if($(this).parent().hasClass("acte")){
+ $("#mulsel5").multiselect('deselect', "opera_acte: " + $(this).parent().text().split(" ")[1].trim());
+ }
+ else if($(this).parent().hasClass("scene")){
+ $("#mulsel6").multiselect('deselect', "opera_scene: " + $(this).parent().text().split(" ")[1].trim());
+ }
+ else if($(this).parent().hasClass("mesure")){
+ $("#mulsel7").multiselect('deselect', "opera_mesure: " + $(this).parent().text().split(" ")[1].trim());
+ }
else if($(this).parent().hasClass("date")){
$('input[name=start_date]').val("");
$('input[name=end_date]').val("");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spel/templates/partial/spel_opera_annotations.html Thu May 15 17:55:50 2014 +0200
@@ -0,0 +1,46 @@
+{% load static %}
+{% load front_tags %}
+{% load spel_tags %}
+<div class="row">
+ <div class="col-md-8">
+ <ul class="list-inline chapter-tag-list">
+ {% if start_date != "" or end_date != "" %}<li class="small searched-tag date">
+ {% if start_date != "" %}{{ start_date }} ≤ {% endif %}date{% if end_date != "" %} ≤ {{ end_date }}{% endif %}
+ <span class="glyphicon glyphicon-remove small"></span></li>
+ {% endif %}
+ {% for t in annot_types %}<li class="small searched-tag type">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% for t in mod_scen %}<li class="small searched-tag modscen">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% for t in perso %}<li class="small searched-tag perso">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% for t in type_travail %}<li class="small searched-tag type-travail">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% for t in acte %}<li class="small searched-tag acte">{{ t|remove_opera }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% for t in scene %}<li class="small searched-tag scene">{{ t|remove_opera }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% for t in mesure %}<li class="small searched-tag mesure">{{ t|remove_opera }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ </ul>
+ <p>{{ segments|length }} segment(s) trouvé(s)</p>
+ </div>
+</div>
+<table class="table table-striped table-condensed tablesorter">
+ <thead>
+ <tr><th>Type</th><th>Titre de la vidéo</th><th>Modalités scéniques</th><th>Personnages</th><th>Travail</th><th>Acte</th><th>Scène</th><th>Mesure</th><th class="popinfo"> </th></tr>
+ </thead>
+ <tbody>
+ {% for s in segments %}
+ <tr class="chapter-data" data-content="{{ s.iri_id }}" data-start="{{ s.start_ts }}" data-end="{{ s.start_ts|add:s.duration }}">
+ <td title="{{ s.cutting_id }}">{{ s.cutting_id|slice:":1"|upper }}</td>
+ <td>{% if annot_chapters %}{{ s.ct }}{% else %}{{ s.content.title }}{% endif %}</td>
+ <td>{{ s.tags|get_tags:"opera_modalites_sceniques"|join:', ' }}</td>
+ <td>{{ s.tags|get_tags:"opera_personnages"|join:', ' }}</td>
+ <td>{{ s.tags|get_tags:"opera_type_travail"|join:', ' }}</td>
+ <td>{{ s.tags|get_tags:"opera_acte"|join:', ' }}</td>
+ <td>{{ s.tags|get_tags:"opera_scene"|join:', ' }}</td>
+ <td>{{ s.tags|get_tags:"opera_mesure"|join:', ' }}</td>
+ <td>
+ <span class="glyphicon glyphicon-info-sign popinfo" data-trigger="hover" data-container="body" data-toggle="popover" data-placement="auto"
+ data-content="<strong>Timecodes:</strong> {{ s.start_ts|str_duration }} - {{ s.start_ts|add:s.duration|str_duration }}"></span>
+ <a class="play-button" href="{% url 'spel_player' %}?g={{ s.iri_id }}&d=opera&f=original_web.mp4#id={{ s.element_id }}" target="_blank"><span class="glyphicon glyphicon-play"></span></a>
+ <input type="checkbox" class="filter-chapter-annot" />
+ </td>
+ </tr>
+ {% endfor %}
+ <tbody>
+</table>
--- a/src/spel/templates/spel_opera.html Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/templates/spel_opera.html Thu May 15 17:55:50 2014 +0200
@@ -13,7 +13,7 @@
{% block spel_content %}
<h3>Page Opéra</h3>
- <div class="row">
+ <div class="row filter-row">
<div class="col-md-4">
<select id="mulsel1" class="multiselect" multiple="multiple" data-title="Types de chapitres"></select>
</div>
@@ -25,7 +25,7 @@
<input type="text" class="input-sm form-control" name="end_date" />
</div>
</div>
- <div class="row">
+ <div class="row filter-row">
<div class="col-md-4">
<select id="mulsel2" class="multiselect" multiple="multiple" data-title="Modalités scéniques" disabled="disabled"></select>
</div>
@@ -36,7 +36,7 @@
<select id="mulsel4" class="multiselect" multiple="multiple" data-title="Type travail" disabled="disabled"></select>
</div>
</div>
- <div class="row">
+ <div class="row filter-row">
<div class="col-md-4">
<select id="mulsel5" class="multiselect" multiple="multiple" data-title="Actes" disabled="disabled"></select>
</div>
@@ -47,9 +47,10 @@
<select id="mulsel7" class="multiselect" multiple="multiple" data-title="Mesures" disabled="disabled"></select>
</div>
</div>
- <div class="row">
- <div class="annotation-results">Résultats d'annotations</div>
+ <div class="row filter-row text-center">
+ <button id="btn-filter-chapters" class="btn btn-success" disabled="disabled">FILTRER</button>
</div>
+ <div class="chapter-results">Résultats d'annotations</div>
{% endblock %}
{% block page_js %}
<script type="text/javascript" src="{% static 'spel/lib/jquery.min.js' %}"></script>
@@ -68,7 +69,7 @@
var urlOS = "{% url 'api_dispatch_list' resource_name='tags' api_name='1.0' %}?format=json&limit=500&name__startswith=opera_scene:&order_by=name";
var urlOM = "{% url 'api_dispatch_list' resource_name='tags' api_name='1.0' %}?format=json&limit=500&name__startswith=opera_mesure&order_by=name";
//var urlChapters = "{% url 'spel_chapters' %}";
- //var urlAnnotations = "{% url 'spel_annotations' %}";
+ var urlAnnotations = "{% url 'spel_opera_annotations' %}";
var csrf_token = "{{csrf_token}}";
$('.input-daterange').datepicker({
format: "yyyy-mm-dd",
--- a/src/spel/templates/spel_theatre.html Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/templates/spel_theatre.html Thu May 15 17:55:50 2014 +0200
@@ -16,7 +16,7 @@
<div class="row">
<div class="col-md-6 chapters">
<h4 class="text-center">CHAPITRES</h4>
- <div class="row">
+ <div class="row filter-row">
<div class="col-md-4">Dates de répétition :</div>
<div class="col-md-7 input-daterange input-group">
<span class="input-group-addon">de</span>
@@ -25,7 +25,7 @@
<input type="text" class="input-sm form-control" name="end_date" />
</div>
</div>
- <div class="row">
+ <div class="row filter-row">
<div class="col-md-4">
<select id="mulsel1" class="multiselect" multiple="multiple" data-title="Types de chapitres">
</select>
@@ -39,13 +39,13 @@
</select>
</div>
</div>
- <div class="row toggle-text"><span class="glyphicon glyphicon-chevron-right"></span> Voir les références de textes</div>
- <div class="row theatre-text" style="display: none;">
+ <div class="row filter-row toggle-text"><span class="glyphicon glyphicon-chevron-right"></span> Voir les références de textes</div>
+ <div class="row filter-row theatre-text" style="display: none;">
<iframe src="{% url 'spel_ctb' %}" width="97%" height="150px"></iframe>
<span>Début : </span><select id="start-text"></select>
<span>Fin : </span><select id="end-text"></select>
</div>
- <div class="row text-center">
+ <div class="row filter-row text-center">
<button id="btn-filter-chapters" class="btn btn-success" disabled="disabled">FILTRER</button>
</div>
<div class="chapter-results"></div>
--- a/src/spel/templatetags/spel_tags.py Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/templatetags/spel_tags.py Thu May 15 17:55:50 2014 +0200
@@ -38,7 +38,7 @@
continue
if t[:t.index(":")]=="modalites_sceniques" or t[:t.index(":")]=="personnages":
val.append(t[t.index(":")+2:])
- elif arg in ["type_inter", "personnages", "ref_text"]:
+ elif arg in ["type_inter", "personnages", "ref_text", "opera_modalites_sceniques", "opera_personnages", "opera_type_travail", "opera_acte", "opera_scene", "opera_mesure"]:
for t in a:
try:
t.index(":")
@@ -83,3 +83,16 @@
return value[value.index(":")+2:]
remove_tag_key.is_safe = True
+@register.filter
+def remove_opera(value):
+ """ Takes a string as 'opera_key: value' and returns the 'key: value' """
+ # Error management
+ if value is None :
+ return ""
+ if not isinstance(value, (str,unicode)) :
+ raise TemplateSyntaxError('remove_tag_key value error : string is required')
+ if value[:6]=="opera_":
+ return value[6:]
+ return value
+remove_tag_key.is_safe = True
+
--- a/src/spel/urls.py Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/urls.py Thu May 15 17:55:50 2014 +0200
@@ -6,7 +6,7 @@
from django.views.generic import RedirectView, TemplateView
from ldt.auth.views import login as pf_login
from ldt.text import VERSION_STR
-from .views import AnnotationRequest, ChapterRequest, Theatre, Opera
+from .views import AnnotationRequest, ChapterRequest, Theatre, Opera, OperaRequest
#from django.conf import settings
@@ -45,12 +45,13 @@
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
url(r'^$', TemplateView.as_view(template_name="spel_home.html"), name='spel_home'),
url(r'^theatre$', Theatre.as_view(), name='spel_theatre'),
- url(r'^opera$', Opera.as_view(), name='spel_opera'),
url(r'^chapters$', ChapterRequest.as_view(), name='spel_chapters'),
url(r'^annotations', AnnotationRequest.as_view(), name='spel_annotations'),
url(r'^ctb', TemplateView.as_view(template_name="ctb.html"), name='spel_ctb'),
url(r'^corpus', TemplateView.as_view(template_name="spel_corpus.html"), name='spel_corpus'),
url(r'^player', TemplateView.as_view(template_name="spel_player.html"), name='spel_player'),
+ url(r'^opera$', Opera.as_view(), name='spel_opera'),
+ url(r'^operaannotations$', OperaRequest.as_view(), name='spel_opera_annotations'),
)
urlpatterns += staticfiles_urlpatterns()
--- a/src/spel/views.py Thu May 15 15:29:21 2014 +0200
+++ b/src/spel/views.py Thu May 15 17:55:50 2014 +0200
@@ -337,7 +337,79 @@
return self.render_to_response(context)
-
+class OperaRequest(TemplateView):
+
+ template_name = "partial/spel_opera_annotations.html"
+
+ def get(self, request):
+ # Filter content by date if necessary
+ content_qs = Content.objects.filter(tags__name__in=["content_opera"])
+ start_date_param = request.GET.get("start_date", "")
+ if start_date_param!="":
+ content_qs = content_qs.filter(content_creation_date__gt=start_date_param)
+ end_date_param = request.GET.get("end_date", "")
+ if end_date_param!="":
+ content_qs = content_qs.filter(content_creation_date__lt=end_date_param + " 23:59:59")
+ iri_ids = content_qs.values_list("iri_id", flat=True)
+ #logger.debug("iri_ids")
+ #logger.debug(iri_ids)
+ # Filter segment if necessary
+ annot_types_param = request.GET.get("annotation_types", "")
+ seg_queryset = Segment.objects.filter(iri_id__in=iri_ids).select_related("content__title")
+ annot_types = []
+ if annot_types_param!="":
+ annot_types = annot_types_param.split(",")
+ seg_queryset = seg_queryset.filter(cutting_id__in=annot_types)
+
+ # First we look at modalites_sceniques and personnages tags.
+ mod_scen_param = request.GET.get("modalites_sceniques", "")
+ mod_scen = []
+ if mod_scen_param!="":
+ mod_scen = mod_scen_param.split(",")
+ perso_param = request.GET.get("personnages", "")
+ perso = []
+ if perso_param!="":
+ perso = perso_param.split(",")
+ type_travail_param = request.GET.get("type_travail", "")
+ type_travail = []
+ if type_travail_param!="":
+ type_travail = type_travail_param.split(",")
+ acte_param = request.GET.get("acte", "")
+ acte = []
+ if acte_param!="":
+ acte = acte_param.split(",")
+ scene_param = request.GET.get("scene", "")
+ scene = []
+ if scene_param!="":
+ scene = scene_param.split(",")
+ mesure_param = request.GET.get("mesure", "")
+ mesure = []
+ if mesure_param!="":
+ mesure = mesure_param.split(",")
+
+
+
+ # Get tags from orm
+ all_tags = mod_scen + perso + type_travail + acte + scene + mesure
+ tags = Tag.objects.filter(name__in=all_tags)
+ # seg_queryset.filter(tags__in=tags) doesn't work because taggit finds segments with one of the tags and not ALL tags
+ # So we make a correct request through TaggedItem first
+ # Get segments from tagged items
+ #s = TaggedItem.objects.get_by_model(seg_queryset, tags)
+ tags = list(tags)
+ seg_ids = list(TaggedItem.objects\
+ .values_list("object_id", flat=True)\
+ .filter(content_type=ContentType.objects.get_for_model(Segment))\
+ .filter(tag__in=tags)\
+ .annotate(count_status=Count('object_id'))\
+ .filter(count_status=len(tags)))
+ s = list(seg_queryset.filter(pk__in=seg_ids))
+
+ context = {"annot_types":annot_types, "start_date":start_date_param, "end_date":end_date_param,
+ "mod_scen":mod_scen, "perso":perso, "type_travail":type_travail, "acte":acte,
+ "scene":scene, "mesure":mesure, "segments": s}
+
+ return self.render_to_response(context)