--- a/src/spel/__init__.py Mon May 19 13:14:17 2014 +0200
+++ b/src/spel/__init__.py Wed May 21 18:28:07 2014 +0200
@@ -1,4 +1,4 @@
-VERSION = (0, 5, 14, "final", 0)
+VERSION = (0, 5, 15, "final", 0)
VERSION_STR = unicode(".".join(map(lambda i:"%02d" % (i,), VERSION[:2])))
--- a/src/spel/static/spel/css/spel.css Mon May 19 13:14:17 2014 +0200
+++ b/src/spel/static/spel/css/spel.css Wed May 21 18:28:07 2014 +0200
@@ -99,6 +99,9 @@
padding-left: 5px;
padding-right: 5px;
}
+.select-opera{
+ max-width: 100px;
+}
/* Player */
#LdtPlayer, #AnnotationsListContainer {
float: left;
--- a/src/spel/static/spel/js/opera.js Mon May 19 13:14:17 2014 +0200
+++ b/src/spel/static/spel/js/opera.js Wed May 21 18:28:07 2014 +0200
@@ -1,23 +1,31 @@
$(document).ready(function () {
+ function enabledFilter(){
+ var filter_enabled = false;
+ var chbs = $(".spel-content input:checkbox");
+ for (var i = chbs.length - 1; i >= 0; i--) {
+ filter_enabled = filter_enabled || $(chbs[i]).is(":checked");
+ }
+ if(!filter_enabled){
+ // check mesure
+ if((typeof $("#end-mesure").attr('disabled'))==="undefined" || $("#start-mesure").val()!="start"){
+ filter_enabled = true;
+ }
+ }
+ if(filter_enabled){
+ $("#btn-filter-chapters").removeAttr('disabled');
+ }
+ else{
+ $("#btn-filter-chapters").attr('disabled','disabled');
+ }
+ }
+
// Chapter multiselect management
$('.multiselect').multiselect({
buttonText: function(options, select) {
return $(select).attr("data-title") + ' (' + options.length + ') <b class="caret"></b>';
},
- onChange: function(element, checked) {
- var filter_enabled = false;
- var chbs = $(".spel-content input:checkbox");
- for (var i = chbs.length - 1; i >= 0; i--) {
- filter_enabled = filter_enabled || $(chbs[i]).is(":checked");
- };
- if(filter_enabled){
- $("#btn-filter-chapters").removeAttr('disabled');
- }
- else{
- $("#btn-filter-chapters").attr('disabled','disabled');
- }
- }
+ onChange: enabledFilter
});
// Data 1
@@ -138,9 +146,30 @@
}
return v1 - v2;
});
- $("#mulsel7").multiselect('dataprovider', data7);
- $("#mulsel7").multiselect('enable');
+ // Init select text
+ $("#start-mesure").append('<option value="start">Début</option>');
+ $.each(data7, function(k,val){
+ $("#start-mesure").append('<option value="'+ val.label +'">'+ val.label +'</option>');
+ var v = parseInt(val.label);
+ if(!isNaN(v)){
+ $("#end-mesure").append('<option value="'+ v +'">'+ v +'</option>');
+ }
+ });
+ $("#end-mesure").append('<option value="end" selected="selected">Fin</option>');
});
+ // start-mesure
+ $("#start-mesure").on('change', function() {
+ var reg = /^\d+$/;
+ if(reg.test(this.value)){
+ $("#end-mesure").removeAttr('disabled');
+ }
+ else{
+ $("#end-mesure").attr('disabled','disabled');
+ }
+ enabledFilter();
+ });
+
+
function buildChapterTable(html){
$(".chapter-results").removeClass("loader");
@@ -161,7 +190,7 @@
// Search chapters management
$("#btn-filter-chapters").click(function(e){
- if($("#mulsel1").val()==null && $("#mulsel2").val()==null && $("#mulsel3").val()==null && $("#mulsel4").val()==null && $("#mulsel5").val()==null && $("#mulsel6").val()==null && $("#mulsel7").val()==null){
+ if($("#mulsel1").val()==null && $("#mulsel2").val()==null && $("#mulsel3").val()==null && $("#mulsel4").val()==null && $("#mulsel5").val()==null && $("#mulsel6").val()==null && !((typeof $("#end-mesure").attr('disabled'))==="undefined" || $("#start-mesure").val()!="start")){
$(".chapter-results").html("<p>Vous devez sélectionner au moins un filtre</p>");
return false;
}
@@ -178,9 +207,8 @@
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()
+ start_mesure: $("#start-mesure").val(),
+ end_mesure: ($("#end-mesure").attr('disabled')) ? "" : $("#end-mesure").val()
}
})
.done(function( html ) {
@@ -215,7 +243,8 @@
$("#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());
+ $('#start-mesure')[0].selectedIndex = 0;
+ $("#end-mesure").attr('disabled','disabled');
}
else if($(this).parent().hasClass("date")){
$('input[name=start_date]').val("");
@@ -254,225 +283,8 @@
// Search annotations management
-
- function searchAnnotations(){
- $(".annotation-results").html("<br/><br/>");
- $(".annotation-results").addClass("loader");
- $.ajax({
- url: urlAnnotations,
- data:{
- q: $('#search-input').val(),
- type_inter: ( ($("#mulsel4").val()==null) ? [] : $("#mulsel4").val() ).join(",")
- }
- })
- .done(function(html){
- $(".annotation-results").removeClass("loader");
- $(".annotation-results").html(html);
- if($('#search-input').val() && $('#search-input').val()!=""){
- $("#btn-filter-annotations").click();
- }
- })
- .fail(function() {
- $(".annotation-results").removeClass("loader");
- $(".annotation-results").html('<p class="bg-danger">Erreur de chargement</p>');
- });
- }
-
- $("#btn-search-annotations").click(function(e){
- e.preventDefault();
- if($("#search-input").val()==""){
- $(".annotation-results").html("<p>Vous devez indiquer un terme pour la recherche.</p>");
- return false;
- }
- searchAnnotations();
- });
-
- $("#btn-filter-annotations").click(function(e){
- if($("#mulsel4").val() && $("#mulsel4").val()!=""){
- var filters = $("#mulsel4").val();
- var nb_filters = filters.length;
- if($('#search-input').val()!=""){
- $( ".searched-annot" ).each(function(index){
- var type_inter = $(this).attr("data-type-inter").split(", ");
- var found = true;
- for(var i=0;i<nb_filters;i++){
- if(type_inter.indexOf(filters[i])==-1){
- found = found && false;
- }
- }
- found ? $(this).show() : $(this).hide();
- });
- }
- else{
- searchAnnotations();
- }
- }
- else{
- $( ".searched-annot" ).each(function(j){
- $(this).show();
- });
- }
- // We display the clickable/removable tags.
- // First we remove all childs but the searched-term one
- if($(".annot-tag-list").children().first().children().first().hasClass("glyphicon-search")){
- $(".annot-tag-list").find("li:gt(0)").remove();
- }
- else{
- $(".annot-tag-list").children().remove();
- }
- if($("#mulsel4").val() && $("#mulsel4").val()!=""){
- var filters = $("#mulsel4").val();
- var nb_filters = filters.length;
- for(var i=0;i<nb_filters;i++){
- if(filters[i].trim()!=""){
- $(".annot-tag-list").append('<li class="small searched-tag">' + filters[i] + ' <span class="glyphicon glyphicon-remove small"></span></li>');
- }
- }
- }
- // Update number displayed
- $(".nb-annotations-found").html($('.annotation-results > div.searched-annot:visible').length);
- });
-
- // click-to-remove-tag management for annotations
- $(".annotation-results").on("click", ".annot-tag-list .glyphicon-remove", function(){
- if($(this).parent().children().first().hasClass("glyphicon-search")){
- $("#search-input").val("");
- }
- else{
- $("#mulsel4").multiselect('deselect', $(this).parent().text().trim());
- }
- $("#btn-filter-annotations").click();
- // manage when nothing is selected
- if($(".annot-tag-list").children().length==0 && $(".annotation-results .info").length==0){
- $(".annotation-results").html('');
- }
+ $('#searchform').submit(function() {
+ return false;
});
- // Annotations to chapters management
- $(".annotation-results").on("click", ".annot-to-chapter", function(){
- // First we unselect chapter filters
- $('option', $('#mulsel1')).each(function(element) { $(this).removeAttr('selected').prop('selected', false); });
- $('#mulsel1').multiselect('refresh');
- $('option', $('#mulsel2')).each(function(element) { $(this).removeAttr('selected').prop('selected', false); });
- $('#mulsel2').multiselect('refresh');
- $('option', $('#mulsel3')).each(function(element) { $(this).removeAttr('selected').prop('selected', false); });
- $('#mulsel3').multiselect('refresh');
- // Then we request
- $(".chapter-results").html("<br/><br/>");
- $(".chapter-results").addClass("loader");
- var bla = [];
- $('.annotation-results > div.searched-annot:visible').each(function(index){
- bla.push({data: $(this).attr("data-start"), iri_id: $(this).attr("data-content") });
- });
- if(bla.length==0){
- $(".chapter-results").removeClass("loader");
- return;
- }
- $.post(
- urlChapters,
- {
- annotations: JSON.stringify(bla),
- csrfmiddlewaretoken: csrf_token
- },
- function( html ) {
- buildChapterTable(html);
- }
- )
- .fail(function() {
- $(".chapter-results").removeClass("loader");
- $(".chapter-results").html('<p class="bg-danger">Erreur de chargement</p>');
- });
- });
-
- // Chapter to annotations management
- $(".chapter-results").on("click", ".chapter-to-annot", function(){
- // First we unselect chapter filters
- $('option', $('#mulsel4')).each(function(element) { $(this).removeAttr('selected').prop('selected', false); });
- $('#mulsel4').multiselect('refresh');
- // Then we request
- $(".annotation-results").html("<br/><br/>");
- $(".annotation-results").addClass("loader");
- var bla = [];
- $('.chapter-data').each(function(index){
- bla.push({start: $(this).attr("data-start"), end: $(this).attr("data-end"), iri_id: $(this).attr("data-content") });
- });
- if(bla.length==0){
- $(".annotation-results").removeClass("loader");
- return;
- }
- $.post(
- urlAnnotations,
- {
- chapters: JSON.stringify(bla),
- csrfmiddlewaretoken: csrf_token
- },
- function( html ) {
- $("#search-input").val(" "); // trick to simply enable filter annotations
- $(".annotation-results").removeClass("loader");
- $(".annotation-results").html(html);
- }
- )
- .fail(function() {
- $(".annotation-results").removeClass("loader");
- $(".annotation-results").html('<p class="bg-danger">Erreur de chargement</p>');
- });
- });
-
- // Filter chapter to annotations
- $(".chapter-results").on("click", ".filter-chapter-annot", function(){
- var $tr = $(this).parent().parent();
- // green line or not
- ($(this).prop('checked')==true) ? $tr.addClass("success") : $tr.removeClass("success");
- filterAnnotationsWithChapters();
- });
-
- function filterAnnotationsWithChapters(){
- // Remove all childs but the searched-term one
- if($(".annot-tag-list").children().first().children().first().hasClass("glyphicon-search")){
- $(".annot-tag-list").find("li:gt(0)").remove();
- }
- else{
- $(".annot-tag-list").children().remove();
- }
- // We build the the array of content ids and timecodes
- var id_tc = {};
- $(".chapter-results input[type=checkbox]:checked").each(function(index){
- var $tr = $(this).parent().parent();
- var iri_id = $tr.attr("data-content");
- if(!(iri_id in id_tc)){
- id_tc[iri_id] = [];
- }
- id_tc[iri_id].push({ start: parseInt($tr.attr("data-start")), end: parseInt($tr.attr("data-end")) });
- });
- $('.annotation-results > div.searched-annot').each(function(index){
- // annot in timecode and content ?
- var show = true;
- var iri_id = $(this).attr("data-content");
- if(iri_id in id_tc){
- show = true;
- }
- else{
- show = false;
- }
- show ? $(this).show() : $(this).hide();
- });
-
- if($(".chapter-results input[type=checkbox]:checked").length==0){
- $('.annotation-results > div.searched-annot').show();
- }
- // Update number displayed
- $(".nb-annotations-found").html($('.annotation-results > div.searched-annot:visible').length);
- }
-
- // spectacle theatre text management
- $(".toggle-text").click(function(e){
- if($(".theatre-text:visible").length==0){
- $(".theatre-text").show();
- $(".toggle-text .glyphicon-chevron-right").addClass("rotate-90");
- }
- else{
- $(".theatre-text").hide();
- $(".toggle-text .glyphicon-chevron-right").removeClass("rotate-90");
- }
- });
});
--- a/src/spel/templates/partial/spel_opera_annotations.html Mon May 19 13:14:17 2014 +0200
+++ b/src/spel/templates/partial/spel_opera_annotations.html Wed May 21 18:28:07 2014 +0200
@@ -14,7 +14,11 @@
{% 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 %}
+ {% if mesure|length > 1 %}
+ <li class="small searched-tag mesure">{{ mesure|first }} ≤ Mesure ≤ {{ mesure|last }} <span class="glyphicon glyphicon-remove small"></span></li>
+ {% else %}
+ {% for t in mesure %}<li class="small searched-tag mesure">{{ t }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+ {% endif %}
</ul>
<p>{{ segments|length }} segment(s) trouvé(s)</p>
</div>
--- a/src/spel/templates/spel_opera.html Mon May 19 13:14:17 2014 +0200
+++ b/src/spel/templates/spel_opera.html Wed May 21 18:28:07 2014 +0200
@@ -26,25 +26,34 @@
</div>
</div>
<div class="row filter-row">
- <div class="col-md-4">
+ <div class="col-md-3">
<select id="mulsel2" class="multiselect" multiple="multiple" data-title="Modalités scéniques" disabled="disabled"></select>
</div>
- <div class="col-md-4">
+ <div class="col-md-3">
<select id="mulsel3" class="multiselect" multiple="multiple" data-title="Personnages" disabled="disabled"></select>
</div>
- <div class="col-md-4">
+ <div class="col-md-3">
<select id="mulsel4" class="multiselect" multiple="multiple" data-title="Type travail" disabled="disabled"></select>
</div>
+ <div class="col-md-3">
+ <form id="searchform" role="form">
+ <input type="text" class="form-control" id="search-input" name="search-input" placeholder="Commentaire" disabled="disabled" />
+ <button style="display: none;"><span class="glyphicon glyphicon-search form-control-feedback"></span></button>
+ </form>
+ </div>
</div>
<div class="row filter-row">
- <div class="col-md-4">
+ <div class="col-md-3">
<select id="mulsel5" class="multiselect" multiple="multiple" data-title="Actes" disabled="disabled"></select>
</div>
- <div class="col-md-4">
+ <div class="col-md-3">
<select id="mulsel6" class="multiselect" multiple="multiple" data-title="Scènes" disabled="disabled"></select>
</div>
- <div class="col-md-4">
- <select id="mulsel7" class="multiselect" multiple="multiple" data-title="Mesures" disabled="disabled"></select>
+ <div class="col-md-6">
+ <form class="form-inline" role="form">
+ Mesures : <small>Début : </small><select class="form-control select-opera" id="start-mesure"></select>
+ <small>Fin : </small><select class="form-control select-opera" id="end-mesure" disabled="disabled"></select>
+ </form>
</div>
</div>
<div class="row filter-row text-center">
--- a/src/spel/views.py Mon May 19 13:14:17 2014 +0200
+++ b/src/spel/views.py Wed May 21 18:28:07 2014 +0200
@@ -382,32 +382,82 @@
scene = []
if scene_param!="":
scene = scene_param.split(",")
- mesure_param = request.GET.get("mesure", "")
- mesure = []
- if mesure_param!="":
- mesure = mesure_param.split(",")
-
+ start_mesure = request.GET.get("start_mesure", "")
+ end_mesure = request.GET.get("end_mesure", "")
+ mesure = None
+ mesure_int = None
+ if start_mesure=="start" and end_mesure=="":
+ mesure = []
+ mesure_int = []
+ elif start_mesure!="start" and end_mesure=="":
+ # Only one mesure has been defined
+ mesure = [Tag.objects.get(name="opera_mesure: " + start_mesure)]
+ mesure_int = [start_mesure]
+ elif end_mesure!="":
+ # First get all ref_text values
+ m_tags = Tag.objects.filter(name__startswith="opera_mesure:")
+ mesure_int = []
+ for m in m_tags:
+ tested = re.match(r"^(\d+)$", m.name[14:])
+ if tested and len(tested.groups())==1:
+ mesure_int.append(int(tested.group(1)))
+ mesure_int.sort()
+
+ # At least start or end have been defined, so we search for the concerned chapter ids.
+ start_index = 0
+ if start_mesure!="start":
+ try:
+ start_index = mesure_int.index(int(start_mesure))
+ except:
+ pass
+ end_index = len(mesure_int)
+ if end_mesure!="end":
+ try:
+ end_index = mesure_int.index(int(end_mesure)) + 1
+ except:
+ pass
+ mesure_int = mesure_int[start_index:end_index]
+ mesure = Tag.objects.filter(name__in=[ ("opera_mesure: " + str(m)) for m in mesure_int ])
# Get tags from orm
- all_tags = mod_scen + perso + type_travail + acte + scene + mesure
+ all_tags = mod_scen + perso + type_travail + acte + scene
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))
+ # Mesure filter if possible
+ if mesure and len(mesure)>0:
+ # a chapter can only have on ref_text, and the search on ref_text is a OR.
+ # That's many requests (with the orm) but it seems the only thing possible with tagging
+ s = []
+ for m in mesure:
+ current_tags = list(tags)
+ current_tags.append(m)
+ #s += list(TaggedItem.objects.get_by_model(seg_queryset, current_tags))
+ seg_ids = list(TaggedItem.objects\
+ .values_list("object_id", flat=True)\
+ .filter(content_type=ContentType.objects.get_for_model(Segment))\
+ .filter(tag__in=current_tags)\
+ .annotate(count_status=Count('object_id'))\
+ .filter(count_status=len(current_tags)))
+ s += list(seg_queryset.filter(pk__in=seg_ids))
+ else:
+ # 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}
+ "scene":scene, "mesure":mesure_int, "segments": s}
return self.render_to_response(context)