Gitlab CSE Unil

Commit 658fc668 authored by M. Chardon's avatar M. Chardon
Browse files

documentation

parent 6dba139a
This diff is collapsed.
# Annotate audio files, Moodle actiity module
This module is developed and maintained by RISET/University of Lausanne.
Author: Marion Chardon, <marion.chardon@unil.ch>
Compatible with Moodle versions: 3.7+
## Description
This tool is a Moodle activity wich allows:
- as a student:
- to give audio assignement (one or several audio files)
- to annotate its own assignement
- to annotate pair assignement
- to have a feedback and see all annotations on its assignement
- to give feedback to annotations on its assignement
- as a teacher:
- to annotate an audio file, in a write and/or audio way
- to ask question or feedback to student on a specific point
- to create different custom categories of annotations to grade work
- to manage favorite set of annotation's caregories
See this <a href="https://gitlabriset.unil.ch/Marion.Chardon/moodle-mod_audioannotation/wikis/home">wiki page</a> for screenshots.
## Installation
1. Download as a ZIP file
2. Extract the ZIP file in '<your-moodle-root-directory>/mod/' directory
3. Rename the extracted root directory to 'audioannotation'
## Configuration
You need to specify ffmpeg library location.
## Tips
In player, in write mode (pairing, teacher in edit mode and student in edit mode), there are some shortcuts you can use:
- 'space' for playing/pausing sound
- 'b' for going back from 2 seconds
- 'n' for create a new annotation
## What's next?
Upcoming developments may include:
- annotation on an time interval
- audi feedback in student side
## Technical part
### Global schema
See this <a href="https://gitlabriset.unil.ch/Marion.Chardon/moodle-mod_audioannotation/wikis/technical_explanations">wiki page</a> for schema.
### ffmpeg
All audio file are converted in mp3 format, for more compatibilty and browser display, as mp3 is the only one (for now) to be displayed in all browsers and devices.
If a user inserts an unrecognazie audio format, you can add it on your Moodle configuration (file types pages, in Moodle administration).
### Web RTC
Module use javascript web RTC technology. By careful, there is a lof of different comportement between browsers and devices. All web RTC developements are include in record.js and recordsManager.js
### JustWave
Thanks to this tool https://github.com/beotiger , with some modifications and adaptations, the module can generate:
- a picture of the sound (which is set in cache to Moodle, and clear with a cron task)
- a multi function player
## Contributors and Licenses
Copyright: University of Lausanne, RISET
Author: Marion Chardon, <marion.chardon@unil.ch>
'Audio annotation' is a free software released under the GNU GPL licence, version 3.
define(["jquery","mod_audioannotation/justWave","mod_audioannotation/editor","mod_audioannotation/rightMenu"],function(a,b,c,d){function e(a){e.currentUser="userid"in a?a.userid:null,e.courseid="course"in a?a.course:null,e.audioannotation="audioannotation"in a?a.audioannotation:null,e.eval="eval"in a?a.eval:0,e.iswriting="iswriting"in a?a.iswriting:0,e.pairing="pairing"in a?a.pairing:0;var f="repo"in a?a.repo:null,g="assignparts"in a?a.assignparts:null,h=null;if(g)try{h=JSON.parse(g)}catch(i){window.console.error(i)}var j="tags"in a?a.tags:null,k=null;if(j)try{k=JSON.parse(j)}catch(i){window.console.error(i)}if(e.editors=[],h)for(var l=0;l<h.length;l++){e.editors[h[l].id]=new c({controler:this,courseid:e.courseid,assignpart:h[l],audioannotation:e.audioannotation,tags:k,repo:f});var m=new b(this,e.editors[h[l].id]);e.editors[h[l].id].setWavePlayer(m),this.initWave(m,"justwave",h[l].id)}this.initTrigger(),e.rightMenu=new d({controler:this}),this.initDisplay()}return e.courseid=-1,e.audioannotation=-1,e.prototype.editors=null,e.rightMenu=null,e.eval=0,e.iswriting=0,e.pairing=0,e.currentUser=null,e.prototype.initTrigger=function(){1!=e.eval&&1!=e.iswriting||(a(".btn_add_annotation").on("click",function(){e.editors[a(this).data("assignpart")].notify("add")}),a(".btn_add_annotation").on("mouseout",function(){a(this).blur(),a(this).parents('div[data-parent="#accordionAssignPart"]').focus()})),a(".select_tqs").on("change",function(){var b=a(this).data("assignpart");e.editors[b].notify("displaytqs",{tag:a("#select_tag"+b).val(),question:a("#select_question"+b).val(),statut:a("#select_statut"+b).val(),author:a("#select_author"+b).val()})}),a("li[data-annotation]").on("click",function(){var b=a(this).data("annotation"),c=a(this).parents(".annotationGroupAccordion").data("assignpart");b&&e.editors[c].notify("view",{annotation:b})}),a("#id_grade").on("change",function(){a(this).val()?a("input[name=gradeempty]").val(0):a("input[name=gradeempty]").val(1)}),a("div[data-parent='#accordionAssignPart']").on("show.bs.collapse",function(){var b=a("div[data-target='#"+a(this).attr("id")+"']"),c=b.find("i.fa-caret-right");c.removeClass("fa-caret-right"),c.addClass("fa-caret-down")}),a("div[data-parent='#accordionAssignPart']").on("hide.bs.collapse",function(){var b=a("div[data-target='#"+a(this).attr("id")+"']"),c=b.find("i.fa-caret-down");c.removeClass("fa-caret-down"),c.addClass("fa-caret-right")});var b=a("input[name$='mod_audioannotation_form_assignaudio_eval_form']");a("div.feedback > form").on("submit",function(){a("div.feedback > form").append(b)})},e.prototype.initWave=function(b,c,d){b.init(c),b.drawWaveDisplay(a(".justwave"+d+" audio"))},e.prototype.initAnnotations=function(){for(var a=0;a<e.editors.length;a++)e.editors[a]&&e.editors[a].initAnnotationsDisplay()},e.prototype.notify=function(a,b,c){switch(a){case"loadedmetadata":this.initAnnotations();break;case"addannotation":for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("add");break;case"editannotation":for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("edit");break;case"viewannotation":for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("view");break;case"deleteannotation":if("rightMenu"===b)for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].notify("delete",c);else for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("delete")}},e.prototype.getEval=function(){return e.eval},e.prototype.isWriting=function(){return e.iswriting},e.prototype.getPairing=function(){return e.pairing},e.prototype.getCurrentUser=function(){return e.currentUser},e});
\ No newline at end of file
define(["jquery","mod_audioannotation/justWave","mod_audioannotation/editor","mod_audioannotation/rightMenu"],function(a,b,c,d){function e(a){e.currentUser="userid"in a?a.userid:null,e.courseid="course"in a?a.course:null,e.audioannotation="audioannotation"in a?a.audioannotation:null,e.eval="eval"in a?a.eval:0,e.iswriting="iswriting"in a?a.iswriting:0,e.pairing="pairing"in a?a.pairing:0;var f="repo"in a?a.repo:null,g="assignparts"in a?a.assignparts:null,h=null;if(g)try{h=JSON.parse(g)}catch(i){window.console.error(i)}var j="tags"in a?a.tags:null,k=null;if(j)try{k=JSON.parse(j)}catch(i){window.console.error(i)}if(e.editors=[],h)for(var l=0;l<h.length;l++){e.editors[h[l].id]=new c({controler:this,courseid:e.courseid,assignpart:h[l],audioannotation:e.audioannotation,tags:k,repo:f});var m=new b(this,e.editors[h[l].id]);e.editors[h[l].id].setWavePlayer(m),this.initWave(m,"justwave",h[l].id)}this.initTrigger(),e.rightMenu=new d({controler:this})}return e.courseid=-1,e.audioannotation=-1,e.prototype.editors=null,e.rightMenu=null,e.eval=0,e.iswriting=0,e.pairing=0,e.currentUser=null,e.prototype.initTrigger=function(){1!=e.eval&&1!=e.iswriting||(a(".btn_add_annotation").on("click",function(){e.editors[a(this).data("assignpart")].notify("add")}),a(".btn_add_annotation").on("mouseout",function(){a(this).blur(),a(this).parents('div[data-parent="#accordionAssignPart"]').focus()})),a(".select_tqs").on("change",function(){var b=a(this).data("assignpart");e.editors[b].notify("displaytqs",{tag:a("#select_tag"+b).val(),question:a("#select_question"+b).val(),statut:a("#select_statut"+b).val(),author:a("#select_author"+b).val()})}),a("li[data-annotation]").on("click",function(){var b=a(this).data("annotation"),c=a(this).parents(".annotationGroupAccordion").data("assignpart");b&&e.editors[c].notify("view",{annotation:b})}),a("#id_grade").on("change",function(){a(this).val()?a("input[name=gradeempty]").val(0):a("input[name=gradeempty]").val(1)}),a("div[data-parent='#accordionAssignPart']").on("show.bs.collapse",function(){var b=a("div[data-target='#"+a(this).attr("id")+"']"),c=b.find("i.fa-caret-right");c.removeClass("fa-caret-right"),c.addClass("fa-caret-down")}),a("div[data-parent='#accordionAssignPart']").on("hide.bs.collapse",function(){var b=a("div[data-target='#"+a(this).attr("id")+"']"),c=b.find("i.fa-caret-down");c.removeClass("fa-caret-down"),c.addClass("fa-caret-right")});var b=a("input[name$='mod_audioannotation_form_assignaudio_eval_form']");a("div.feedback > form").on("submit",function(){a("div.feedback > form").append(b)})},e.prototype.initWave=function(b,c,d){b.init(c),b.drawWaveDisplay(a(".justwave"+d+" audio"))},e.prototype.initAnnotations=function(){for(var a=0;a<e.editors.length;a++)e.editors[a]&&e.editors[a].initAnnotationsDisplay()},e.prototype.notify=function(a,b,c){switch(a){case"loadedmetadata":this.initAnnotations();break;case"addannotation":for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("add");break;case"editannotation":for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("edit");break;case"viewannotation":for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("view");break;case"deleteannotation":if("rightMenu"===b)for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].notify("delete",c);else for(var d=0;d<e.editors.length;d++)e.editors[d]&&e.editors[d].setEditorStatus("delete")}},e.prototype.getEval=function(){return e.eval},e.prototype.isWriting=function(){return e.iswriting},e.prototype.getPairing=function(){return e.pairing},e.prototype.getCurrentUser=function(){return e.currentUser},e});
\ No newline at end of file
define(["jquery"],function(a){function b(a,c){return this.controler=a,this.assignpart=c,b.clickAnnotation=0,this}b.controler=null,b.assignpart=-1,b.clickAnnotation=0,b.delayBeforeAnnotation=2,b.options=null,b.prototype.PLAYPAUSEBUTTON=".justwave_playpause",b.prototype.PLAYPAUSEBUTTONBEFORE=".justwave_playpause_before",b.prototype.CURRENTFOCUS=".justwave_curfocus",b.prototype.drawAnnotation=function(b,c,d){if(b&&b.duration){var e=c.timeposition/b.duration*100,f=a(b).next(),g=c.displayDiv(e,d);f.find(".audio_annotations").append(g)}},b.prototype.goBeforeAnnotation=function(a,d){a&&(a.currentTime=Math.max(d.timeposition-b.delayBeforeAnnotation,0),c(a),b.clickAnnotation=1)},b.prototype.getWaveOpts=function(c){var d={ajax:"justWave/justwave.ajax.php",width:900,height:100,wave_color:"#909296",prog_color:"#74cdd7",back_color:"#FFFFFF",buttoncolor:"#A47655",buttonsize:0,showname:1,namesize:15,showtimes:1,nowaves:0,nocache:!0};a.isPlainObject(b.options)&&a.extend(d,b.options),c.attr("width")&&(d.width=c.attr("width")),c.attr("height")&&(d.height=c.attr("height")),c.attr("poster")&&(d.poster=c.attr("poster"));var e=c.data();return Object.keys(e).map(function(a){return d[a]=e[a],d[a]}),d},b.prototype.init=function(h,i){var j=a("#player_markup > div.justwave_wrapper").clone(),k=a("audio");null!==this.assignpart&&(k=a(".justwave"+this.assignpart.assignpartid).find("audio")),"string"==typeof h&&(i=h),"string"==typeof i&&(k=k.filter("."+i));var l=this.controler,m=this.assignpart,n=this.getWaveOpts;k.each(function(){var h=this,i=a(this);h.opts=n(i),h.opts.chained&&i.addClass("justwave_chained"),i.after(j),a(h).on("canplay",function(b){var c=b.target,d=a(c).next();c.xduration=c.duration,c.opts.showtimes&&c.opts.showtimes>0?d.find(".justwave_duration, .justwave_curpos").show():d.find(".justwave_duration, .justwave_curpos").hide()}).on("playing",function(c){var d=c.target,e=a(d).next();e.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").addClass("fa-pause"),e.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").removeClass("fa-play"),d.opts.chained&&a("audio.justwave_chained").each(function(){this!==d&&this.pause()}),l.notify("playing","player",d)}).on("pause",function(c){var d=a(c.target).next();d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").addClass("fa-play"),d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").removeClass("fa-pause")}).on("error",function(c){var d=c.target,e=a(d).next();f(d),e.find(b.prototype.PLAYPAUSEBUTTON).prop("disabled",!0),e.find(b.prototype.PLAYPAUSEBUTTONBEFORE).prop("disabled",!0),e.find(".justwave_songname").text(a(d).attr("src").replace(/.+[\\\/]/,"")),e.find(".justwave_duration").text("00:00"),d.xduration=0,e.find(".justwave_duration, .justwave_curpos, "+b.prototype.CURRENTFOCUS).hide(),l.notify("error","player",d)}).on("timeupdate",function(){c(this)}).on("ended",function(){this.pause()}),f(h),g(h);var k=i.next();k.click(function(d){if(!b.clickAnnotation||0===b.clickAnnotation){d.preventDefault();var e=a(this).prev()[0],f=a(this).offset(),g=d.pageX-f.left;e.currentTime=g*e.xduration/this.offsetWidth,c(e),m.notify("click",e.currentTime)}b.clickAnnotation=0}).mousemove(function(c){var f=a(this).offset(),g=c.pageX-f.left,h=c.pageY-f.top,i=this,j=a(this).prev()[0];a(i).find(b.prototype.CURRENTFOCUS).text(d(g/this.offsetWidth*j.xduration)).css({top:h-5+"px",left:g+5+"px"}),j.opts.showname&&j.opts.showname>0&&e(a(i).find(".justwave_songname"))}).mouseleave(function(){a(this).find(b.prototype.CURRENTFOCUS).hide(),a(this).find(b.prototype.PLAYPAUSEBUTTON).fadeOut(1e3),a(this).find(b.prototype.PLAYPAUSEBUTTONBEFORE).fadeOut(1e3)}).mouseenter(function(){var c=a(this).prev()[0];a(this).find(b.prototype.PLAYPAUSEBUTTON).stop(!1,!0).fadeIn(500),a(this).find(b.prototype.PLAYPAUSEBUTTONBEFORE).stop(!1,!0).fadeIn(500),c.opts.showtimes&&c.opts.showtimes>0&&a(this).find(b.prototype.CURRENTFOCUS).show(),l.notify("mouseenter","player",c)}).dblclick(function(){b.clickAnnotation&&0!==b.clickAnnotation||(h.pause(),m.notify("dblclick")),b.clickAnnotation=0}),k.find(b.prototype.PLAYPAUSEBUTTON).on("click touchstart",function(b){b.stopPropagation(),b.preventDefault();var c=a(this).parent(),d=c.prev()[0];d.ended&&(d.currentTime=0),d.paused?d.play():(d.pause(),m.notify("pause",d.currentTime)),l.notify("pause","player",d)}),k.find(b.prototype.PLAYPAUSEBUTTONBEFORE).on("click touchstart",function(d){d.stopPropagation(),d.preventDefault();var e=a(this).parent(),f=e.prev()[0];f.ended&&(f.currentTime=0),f.currentTime=Math.max(f.currentTime-b.delayBeforeAnnotation,0),c(f)}).on("dblclick",function(a){a.stopPropagation(),a.preventDefault()}),k.find(".justwave_playpause_btn").mouseenter(function(){a(this).siblings(b.prototype.CURRENTFOCUS).hide()}).mouseleave(function(){var c=a(this).parent().prev()[0];c.opts.showtimes&&c.opts.showtimes>0&&a(this).siblings(b.prototype.CURRENTFOCUS).show()});var o=k.parents('div[data-parent="#accordionAssignPart"]');o.attr("tabindex",0),o.on("keydown",function(a){32===a.which&&(a.preventDefault(),k.find("button"+b.prototype.PLAYPAUSEBUTTON).click()),66===a.which&&(a.preventDefault(),k.find("button"+b.prototype.PLAYPAUSEBUTTONBEFORE).click()),78===a.which&&(a.preventDefault(),h.pause(),m.notify("pause",h.currentTime),m.notify("dblclick"))}),l.notify("initeach","player",h)})};var c=function(b){var c=b.currentTime/b.xduration*100,e=a(b).next();c<=100.1&&e.find(".justwave_playhead").width(c+"%"),e.find(".justwave_curpos").text(d(b.currentTime))},d=function(a){var b=Math.floor(a/60),c=Math.floor(a%60);return isNaN(a)?"00:00":(b<10?"0":"")+b+":"+(c<10?"0":"")+c},e=function(a,b){b&&a.stop(!0,!0).hide(),a.is(":visible")||a.fadeIn(300,function(){a.fadeOut(7e3,"swing")})},f=function(b){var c=a(b).next();c.find(".justwave_wave").width(0).attr("src",""),c.find(".justwave_progress").width(0).attr("src",""),c.width(b.opts.width).height(b.opts.height).css("background",b.opts.wave_color),b.opts.poster&&c.css("background-image","url("+b.opts.poster+")"),c.find(".justwave_playhead").css("background",b.opts.prog_color)},g=function(c){var d=a(c).next();d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").addClass("fa-play"),d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").removeClass("fa-pause")};return b.prototype.drawWaveDisplay=function(b){var c=this.assignpart;b.opts=this.getWaveOpts(b);var h=new Audio;a(h).on("loadedmetadata",function(){var h=a(b).next();f(b),g(b),a(b).attr("src")?b.opts.audio=a(b).attr("src"):b.opts.audio=b.currentSrc;var i=h.find(".justwave_songname").css("font-size",b.opts.namesize+"px").text(decodeURIComponent(b.opts.audio.replace(/.+[\\\/]/,"")));b.opts.showname&&b.opts.showname>0&&e(i,!0),+b.opts.nowaves||a.ajax(b.opts.ajax,{dataType:"json",type:"POST",data:b.opts}).done(function(e){var f=a(b).next(),g=f.find(".justwave_wave"),h=f.find(".justwave_progress");"ok"===e.status&&(g.width(b.opts.width),h.width(b.opts.width),f.css("background",""),f.find(".justwave_playhead").css("background",""),b.opts.poster&&f.css("background-image","url("+b.opts.poster+")"),g.attr("src",e.waveurl),b.opts.wave_color===b.opts.prog_color?h.attr("src",e.waveurl):h.attr("src",e.progressurl)),b.xduration=parseFloat(e.duration),b.xduration||(b.xduration=b.duration),b.xduration&&!b.duration&&(b.duration=e.duration),f.find(".justwave_duration").text(d(b.xduration));var i=a(f).prev()[0];i.xduration=b.xduration,i.duration=b.duration,c&&c.notify("loadedmetadata",b)})}),h.src=a(b).attr("src")},b});
\ No newline at end of file
define(["jquery"],function(a){function b(a,c){return this.controler=a,this.assignpart=c,b.clickAnnotation=0,this}b.controler=null,b.assignpart=-1,b.clickAnnotation=0,b.delayBeforeAnnotation=2,b.options=null,b.prototype.PLAYPAUSEBUTTON=".justwave_playpause",b.prototype.PLAYPAUSEBUTTONBEFORE=".justwave_playpause_before",b.prototype.CURRENTFOCUS=".justwave_curfocus",b.prototype.drawAnnotation=function(b,c,d){if(b&&b.duration){var e=c.timeposition/b.duration*100,f=a(b).next(),g=c.displayDiv(e,d);f.find(".audio_annotations").append(g)}},b.prototype.goBeforeAnnotation=function(a,d){a&&(a.currentTime=Math.max(d.timeposition-b.delayBeforeAnnotation,0),c(a),b.clickAnnotation=1)},b.prototype.getWaveOpts=function(c){var d={ajax:"justWave/justwave.ajax.php",width:900,height:100,wave_color:"#909296",prog_color:"#74cdd7",back_color:"#FFFFFF",buttoncolor:"#A47655",buttonsize:0,showname:1,namesize:15,showtimes:1,nowaves:0,nocache:!0};a.isPlainObject(b.options)&&a.extend(d,b.options),c.attr("width")&&(d.width=c.attr("width")),c.attr("height")&&(d.height=c.attr("height")),c.attr("poster")&&(d.poster=c.attr("poster"));var e=c.data();return Object.keys(e).map(function(a){return d[a]=e[a],d[a]}),d},b.prototype.init=function(h,i){var j=a("#player_markup > div.justwave_wrapper").clone(),k=a("audio");null!==this.assignpart&&(k=a(".justwave"+this.assignpart.assignpartid).find("audio")),"string"==typeof h&&(i=h),"string"==typeof i&&(k=k.filter("."+i));var l=this.controler,m=this.assignpart,n=this.getWaveOpts;k.each(function(){var h=this,i=a(this);h.opts=n(i),h.opts.chained&&i.addClass("justwave_chained"),i.after(j),a(h).on("canplay",function(b){var c=b.target,d=a(c).next();c.xduration=c.duration,c.opts.showtimes&&c.opts.showtimes>0?d.find(".justwave_duration, .justwave_curpos").show():d.find(".justwave_duration, .justwave_curpos").hide()}).on("playing",function(c){var d=c.target,e=a(d).next();e.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").addClass("fa-pause"),e.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").removeClass("fa-play"),d.opts.chained&&a("audio.justwave_chained").each(function(){this!==d&&this.pause()}),l.notify("playing","player",d)}).on("pause",function(c){var d=a(c.target).next();d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").addClass("fa-play"),d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").removeClass("fa-pause")}).on("error",function(c){var d=c.target,e=a(d).next();f(d),e.find(b.prototype.PLAYPAUSEBUTTON).prop("disabled",!0),e.find(b.prototype.PLAYPAUSEBUTTONBEFORE).prop("disabled",!0),e.find(".justwave_songname").text(a(d).attr("src").replace(/.+[\\\/]/,"")),e.find(".justwave_duration").text("00:00"),d.xduration=0,e.find(".justwave_duration, .justwave_curpos, "+b.prototype.CURRENTFOCUS).hide(),l.notify("error","player",d)}).on("timeupdate",function(){c(this)}).on("ended",function(){this.pause()}),f(h),g(h);var k=i.next();k.click(function(d){if(!b.clickAnnotation||0===b.clickAnnotation){d.preventDefault();var e=a(this).prev()[0],f=a(this).offset(),g=d.pageX-f.left;e.currentTime=g*e.xduration/this.offsetWidth,c(e),m.notify("click",e.currentTime)}b.clickAnnotation=0}).mousemove(function(c){var f=a(this).offset(),g=c.pageX-f.left,h=c.pageY-f.top,i=this,j=a(this).prev()[0];a(i).find(b.prototype.CURRENTFOCUS).text(d(g/this.offsetWidth*j.xduration)).css({top:h-5+"px",left:g+5+"px"}),j.opts.showname&&j.opts.showname>0&&e(a(i).find(".justwave_songname"))}).mouseleave(function(){a(this).find(b.prototype.CURRENTFOCUS).hide(),a(this).find(b.prototype.PLAYPAUSEBUTTON).fadeOut(1e3),a(this).find(b.prototype.PLAYPAUSEBUTTONBEFORE).fadeOut(1e3)}).mouseenter(function(){var c=a(this).prev()[0];a(this).find(b.prototype.PLAYPAUSEBUTTON).stop(!1,!0).fadeIn(500),a(this).find(b.prototype.PLAYPAUSEBUTTONBEFORE).stop(!1,!0).fadeIn(500),c.opts.showtimes&&c.opts.showtimes>0&&a(this).find(b.prototype.CURRENTFOCUS).show(),l.notify("mouseenter","player",c)}).dblclick(function(){l.isWriting()<=0&&l.getPairing()<=0||(b.clickAnnotation&&0!==b.clickAnnotation||(h.pause(),m.notify("dblclick")),b.clickAnnotation=0)}),k.find(b.prototype.PLAYPAUSEBUTTON).on("click touchstart",function(b){b.stopPropagation(),b.preventDefault();var c=a(this).parent(),d=c.prev()[0];d.ended&&(d.currentTime=0),d.paused?d.play():(d.pause(),m.notify("pause",d.currentTime)),l.notify("pause","player",d)}),k.find(b.prototype.PLAYPAUSEBUTTONBEFORE).on("click touchstart",function(d){d.stopPropagation(),d.preventDefault();var e=a(this).parent(),f=e.prev()[0];f.ended&&(f.currentTime=0),f.currentTime=Math.max(f.currentTime-b.delayBeforeAnnotation,0),c(f)}).on("dblclick",function(a){a.stopPropagation(),a.preventDefault()}),k.find(".justwave_playpause_btn").mouseenter(function(){a(this).siblings(b.prototype.CURRENTFOCUS).hide()}).mouseleave(function(){var c=a(this).parent().prev()[0];c.opts.showtimes&&c.opts.showtimes>0&&a(this).siblings(b.prototype.CURRENTFOCUS).show()});var o=k.parents('div[data-parent="#accordionAssignPart"]');o.attr("tabindex",0),o.on("keydown",function(a){l.isWriting()<=0&&l.getPairing()<=0||(32===a.which&&(a.preventDefault(),k.find("button"+b.prototype.PLAYPAUSEBUTTON).click()),66===a.which&&(a.preventDefault(),k.find("button"+b.prototype.PLAYPAUSEBUTTONBEFORE).click()),78===a.which&&(a.preventDefault(),h.pause(),m.notify("pause",h.currentTime),m.notify("dblclick")))}),l.notify("initeach","player",h)})};var c=function(b){var c=b.currentTime/b.xduration*100,e=a(b).next();c<=100.1&&e.find(".justwave_playhead").width(c+"%"),e.find(".justwave_curpos").text(d(b.currentTime))},d=function(a){var b=Math.floor(a/60),c=Math.floor(a%60);return isNaN(a)?"00:00":(b<10?"0":"")+b+":"+(c<10?"0":"")+c},e=function(a,b){b&&a.stop(!0,!0).hide(),a.is(":visible")||a.fadeIn(300,function(){a.fadeOut(7e3,"swing")})},f=function(b){var c=a(b).next();c.find(".justwave_wave").width(0).attr("src",""),c.find(".justwave_progress").width(0).attr("src",""),c.width(b.opts.width).height(b.opts.height).css("background",b.opts.wave_color),b.opts.poster&&c.css("background-image","url("+b.opts.poster+")"),c.find(".justwave_playhead").css("background",b.opts.prog_color)},g=function(c){var d=a(c).next();d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").addClass("fa-play"),d.find(b.prototype.PLAYPAUSEBUTTON+" i.fa").removeClass("fa-pause")};return b.prototype.drawWaveDisplay=function(b){var c=this.assignpart;b.opts=this.getWaveOpts(b);var h=new Audio;a(h).on("loadedmetadata",function(){var h=a(b).next();f(b),g(b),a(b).attr("src")?b.opts.audio=a(b).attr("src"):b.opts.audio=b.currentSrc;var i=h.find(".justwave_songname").css("font-size",b.opts.namesize+"px").text(decodeURIComponent(b.opts.audio.replace(/.+[\\\/]/,"")));b.opts.showname&&b.opts.showname>0&&e(i,!0),+b.opts.nowaves||a.ajax(b.opts.ajax,{dataType:"json",type:"POST",data:b.opts}).done(function(e){var f=a(b).next(),g=f.find(".justwave_wave"),h=f.find(".justwave_progress");"ok"===e.status&&(g.width(b.opts.width),h.width(b.opts.width),f.css("background",""),f.find(".justwave_playhead").css("background",""),b.opts.poster&&f.css("background-image","url("+b.opts.poster+")"),g.attr("src",e.waveurl),b.opts.wave_color===b.opts.prog_color?h.attr("src",e.waveurl):h.attr("src",e.progressurl)),b.xduration=parseFloat(e.duration),b.xduration||(b.xduration=b.duration),b.xduration&&!b.duration&&(b.duration=e.duration),f.find(".justwave_duration").text(d(b.xduration));var i=a(f).prev()[0];i.xduration=b.xduration,i.duration=b.duration,c&&c.notify("loadedmetadata",b)})}),h.src=a(b).attr("src")},b});
\ No newline at end of file
......@@ -135,8 +135,6 @@ define(['jquery', 'mod_audioannotation/justWave', 'mod_audioannotation/editor',
this.initTrigger();
//init right context menu
Controler.rightMenu = new RightMenu({'controler': this});
//init global display
this.initDisplay();
}
/*************
......
......@@ -28,7 +28,7 @@ require_once("$CFG->libdir/formslib.php");
use moodleform;
/**
* Form to edit feedback to an assignement
* Form to notify teacher for a release
*
* @package mod_audioannotation
* @copyright 2019 Université de Lausanne
......
......@@ -28,7 +28,7 @@ require_once("$CFG->libdir/formslib.php");
use moodleform;
/**
* Form to edit feedback to an annotation
* Form to add a tag
*
* @package mod_audioannotation
* @copyright 2018 Université de Lausanne
......
......@@ -28,7 +28,7 @@ require_once("$CFG->libdir/formslib.php");
use moodleform;
/**
* Form to edit feedback to an annotation
* Form to export a set of tags
*
* @package mod_audioannotation
* @copyright 2019 Université de Lausanne
......
......@@ -28,7 +28,7 @@ require_once("$CFG->libdir/formslib.php");
use moodleform;
/**
* Form to edit feedback to an annotation
* Form to edit tags set
*
* @package mod_audioannotation
* @copyright 2018 Université de Lausanne
......
......@@ -21,7 +21,7 @@ namespace mod_audioannotation\justWave;
* Internal library of functions for module audioannotation
*
* All the audioannotation specific functions, needed to implement the module
* logic, should go here. Never include this file from your lib.php!
* logic, should go here.
*
* @package mod_audioannotation
* @copyright 2018 Université de Lausanne
......
......@@ -40,7 +40,7 @@ class invalidatecache_task extends \core\task\scheduled_task {
}
/**
* Run forum cron.
* Run wavestorage cron.
*/
public function execute() {
$wavecache = \cache::make('mod_audioannotation', 'wavestorage');
......
This diff is collapsed.
......@@ -101,6 +101,7 @@ class audioanntation_external extends external_api {
/**
* Set standard error message
*
* @param string $content Message's specific text
* @return array The message error in an array
*/
public static function getMessageError($content = '') {
......
......@@ -23,11 +23,9 @@
* @copyright 2018 Université de Lausanne
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . "../../../config.php");
require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
$id = required_param('id', PARAM_INT); // Course module ID.
$itemnumber = optional_param('itemnumber', 0, PARAM_INT); // Item number may be != 0 for activities that allow more than one grade per user.
$userid = optional_param('userid', 0, PARAM_INT); // Graded user ID (optional).
$cm = get_coursemodule_from_id('audioannotation', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
......
......@@ -25,72 +25,15 @@
* @copyright 2018 Université de Lausanne
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Replace audioannotation with the name of your module and remove this line.
require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
require_once(dirname(__FILE__) . '/lib.php');
$id = required_param('id', PARAM_INT); // Course.
$id = required_param('id', PARAM_INT); // Course module ID.
$cm = get_coursemodule_from_id('audioannotation', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
require_login($course, false, $cm);
require_course_login($course);
$PAGE->set_url('/mod/audioannotation/grade.php', array('id' => $cm->id));
$params = array(
'context' => context_course::instance($course->id)
);
$event = \mod_audioannotation\event\course_module_instance_list_viewed::create($params);
$event->add_record_snapshot('course', $course);
$event->trigger();
$strname = get_string('modulenameplural', AUDIOANNOT_MODNAME_COMPLETE);
$PAGE->set_url('/mod/audioannotation/index.php', array('id' => $id));
$PAGE->navbar->add($strname);
$PAGE->set_title("$course->shortname: $strname");
$PAGE->set_heading($course->fullname);
$PAGE->set_pagelayout('incourse');
echo $OUTPUT->header();
echo $OUTPUT->heading($strname);
if (!$audioannotations = get_all_instances_in_course(MODNAME, $course)) {
notice(get_string('noaudioannotations', MODNAME), new moodle_url('/course/view.php', array('id' => $course->id)));
}
$usesections = course_format_uses_sections($course->format);
$table = new html_table();
$table->attributes['class'] = 'generaltable mod_index';
if ($usesections) {
$strsectionname = get_string('sectionname', 'format_' . $course->format);
$table->head = array($strsectionname, $strname);
$table->align = array('center', 'left');
} else {
$table->head = array($strname);
$table->align = array('left');
}
$modinfo = get_fast_modinfo($course);
$currentsection = '';
foreach ($modinfo->instances[MODNAME] as $cm) {
$row = array();
if ($usesections && $cm->sectionnum !== $currentsection) {
if ($cm->sectionnum) {
$row[] = get_section_name($course, $cm->sectionnum);
}
if ($currentsection !== '') {
$table->data[] = 'hr';
}
$currentsection = $cm->sectionnum;
}
$class = $cm->visible ? null : array('class' => 'dimmed');
$row[] = html_writer::link(new moodle_url('view.php', array('id' => $cm->id)), $cm->get_formatted_name(), $class);
$table->data[] = $row;
}
echo html_writer::table($table);
echo $OUTPUT->footer();
redirect('view.php?id=' . $cm->id);
......@@ -17,10 +17,12 @@
/**
* Syntax: justWave/justwave.ajax.php
* API JustWave
*
* @package mod_audioannotation
* @copyright 2018 Université de Lausanne
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* inspred by https://github.com/beotiger
*/
......
......@@ -189,7 +189,6 @@ $string['notify_teacher'] = 'Notify teachers';
$string['sendnotification'] = 'Send';
$string['message_webrtc'] = 'WEB RTC is not support on your browser. Please try with an other browser, or active web RTC support, to allow recording tools.';
$string['message_microphone'] = 'No available microphone.';
$string['audioannotation'] = 'Audio annotation';
$string['pluginadministration'] = 'Audio annotation administration';
$string['pluginname'] = 'Audio annotation';
......@@ -190,7 +190,6 @@ $string['notify_teacher'] = 'Notifier l\'équipe enseignante';
$string['sendnotification'] = 'Envoyer';
$string['message_webrtc'] = 'Web RTC n\'est pas supporté dans votre navigateur. Essayez avec un autre navigateur, ou activer la prise en charge du Web RTC pour activer les outils d\'enregistrement.';
$string['message_microphone'] = 'Pas de microphone disponible ou reconnu.';
$string['audioannotation'] = 'Audio annotation';
$string['pluginadministration'] = 'Audio annotation administration';
$string['pluginname'] = 'Audio annotation';
......@@ -83,15 +83,6 @@ function audioannotation_add_instance(stdClass $audioannotation, mod_audioannota
$audioannotation->id = $DB->insert_record(AUDIOANNOT_MODNAME, $audioannotation);
//enregistrement des tags
/*if ($audioannotation->tagids) {
foreach ($audioannotation->tagids as $tagtmp) {
if (isset($tagtmp) && strlen($tagtmp) > 0) {
editor::addCategory($audioannotation, $tagtmp);
}
}
}*/
//enregistrement des fichiers annexes
$formData = $mform->get_data();
if ($formData) {
......@@ -543,21 +534,6 @@ function audioannotation_pluginfile($course, $cm, $context, $filearea, array $ar
}
/* Navigation API */
/**
* Extends the global navigation tree by adding audioannotation nodes if there is a relevant content
*
* This can be called by an AJAX request so do not rely on $PAGE as it might not be set up properly.
*
* @param navigation_node $navref An object representing the navigation tree node of the audioannotation module instance
* @param stdClass $course current course record
* @param stdClass $module current audioannotation instance record
* @param cm_info $cm course module information
*/
/* function audioannotation_extend_navigation(navigation_node $navref, stdClass $course, stdClass $module, cm_info $cm) {
// TODO Delete this function and its docblock, or implement it.
} */
/**
* Extends the settings navigation with the audioannotation settings
*
......@@ -647,7 +623,6 @@ function mod_audioannotation_output_fragment_annotation($args) {
}
require_once('locallib.php');
//if (has_capability('assignfeedback/editpdfplus:managetools', $context, null, false)) {
$course = $DB->get_record(COURSELIB, array('id' => $courseid), '*', MUST_EXIST);
$audioannotationlib = new audioannotation_assignement($context, $course);
......@@ -655,6 +630,6 @@ function mod_audioannotation_output_fragment_annotation($args) {
if ($action) {
return $audioannotationlib->getAnnotationForm($action, $args);
}
//}
return null;
}
......@@ -89,9 +89,11 @@ class audioannotation_assignement {
/**
* Get an eval submission view for a given assignement
* @global $audioannotation
* @global $DB
* @param renderer $renderer
* @param widget $baseWidget
* @param assignement $devoir
* @param boolean $pairing pairing mode
* @return html
*/
private function getViewEvalSubmission($renderer, $baseWidget, $devoir, $pairing = false) {
......@@ -109,7 +111,6 @@ class audioannotation_assignement {
$formAssign->id = "audioannotation_assign_save";
$formAssign->action = "savefeedback";
//$formAssign->assignid = $devoir->id;
$widget->feedbackform = $formAssign;
$widget->user = $DB->get_record('user', array('id' => $devoir->user), '*', MUST_EXIST);
......@@ -129,8 +130,10 @@ class audioannotation_assignement {
/**
* Get a view with the overview of the all assignements for a given activity
* @global $audioannotation
* @global $DB
* @param renderer $renderer
* @param widget $widget
* @param int $pairing
* @return html
*/
private function getViewListSubmissions($renderer, $widget, $pairing = false) {
......@@ -185,6 +188,14 @@ class audioannotation_assignement {
return $renderer->render_student_pairinglist($widget);
}
/**
* Save student answer, and send a message to teacher team
* @global $audioannotation
* @global $USER
* @param assignement $devoir
* @param moodleform $formAssign
* @return boolean
*/
private function saveStudentFeedback($devoir, $formAssign) {
global $audioannotation, $USER;
$formData = $formAssign->get_data();
......@@ -221,9 +232,6 @@ class audioannotation_assignement {
$this->importGradeLib();
//$grading_info = grade_get_grades($this->course, 'mod', AUDIOANNOT_MODNAME, $audioannotation->id, $devoir->user);
//$gradeRef = $grading_info->items[0]->grades[$devoir->user];
$formData = $formAssign->get_data();
$grade = new stdClass();
......@@ -275,6 +283,7 @@ class audioannotation_assignement {
* @global $PAGE
* @param String $action
* @param int $assign assignement id
* @param tag_model $model
* @return html
*/
public function viewTeacher($action = null, $assign = null, $model = null) {
......@@ -327,6 +336,11 @@ class audioannotation_assignement {
return $this->getViewListSubmissions($renderer, $widget);
}
/**
* Save a set of tags
* @global $audioannotation
* @return boolean
*/
private function saveTags() {
global $audioannotation;
$tags = editor::getCategories($audioannotation->id);
......@@ -369,6 +383,14 @@ class audioannotation_assignement {
return true;
}
/**
* Create a view to manage tags
* @global $audioannotation
* @global $USER
* @param renderer $renderer
* @param object $widget
* @return html
*/
private function manageTags($renderer, $widget) {
global $audioannotation, $USER;
$tags = editor::getCategories($audioannotation->id);
......@@ -391,6 +413,11 @@ class audioannotation_assignement {
return $renderer->render_teacher_managetags($widget);
}
/**
* Save a new tag
* @global $audioannotation
* @return boolean
*/
private function saveAddTag() {
global $audioannotation;
$formTag = new tag_add_form();
......@@ -413,6 +440,12 @@ class audioannotation_assignement {
return true;
}
/**
* Create a html form to add a new tag
* @param renderer $renderer
* @param object $widget
* @return html
*/
private function addTag($renderer, $widget) {
$formTag = new tag_add_form();
$formTag->set_data(array('id' => $this->cm->id));
......@@ -422,6 +455,12 @@ class audioannotation_assignement {
return $renderer->render_teacher_addtag($widget);
}
/**
* Save a set of tag into a model for the current user
* @global $audioannotation
* @global $USER
* @return boolean
*/
private function saveExportTags() {
global $audioannotation, $USER;
$formTag = new tag_export_form();
......@@ -446,12 +485,19 @@ class audioannotation_assignement {
$tagForModel->id = null;
$tagForModel->audioannotation = null;
$tagForModel->model = $modeltag->id;
$id = editor::addCategoryObject($tagForModel);
editor::addCategoryObject($tagForModel);
}
return true;
}
/**
* Create a form to allow user to export a new set of tags as model
* @global $audioannotation
* @param renderer $renderer