diff --git a/amd/build/videotime.min.js b/amd/build/videotime.min.js index f1425660..e5ce6310 100644 --- a/amd/build/videotime.min.js +++ b/amd/build/videotime.min.js @@ -3,6 +3,6 @@ * @copyright 2021 bdecent gmbh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("mod_videotime/videotime",["jquery","mod_videotime/player","core/ajax","core/config","core/log","core/templates","core/notification"],(function($,Vimeo,Ajax,Config,Log,Templates,Notification){let VideoTime=function(elementId,cmId,hasPro,interval,instance){this.elementId=elementId,this.cmId=cmId,this.hasPro=hasPro,this.interval=interval,this.player=null,this.resumeTime=null,this.session=null,this.instance=instance,this.played=!1,this.playing=!1,this.time=0,this.percent=0,this.currentTime=0,this.playbackRate=1,this.plugins=[],hasPro&&$("body").hasClass("path-course-view")&&!$("body").hasClass("vtinit")&&($("body").addClass("vtinit"),$(document).on("focus","body",this.initializeNewInstances.bind(this))),this.modulecount=$("body .activity.videotime").length};return VideoTime.prototype.getCmId=function(){return this.cmId},VideoTime.prototype.registerPlugin=function(plugin){this.plugins.push(plugin)},VideoTime.prototype.initialize=function(){let instance=this.instance;Log.debug("Initializing Video Time "+this.elementId),Log.debug("Initializing Vimeo player with options:"),Log.debug(instance),this.player=new Vimeo(this.elementId,{autopause:Number(instance.autopause),autoplay:Number(instance.autoplay),background:Number(instance.background),byline:Number(instance.byline),color:instance.color,controls:Number(instance.controls),dnt:Number(instance.dnt),height:instance.height,loop:Number(instance.option_loop),maxheight:instance.maxheight,maxwidth:instance.maxwidth,muted:Number(instance.muted),portrait:instance.portrait,pip:Number(instance.pip),playsinline:instance.playsinline,responsive:Number(instance.responsive),speed:instance.speed,title:Number(instance.title),transparent:Number(instance.transparent),url:instance.vimeo_url,width:instance.width});let url=new URL(window.location.href),q=url.searchParams.get("q"),starttime=(url.searchParams.get("time")||"").match(/^([0-9]+:){0,2}([0-9]+)(\.[0-9]+)$/);starttime?this.setStartTime(starttime[0]).then((function(){return q&&window.find&&window.find(q),!0})).catch(Notification.exception):q&&window.find&&window.find(q),this.addListeners();for(let i=0;i(this.hasPro&&this.startWatchInterval(),this.view(),!0))),this.hasPro&&(this.player.on("loaded",(()=>!this.instance.resume_playback||!this.instance.resume_time||this.instance.resume_time<=0||this.getDuration().then((duration=>{let resumeTime=this.instance.resume_time;return resumeTime+1>=Math.floor(duration)&&(Log.debug("VIDEO_TIME video finished, resuming at start of video."),resumeTime=0),Log.debug("VIDEO_TIME duration is "+duration),Log.debug("VIDEO_TIME resuming at "+resumeTime),this.setCurrentPosition(resumeTime),!0})).fail(Notification.exception))),this.player.on("play",function(){this.playing=!0,Log.debug("VIDEO_TIME play")}.bind(this)),this.player.on("playing",function(){this.playing=!0,Log.debug("VIDEO_TIME playing")}.bind(this)),this.player.on("pause",function(){this.playing=!1,Log.debug("VIDEO_TIME pause")}.bind(this)),this.player.on("stalled",function(){this.playing=!1,Log.debug("VIDEO_TIME stalled")}.bind(this)),this.player.on("suspend",function(){this.playing=!1,Log.debug("VIDEO_TIME suspend")}.bind(this)),this.player.on("abort",function(){this.playing=!1,Log.debug("VIDEO_TIME abort")}.bind(this)),this.player.getPlaybackRate().then(function(playbackRate){this.playbackRate=playbackRate}.bind(this)).catch(Notification.exception),this.player.on("playbackratechange",function(event){this.playbackRate=event.playbackRate}.bind(this)),this.player.on("timeupdate",function(event){this.percent=event.percent,this.currentTime=event.seconds,event.seconds===event.duration&&this.plugins.forEach((plugin=>{"function"==typeof plugin.setCurrentTime&&plugin.getSessions().then((session=>(plugin.setCurrentTime(session.id,event.seconds),session))).catch(Notification.exception)}))}.bind(this)),this.player.on("ended",this.handleEnd.bind(this)),this.player.on("pause",this.handlePause.bind(this)))):Log.debug("Player was not properly initialized for course module "+this.cmId)},VideoTime.prototype.handlePause=function(){this.plugins.forEach((plugin=>{"function"==typeof plugin.handlePause&&plugin.handlePause()}))},VideoTime.prototype.handleEnd=function(){this.playing=!1,Log.debug("VIDEO_TIME ended"),this.plugins.length>2?this.plugins.forEach((plugin=>{"function"==typeof plugin.handleEnd&&plugin.handleEnd()})):this.getSession().then(function(session){this.setSessionState(session.id,1).then((()=>this.setPercent(session.id,1))).then((()=>this.setCurrentTime(session.id,this.currentTime))).then((()=>this.getNextActivityButtonData(session.id).then((response=>{let data=JSON.parse(response.data);if(data.instance&&parseInt(data.instance.next_activity_auto)&&!data.is_restricted&&data.hasnextcm){let link=$('.aalink[href="'+data.nextcm_url+'"] img').first();$(".path-course-view").length&&link?link.click():window.location.href=data.nextcm_url}return Templates.render("videotime/next_activity_button",JSON.parse(response.data)).then((function(html){return $("#next-activity-button").html(html),!0}))})))).catch(Notification.exception)}.bind(this)).catch(Notification.exception)},VideoTime.prototype.startWatchInterval=function(){this.plugins.forEach((plugin=>{"function"==typeof plugin.startWatchInterval&&(this.watchInterval=!0,plugin.startWatchInterval())})),this.watchInterval||(this.watchInterval=setInterval(function(){this.playing&&(this.time+=this.playbackRate,this.getSession().then(function(session){return this.time%this.interval==0&&(Log.debug("VIDEO_TIME watch_time: "+this.time+". percent: "+this.percent),this.recordWatchTime(session.id,this.time),this.setPercent(session.id,this.percent),this.setCurrentTime(session.id,this.currentTime)),!0}.bind(this)).catch(Notification.exception))}.bind(this),1e3))},VideoTime.prototype.setSessionState=function(sessionId,state){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_set_session_state"),data.set("state",state),data.set("session_id",sessionId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_set_session_state",args:{session_id:sessionId,state:state},fail:Notification.exception}])[0]},VideoTime.prototype.setCurrentTime=function(sessionId,currentTime){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_set_session_current_time"),data.set("current_time",currentTime),data.set("session_id",sessionId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_set_session_current_time",args:{session_id:sessionId,current_time:currentTime},fail:Notification.exception}])[0]},VideoTime.prototype.setPercent=function(sessionId,percent){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_set_percent"),data.set("percent",percent),data.set("session_id",sessionId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_set_percent",args:{session_id:sessionId,percent:percent},fail:Notification.exception}])[0]},VideoTime.prototype.recordWatchTime=function(sessionId,time){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_record_watch_time"),data.set("session_id",sessionId),data.set("time",time),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_record_watch_time",args:{session_id:sessionId,time:time},fail:Notification.exception}])[0]},VideoTime.prototype.getNextActivityButtonData=function(sessionId){return this.instance.token?Promise.resolve({data:"{}"}):Ajax.call([{methodname:"videotimeplugin_pro_get_next_activity_button_data",args:{session_id:sessionId}}])[0]},VideoTime.prototype.getInstance=function(){return this.instance?Promise.resolve(this.instance):Ajax.call([{methodname:"mod_videotime_get_videotime",args:{cmid:this.cmId},done:response=>(this.instance=response,this.instance),fail:Notification.exception}])[0]},VideoTime.prototype.getResumeTime=function(){return this.resumeTime?Promise.resolve(this.resumeTime):Ajax.call([{methodname:"videotimeplugin_pro_get_resume_time",args:{cmid:this.cmId},done:response=>(this.resumeTime=response.seconds,this.resumeTime),fail:Notification.exception}])[0]},VideoTime.prototype.getSession=function(){if(this.instance.token){if(!this.session){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_get_new_session"),data.set("cmid",this.cmId),this.session=fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return this.session}return this.session||(this.session=Ajax.call([{methodname:"videotimeplugin_pro_get_new_session",args:{cmid:this.cmId},fail:Notification.exception}])[0]),this.session},VideoTime.prototype.setStartTime=function(starttime){let time=starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\.[0-9]+))/);return time&&(this.resumeTime=3600*Number(time[3]||0)+60*Number(time[5]||0)+Number(time[6]),this.currentTime(this.resumeTime)),this.player.getCurrentTime()},VideoTime.prototype.view=function(){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","mod_videotime_view_videotime"),data.set("cmid",this.cmId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"mod_videotime_view_videotime",args:{cmid:this.cmId},fail:Notification.exception}])[0]},VideoTime.prototype.initializeNewInstances=function(){this.modulecount!=$("body .activity.videotime").length&&(this.modulecount=$("body .activity.videotime").length,$("body .activity.videotime").each(function(index,module){if(!$(module).find(".instancename").length&&$(module).find(".vimeo-embed").length&&!$(module).find(".vimeo-embed iframe").length){let instance={cmid:Number($(module).attr("id").replace("module-","")),haspro:!0,interval:this.interval,uniqueid:$(module).find(".vimeo-embed").first().attr("id").replace("vimeo-embed-","")};Templates.render("mod_videotime/videotime_instance",{instance:instance}).then((function(html,js){return Templates.runTemplateJS(js),!0})).fail(Notification.exception)}}.bind(this)))},VideoTime.prototype.getPlaybackRate=function(){return this.player.getPlaybackRate()},VideoTime.prototype.getDuration=function(){return this.player.getDuration()},VideoTime.prototype.setCurrentPosition=function(secs){return this.player.setCurrentTime(secs)},VideoTime.prototype.getCurrentPosition=function(){return this.player.getCurrentTime()},VideoTime})); +define("mod_videotime/videotime",["jquery","mod_videotime/player","core/ajax","core/config","core/log","core/templates","core/notification"],(function($,Vimeo,Ajax,Config,Log,Templates,Notification){let VideoTime=function(elementId,cmId,hasPro,interval,instance){this.elementId=elementId,this.cmId=cmId,this.hasPro=hasPro,this.interval=interval,this.player=null,this.resumeTime=null,this.session=null,this.instance=instance,this.played=!1,this.playing=!1,this.time=0,this.percent=0,this.currentTime=0,this.playbackRate=1,this.plugins=[],hasPro&&$("body").hasClass("path-course-view")&&!$("body").hasClass("vtinit")&&($("body").addClass("vtinit"),$(document).on("focus","body",this.initializeNewInstances.bind(this))),this.modulecount=$("body .activity.videotime").length};return VideoTime.prototype.getCmId=function(){return this.cmId},VideoTime.prototype.registerPlugin=function(plugin){this.plugins.push(plugin)},VideoTime.prototype.initialize=function(){let instance=this.instance;Log.debug("Initializing Video Time "+this.elementId),Log.debug("Initializing Vimeo player with options:"),Log.debug(instance),this.player=new Vimeo(this.elementId,{autopause:Number(instance.autopause),autoplay:Number(instance.autoplay),background:Number(instance.background),byline:Number(instance.byline),color:instance.color,controls:Number(instance.controls),dnt:Number(instance.dnt),height:instance.height,loop:Number(instance.option_loop),maxheight:instance.maxheight,maxwidth:instance.maxwidth,muted:Number(instance.muted),portrait:instance.portrait,pip:Number(instance.pip),playsinline:instance.playsinline,responsive:Number(instance.responsive),speed:instance.speed,title:Number(instance.title),transparent:Number(instance.transparent),url:instance.vimeo_url,width:instance.width});let url=new URL(window.location.href),q=url.searchParams.get("q"),starttime=(url.searchParams.get("time")||"").match(/^([0-9]+:){0,2}([0-9]+)(\.[0-9]+)$/);starttime?this.setStartTime(starttime[0]).then((function(){return q&&window.find&&window.find(q),!0})).catch(Notification.exception):q&&window.find&&window.find(q),this.addListeners();for(let i=0;i(this.hasPro&&this.startWatchInterval(),this.view(),!0))),this.hasPro&&(this.player.on("loaded",(()=>!this.instance.resume_playback||!this.instance.resume_time||this.instance.resume_time<=0||this.getDuration().then((duration=>{let resumeTime=this.instance.resume_time;return resumeTime+1>=Math.floor(duration)&&(Log.debug("VIDEO_TIME video finished, resuming at start of video."),resumeTime=0),Log.debug("VIDEO_TIME duration is "+duration),Log.debug("VIDEO_TIME resuming at "+resumeTime),this.setCurrentPosition(resumeTime),!0})).fail(Notification.exception))),this.player.on("play",function(){this.playing=!0,Log.debug("VIDEO_TIME play")}.bind(this)),this.player.on("playing",function(){this.playing=!0,Log.debug("VIDEO_TIME playing")}.bind(this)),this.player.on("pause",function(){this.playing=!1,Log.debug("VIDEO_TIME pause")}.bind(this)),this.player.on("stalled",function(){this.playing=!1,Log.debug("VIDEO_TIME stalled")}.bind(this)),this.player.on("suspend",function(){this.playing=!1,Log.debug("VIDEO_TIME suspend")}.bind(this)),this.player.on("abort",function(){this.playing=!1,Log.debug("VIDEO_TIME abort")}.bind(this)),this.player.getPlaybackRate().then(function(playbackRate){this.playbackRate=playbackRate}.bind(this)).catch(Notification.exception),this.player.on("playbackratechange",function(event){this.playbackRate=event.playbackRate}.bind(this)),this.player.on("timeupdate",function(event){this.percent=event.percent,this.currentTime=event.seconds,event.seconds===event.duration&&this.plugins.forEach((plugin=>{"function"==typeof plugin.setCurrentTime&&plugin.getSessions().then((session=>(plugin.setCurrentTime(session.id,event.seconds),session))).catch(Notification.exception)}))}.bind(this)),this.player.on("ended",this.handleEnd.bind(this)),this.player.on("pause",this.handlePause.bind(this)))):Log.debug("Player was not properly initialized for course module "+this.cmId)},VideoTime.prototype.handlePause=function(){this.plugins.forEach((plugin=>{"function"==typeof plugin.handlePause&&plugin.handlePause()}))},VideoTime.prototype.handleEnd=function(){this.playing=!1,Log.debug("VIDEO_TIME ended"),this.plugins.length>2?this.plugins.forEach((plugin=>{"function"==typeof plugin.handleEnd&&plugin.handleEnd()})):this.getSession().then(function(session){this.setSessionState(session.id,1).then((()=>this.setPercent(session.id,1))).then((()=>this.setCurrentTime(session.id,this.currentTime))).then((()=>this.getNextActivityButtonData(session.id).then((response=>{let data=JSON.parse(response.data);if(data.instance&&parseInt(data.instance.next_activity_auto)&&!data.is_restricted&&data.hasnextcm){let link=$('.aalink[href="'+data.nextcm_url+'"] img').first();$(".path-course-view").length&&link?link.click():window.location.href=data.nextcm_url}return Templates.render("videotime/next_activity_button",JSON.parse(response.data)).then((function(html){return $("#next-activity-button").html(html),!0}))})))).catch(Notification.exception)}.bind(this)).catch(Notification.exception)},VideoTime.prototype.startWatchInterval=function(){this.plugins.forEach((plugin=>{"function"==typeof plugin.startWatchInterval&&(this.watchInterval=!0,plugin.startWatchInterval())})),this.watchInterval||(this.watchInterval=setInterval(function(){this.playing&&(this.time+=this.playbackRate,this.getSession().then(function(session){return this.time/this.playbackRate%this.interval==0&&(Log.debug("VIDEO_TIME watch_time: "+this.time+". percent: "+this.percent),this.recordWatchTime(session.id,this.time),this.setPercent(session.id,this.percent),this.setCurrentTime(session.id,this.currentTime)),!0}.bind(this)).catch(Notification.exception))}.bind(this),1e3))},VideoTime.prototype.setSessionState=function(sessionId,state){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_set_session_state"),data.set("state",state),data.set("session_id",sessionId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_set_session_state",args:{session_id:sessionId,state:state},fail:Notification.exception}])[0]},VideoTime.prototype.setCurrentTime=function(sessionId,currentTime){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_set_session_current_time"),data.set("current_time",currentTime),data.set("session_id",sessionId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_set_session_current_time",args:{session_id:sessionId,current_time:currentTime},fail:Notification.exception}])[0]},VideoTime.prototype.setPercent=function(sessionId,percent){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_set_percent"),data.set("percent",percent),data.set("session_id",sessionId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_set_percent",args:{session_id:sessionId,percent:percent},fail:Notification.exception}])[0]},VideoTime.prototype.recordWatchTime=function(sessionId,time){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_record_watch_time"),data.set("session_id",sessionId),data.set("time",time),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"videotimeplugin_pro_record_watch_time",args:{session_id:sessionId,time:time},fail:Notification.exception}])[0]},VideoTime.prototype.getNextActivityButtonData=function(sessionId){return this.instance.token?Promise.resolve({data:"{}"}):Ajax.call([{methodname:"videotimeplugin_pro_get_next_activity_button_data",args:{session_id:sessionId}}])[0]},VideoTime.prototype.getInstance=function(){return this.instance?Promise.resolve(this.instance):Ajax.call([{methodname:"mod_videotime_get_videotime",args:{cmid:this.cmId},done:response=>(this.instance=response,this.instance),fail:Notification.exception}])[0]},VideoTime.prototype.getResumeTime=function(){return this.resumeTime?Promise.resolve(this.resumeTime):Ajax.call([{methodname:"videotimeplugin_pro_get_resume_time",args:{cmid:this.cmId},done:response=>(this.resumeTime=response.seconds,this.resumeTime),fail:Notification.exception}])[0]},VideoTime.prototype.getSession=function(){if(this.instance.token){if(!this.session){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","videotimeplugin_pro_get_new_session"),data.set("cmid",this.cmId),this.session=fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return this.session}return this.session||(this.session=Ajax.call([{methodname:"videotimeplugin_pro_get_new_session",args:{cmid:this.cmId},fail:Notification.exception}])[0]),this.session},VideoTime.prototype.setStartTime=function(starttime){let time=starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\.[0-9]+))/);return time&&(this.resumeTime=3600*Number(time[3]||0)+60*Number(time[5]||0)+Number(time[6]),this.currentTime(this.resumeTime)),this.player.getCurrentTime()},VideoTime.prototype.view=function(){if(this.instance.token){const url=new URL(Config.wwwroot+"/webservice/rest/server.php"),data=url.searchParams;return data.set("wstoken",this.instance.token),data.set("moodlewsrestformat","json"),data.set("wsfunction","mod_videotime_view_videotime"),data.set("cmid",this.cmId),fetch(url).then((response=>(response.ok||Notification.exeption("Web service error"),response.json())))}return Ajax.call([{methodname:"mod_videotime_view_videotime",args:{cmid:this.cmId},fail:Notification.exception}])[0]},VideoTime.prototype.initializeNewInstances=function(){this.modulecount!=$("body .activity.videotime").length&&(this.modulecount=$("body .activity.videotime").length,$("body .activity.videotime").each(function(index,module){if(!$(module).find(".instancename").length&&$(module).find(".vimeo-embed").length&&!$(module).find(".vimeo-embed iframe").length){let instance={cmid:Number($(module).attr("id").replace("module-","")),haspro:!0,interval:this.interval,uniqueid:$(module).find(".vimeo-embed").first().attr("id").replace("vimeo-embed-","")};Templates.render("mod_videotime/videotime_instance",{instance:instance}).then((function(html,js){return Templates.runTemplateJS(js),!0})).fail(Notification.exception)}}.bind(this)))},VideoTime.prototype.getPlaybackRate=function(){return this.player.getPlaybackRate()},VideoTime.prototype.getDuration=function(){return this.player.getDuration()},VideoTime.prototype.setCurrentPosition=function(secs){return this.player.setCurrentTime(secs)},VideoTime.prototype.getCurrentPosition=function(){return this.player.getCurrentTime()},VideoTime})); //# sourceMappingURL=videotime.min.js.map \ No newline at end of file diff --git a/amd/build/videotime.min.js.map b/amd/build/videotime.min.js.map index ed08b2dd..df999937 100644 --- a/amd/build/videotime.min.js.map +++ b/amd/build/videotime.min.js.map @@ -1 +1 @@ -{"version":3,"file":"videotime.min.js","sources":["../src/videotime.js"],"sourcesContent":["/*\n * @package mod_videotime\n * @copyright 2021 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * @module mod_videotime/videotime\n */\ndefine([\n 'jquery',\n 'mod_videotime/player',\n 'core/ajax',\n 'core/config',\n 'core/log',\n 'core/templates',\n 'core/notification'\n], function($, Vimeo, Ajax, Config, Log, Templates, Notification) {\n let VideoTime = function(elementId, cmId, hasPro, interval, instance) {\n this.elementId = elementId;\n this.cmId = cmId;\n this.hasPro = hasPro;\n this.interval = interval;\n this.player = null;\n this.resumeTime = null;\n this.session = null;\n this.instance = instance;\n\n this.played = false;\n\n this.playing = false;\n this.time = 0;\n this.percent = 0;\n this.currentTime = 0;\n this.playbackRate = 1;\n\n this.plugins = [];\n\n if (hasPro && $('body').hasClass('path-course-view') && !$('body').hasClass('vtinit')) {\n $('body').addClass('vtinit');\n $(document).on('focus', 'body', this.initializeNewInstances.bind(this));\n }\n this.modulecount = $('body .activity.videotime').length;\n };\n\n /**\n * Get course module ID of this VideoTime instance.\n *\n * @return {int}\n */\n VideoTime.prototype.getCmId = function() {\n return this.cmId;\n };\n\n /**\n * Register a plugin to hook into VideoTime functionality.\n *\n * @param {VideoTimePlugin} plugin\n */\n VideoTime.prototype.registerPlugin = function(plugin) {\n this.plugins.push(plugin);\n };\n\n VideoTime.prototype.initialize = function() {\n let instance = this.instance;\n Log.debug('Initializing Video Time ' + this.elementId);\n\n Log.debug('Initializing Vimeo player with options:');\n Log.debug(instance);\n this.player = new Vimeo(this.elementId, {\n autopause: Number(instance.autopause),\n autoplay: Number(instance.autoplay),\n background: Number(instance.background),\n byline: Number(instance.byline),\n color: instance.color,\n controls: Number(instance.controls),\n dnt: Number(instance.dnt),\n height: instance.height,\n loop: Number(instance.option_loop),\n maxheight: instance.maxheight,\n maxwidth: instance.maxwidth,\n muted: Number(instance.muted),\n portrait: instance.portrait,\n pip: Number(instance.pip),\n playsinline: instance.playsinline,\n responsive: Number(instance.responsive),\n speed: instance.speed,\n title: Number(instance.title),\n transparent: Number(instance.transparent),\n url: instance.vimeo_url,\n width: instance.width\n });\n\n let url = new URL(window.location.href),\n q = url.searchParams.get('q'),\n starttime = (url.searchParams.get('time') || '').match(/^([0-9]+:){0,2}([0-9]+)(\\.[0-9]+)$/);\n if (starttime) {\n this.setStartTime(starttime[0]).then(function() {\n if (q && window.find) {\n window.find(q);\n }\n return true;\n }).catch(Notification.exception);\n } else if (q && window.find) {\n window.find(q);\n }\n\n this.addListeners();\n\n for (let i = 0; i < this.plugins.length; i++) {\n const plugin = this.plugins[i];\n plugin.initialize(this, instance);\n }\n\n return true;\n };\n\n /**\n * Get Vimeo player object.\n *\n * @returns {Vimeo}\n */\n VideoTime.prototype.getPlayer = function() {\n return this.player;\n };\n\n /**\n * Register player events to respond to user interaction and play progress.\n */\n VideoTime.prototype.addListeners = function() {\n if (!this.player) {\n Log.debug('Player was not properly initialized for course module ' + this.cmId);\n return;\n }\n\n // If this is a tab play set time cues and listener.\n $($('#' + this.elementId).closest('.videotimetabs')).each(function(i, tabs) {\n $(tabs).find('[data-action=\"cue\"]').each(function(index, anchor) {\n let starttime = anchor.getAttribute('data-start'),\n time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.player.addCuePoint(\n 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]),\n {\n starttime: starttime\n }\n ).catch(Notification.exeception);\n }\n }.bind(this));\n\n this.player.on('cuepoint', function(event) {\n if (event.data.starttime) {\n $(tabs).find('.videotime-highlight').removeClass('videotime-highlight');\n $(tabs).find('[data-action=\"cue\"][data-start=\"' + event.data.starttime + '\"]')\n .closest('.row')\n .addClass('videotime-highlight');\n $('.videotime-highlight').each(function() {\n if (this.offsetTop) {\n this.parentNode.scrollTo({\n top: this.offsetTop - 50,\n left: 0,\n behavior: 'smooth'\n });\n }\n });\n }\n });\n }.bind(this));\n\n // Fire view event in Moodle on first play only.\n this.player.on('play', () => {\n if (this.hasPro) {\n this.startWatchInterval();\n }\n this.view();\n return true;\n });\n\n // Features beyond this point are for pro only.\n if (!this.hasPro) {\n return;\n }\n\n // If resume is present force seek the player to that point.\n this.player.on(\"loaded\", () => {\n if (!this.instance.resume_playback || !this.instance.resume_time || this.instance.resume_time <= 0) {\n return true;\n }\n\n return this.getDuration().then((duration) => {\n let resumeTime = this.instance.resume_time;\n // Duration is often a little greater than a resume time at the end of the video.\n // A user may have watched 100 seconds when the video ends, but the duration may be\n // 100.56 seconds. BUT, sometimes the duration is rounded depending on when the\n // video loads, so it may be 101 seconds. Hence the +1 and Math.floor usage.\n if (resumeTime + 1 >= Math.floor(duration)) {\n Log.debug(\n \"VIDEO_TIME video finished, resuming at start of video.\"\n );\n resumeTime = 0;\n }\n Log.debug(\"VIDEO_TIME duration is \" + duration);\n Log.debug(\"VIDEO_TIME resuming at \" + resumeTime);\n this.setCurrentPosition(resumeTime);\n return true;\n }).fail(Notification.exception);\n });\n\n // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function.\n\n // Catch all events where video plays.\n this.player.on('play', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME play');\n }.bind(this));\n this.player.on('playing', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME playing');\n }.bind(this));\n\n // Catch all events where video stops.\n this.player.on('pause', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME pause');\n }.bind(this));\n this.player.on('stalled', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME stalled');\n }.bind(this));\n this.player.on('suspend', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME suspend');\n }.bind(this));\n this.player.on('abort', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME abort');\n }.bind(this));\n\n this.player.getPlaybackRate().then(function(playbackRate) {\n this.playbackRate = playbackRate;\n }.bind(this)).catch(Notification.exception);\n\n this.player.on('playbackratechange', function(event) {\n this.playbackRate = event.playbackRate;\n }.bind(this));\n\n // Always update internal values for percent and current time watched.\n this.player.on('timeupdate', function(event) {\n this.percent = event.percent;\n this.currentTime = event.seconds;\n if (event.seconds === event.duration) {\n this.plugins.forEach(plugin => {\n if (typeof plugin.setCurrentTime == 'function') {\n plugin.getSessions().then(session => {\n plugin.setCurrentTime(session.id, event.seconds);\n return session;\n }).catch(Notification.exception);\n }\n });\n }\n }.bind(this));\n\n // Initiate video finish procedure.\n this.player.on('ended', this.handleEnd.bind(this));\n this.player.on('pause', this.handlePause.bind(this));\n };\n\n /**\n * Handle pause\n */\n VideoTime.prototype.handlePause = function() {\n this.plugins.forEach(plugin => {\n if (typeof plugin.handlePause == 'function') {\n plugin.handlePause();\n }\n });\n };\n\n /**\n * Start interval that will periodically record user progress via Ajax.\n */\n VideoTime.prototype.handleEnd = function() {\n this.playing = false;\n Log.debug('VIDEO_TIME ended');\n if (this.plugins.length > 2) {\n this.plugins.forEach(plugin => {\n if (typeof plugin.handleEnd == 'function') {\n plugin.handleEnd();\n }\n });\n } else {\n // This moved to pro plugin, but left for compatibility.\n this.getSession().then(function(session) {\n this.setSessionState(session.id, 1).then(() => {\n return this.setPercent(session.id, 1);\n }).then(() => {\n return this.setCurrentTime(session.id, this.currentTime);\n }).then(() => {\n return this.getNextActivityButtonData(session.id).then(response => {\n let data = JSON.parse(response.data);\n\n if (data.instance && parseInt(data.instance.next_activity_auto)) {\n if (!data.is_restricted && data.hasnextcm) {\n let link = $('.aalink[href=\"' + data.nextcm_url + '\"] img').first();\n if ($('.path-course-view').length && link) {\n link.click();\n } else {\n window.location.href = data.nextcm_url;\n }\n }\n }\n\n return Templates.render('videotime/next_activity_button', JSON.parse(response.data))\n .then(function(html) {\n $('#next-activity-button').html(html);\n return true;\n });\n });\n }).catch(Notification.exception);\n }.bind(this)).catch(Notification.exception);\n }\n };\n\n /**\n * Start interval that will periodically record user progress via Ajax.\n */\n VideoTime.prototype.startWatchInterval = function() {\n this.plugins.forEach(plugin => {\n if (typeof plugin.startWatchInterval == 'function') {\n this.watchInterval = true;\n plugin.startWatchInterval();\n }\n });\n if (this.watchInterval) {\n return;\n }\n\n this.watchInterval = setInterval(function() {\n if (this.playing) {\n this.time += this.playbackRate;\n\n this.getSession().then(function(session) {\n if (this.time % this.interval === 0) {\n Log.debug('VIDEO_TIME watch_time: ' + this.time + '. percent: ' + this.percent);\n this.recordWatchTime(session.id, this.time);\n this.setPercent(session.id, this.percent);\n this.setCurrentTime(session.id, this.currentTime);\n }\n return true;\n }.bind(this)).catch(Notification.exception);\n }\n }.bind(this), 1000);\n };\n\n /**\n * Set state on session.\n *\n * @param {int} sessionId\n * @param {int} state\n * @returns {Promise}\n */\n VideoTime.prototype.setSessionState = function(sessionId, state) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_set_session_state');\n data.set('state', state);\n data.set('session_id', sessionId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_state',\n args: {\"session_id\": sessionId, state: state},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Set current watch time for video. Used for resuming.\n *\n * @param {int} sessionId\n * @param {float} currentTime\n * @returns {Promise}\n */\n VideoTime.prototype.setCurrentTime = function(sessionId, currentTime) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_set_session_current_time');\n data.set('current_time', currentTime);\n data.set('session_id', sessionId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_current_time',\n args: {\"session_id\": sessionId, \"current_time\": currentTime},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Set video watch percentage for session.\n *\n * @param {int} sessionId\n * @param {float} percent\n * @returns {Promise}\n */\n VideoTime.prototype.setPercent = function(sessionId, percent) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_set_percent');\n data.set('percent', percent);\n data.set('session_id', sessionId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_percent',\n args: {\"session_id\": sessionId, percent: percent},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Record watch time for session.\n *\n * @param {int} sessionId\n * @param {float} time\n * @returns {Promise}\n */\n VideoTime.prototype.recordWatchTime = function(sessionId, time) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_record_watch_time');\n data.set('session_id', sessionId);\n data.set('time', time);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_record_watch_time',\n args: {\"session_id\": sessionId, time: time},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Get data for next activity button.\n *\n * @param {int} sessionId\n * @returns {Promise}\n */\n VideoTime.prototype.getNextActivityButtonData = function(sessionId) {\n if (this.instance.token) {\n // We do not support button in iframe.\n return Promise.resolve({data: '{}'});\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_get_next_activity_button_data',\n args: {\"session_id\": sessionId}\n }])[0];\n };\n\n /**\n * Get VideoTime instance for this course module.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getInstance = function() {\n if (this.instance) {\n return Promise.resolve(this.instance);\n }\n\n return Ajax.call([{\n methodname: 'mod_videotime_get_videotime',\n args: {cmid: this.cmId},\n done: (response) => {\n this.instance = response;\n return this.instance;\n },\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Get time to resume video as seconds.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getResumeTime = function() {\n if (this.resumeTime) {\n return Promise.resolve(this.resumeTime);\n }\n\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_get_resume_time',\n args: {cmid: this.cmId},\n done: (response) => {\n this.resumeTime = response.seconds;\n return this.resumeTime;\n },\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Get new or existing video viewing session.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getSession = function() {\n if (this.instance.token) {\n if (!this.session) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_get_new_session');\n data.set('cmid', this.cmId);\n this.session = fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n\n return this.session;\n }\n if (!this.session) {\n this.session = Ajax.call([{\n methodname: 'videotimeplugin_pro_get_new_session',\n args: {cmid: this.cmId},\n fail: Notification.exception\n }])[0];\n }\n return this.session;\n };\n\n /**\n * Parse start time and set player\n *\n * @param {string} starttime\n * @returns {Promise}\n */\n VideoTime.prototype.setStartTime = function(starttime) {\n let time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.resumeTime = 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]);\n this.currentTime(this.resumeTime);\n }\n return this.player.getCurrentTime();\n };\n\n /**\n * Log the user view of video.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.view = function() {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'mod_videotime_view_videotime');\n data.set('cmid', this.cmId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n\n }\n return Ajax.call([{\n methodname: 'mod_videotime_view_videotime',\n args: {cmid: this.cmId},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Initialize new labels and preview when editing\n */\n VideoTime.prototype.initializeNewInstances = function() {\n if (this.modulecount == $('body .activity.videotime').length) {\n return;\n }\n this.modulecount = $('body .activity.videotime').length;\n $('body .activity.videotime').each(function(index, module) {\n if (\n !$(module).find('.instancename').length\n && $(module).find('.vimeo-embed').length\n && !$(module).find('.vimeo-embed iframe').length\n ) {\n let instance = {\n cmid: Number($(module).attr('id').replace('module-', '')),\n haspro: true,\n interval: this.interval,\n uniqueid: $(module).find('.vimeo-embed').first().attr('id').replace('vimeo-embed-', '')\n };\n Templates.render('mod_videotime/videotime_instance', {\n instance: instance\n }).then(function(html, js) {\n Templates.runTemplateJS(js);\n return true;\n }).fail(Notification.exception);\n }\n }.bind(this));\n };\n\n /**\n * Get play back rate\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getPlaybackRate = function() {\n return this.player.getPlaybackRate();\n };\n\n /**\n * Get duration of video\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getDuration = function() {\n return this.player.getDuration();\n };\n\n /**\n * Set current time of player\n *\n * @param {float} secs time\n * @returns {Promise}\n */\n VideoTime.prototype.setCurrentPosition = function(secs) {\n return this.player.setCurrentTime(secs);\n };\n\n /**\n * Get current time of player\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getCurrentPosition = function() {\n return this.player.getCurrentTime();\n };\n\n return VideoTime;\n});\n"],"names":["define","$","Vimeo","Ajax","Config","Log","Templates","Notification","VideoTime","elementId","cmId","hasPro","interval","instance","player","resumeTime","session","played","playing","time","percent","currentTime","playbackRate","plugins","hasClass","addClass","document","on","this","initializeNewInstances","bind","modulecount","length","prototype","getCmId","registerPlugin","plugin","push","initialize","debug","autopause","Number","autoplay","background","byline","color","controls","dnt","height","loop","option_loop","maxheight","maxwidth","muted","portrait","pip","playsinline","responsive","speed","title","transparent","url","vimeo_url","width","URL","window","location","href","q","searchParams","get","starttime","match","setStartTime","then","find","catch","exception","addListeners","i","getPlayer","closest","each","tabs","index","anchor","getAttribute","addCuePoint","exeception","event","data","removeClass","offsetTop","parentNode","scrollTo","top","left","behavior","startWatchInterval","view","resume_playback","resume_time","getDuration","duration","Math","floor","setCurrentPosition","fail","getPlaybackRate","seconds","forEach","setCurrentTime","getSessions","id","handleEnd","handlePause","getSession","setSessionState","setPercent","getNextActivityButtonData","response","JSON","parse","parseInt","next_activity_auto","is_restricted","hasnextcm","link","nextcm_url","first","click","render","html","watchInterval","setInterval","recordWatchTime","sessionId","state","token","wwwroot","set","fetch","ok","exeption","json","call","methodname","args","Promise","resolve","getInstance","cmid","done","getResumeTime","getCurrentTime","module","attr","replace","haspro","uniqueid","js","runTemplateJS","secs","getCurrentPosition"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"videotime.min.js","sources":["../src/videotime.js"],"sourcesContent":["/*\n * @package mod_videotime\n * @copyright 2021 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * @module mod_videotime/videotime\n */\ndefine([\n 'jquery',\n 'mod_videotime/player',\n 'core/ajax',\n 'core/config',\n 'core/log',\n 'core/templates',\n 'core/notification'\n], function($, Vimeo, Ajax, Config, Log, Templates, Notification) {\n let VideoTime = function(elementId, cmId, hasPro, interval, instance) {\n this.elementId = elementId;\n this.cmId = cmId;\n this.hasPro = hasPro;\n this.interval = interval;\n this.player = null;\n this.resumeTime = null;\n this.session = null;\n this.instance = instance;\n\n this.played = false;\n\n this.playing = false;\n this.time = 0;\n this.percent = 0;\n this.currentTime = 0;\n this.playbackRate = 1;\n\n this.plugins = [];\n\n if (hasPro && $('body').hasClass('path-course-view') && !$('body').hasClass('vtinit')) {\n $('body').addClass('vtinit');\n $(document).on('focus', 'body', this.initializeNewInstances.bind(this));\n }\n this.modulecount = $('body .activity.videotime').length;\n };\n\n /**\n * Get course module ID of this VideoTime instance.\n *\n * @return {int}\n */\n VideoTime.prototype.getCmId = function() {\n return this.cmId;\n };\n\n /**\n * Register a plugin to hook into VideoTime functionality.\n *\n * @param {VideoTimePlugin} plugin\n */\n VideoTime.prototype.registerPlugin = function(plugin) {\n this.plugins.push(plugin);\n };\n\n VideoTime.prototype.initialize = function() {\n let instance = this.instance;\n Log.debug('Initializing Video Time ' + this.elementId);\n\n Log.debug('Initializing Vimeo player with options:');\n Log.debug(instance);\n this.player = new Vimeo(this.elementId, {\n autopause: Number(instance.autopause),\n autoplay: Number(instance.autoplay),\n background: Number(instance.background),\n byline: Number(instance.byline),\n color: instance.color,\n controls: Number(instance.controls),\n dnt: Number(instance.dnt),\n height: instance.height,\n loop: Number(instance.option_loop),\n maxheight: instance.maxheight,\n maxwidth: instance.maxwidth,\n muted: Number(instance.muted),\n portrait: instance.portrait,\n pip: Number(instance.pip),\n playsinline: instance.playsinline,\n responsive: Number(instance.responsive),\n speed: instance.speed,\n title: Number(instance.title),\n transparent: Number(instance.transparent),\n url: instance.vimeo_url,\n width: instance.width\n });\n\n let url = new URL(window.location.href),\n q = url.searchParams.get('q'),\n starttime = (url.searchParams.get('time') || '').match(/^([0-9]+:){0,2}([0-9]+)(\\.[0-9]+)$/);\n if (starttime) {\n this.setStartTime(starttime[0]).then(function() {\n if (q && window.find) {\n window.find(q);\n }\n return true;\n }).catch(Notification.exception);\n } else if (q && window.find) {\n window.find(q);\n }\n\n this.addListeners();\n\n for (let i = 0; i < this.plugins.length; i++) {\n const plugin = this.plugins[i];\n plugin.initialize(this, instance);\n }\n\n return true;\n };\n\n /**\n * Get Vimeo player object.\n *\n * @returns {Vimeo}\n */\n VideoTime.prototype.getPlayer = function() {\n return this.player;\n };\n\n /**\n * Register player events to respond to user interaction and play progress.\n */\n VideoTime.prototype.addListeners = function() {\n if (!this.player) {\n Log.debug('Player was not properly initialized for course module ' + this.cmId);\n return;\n }\n\n // If this is a tab play set time cues and listener.\n $($('#' + this.elementId).closest('.videotimetabs')).each(function(i, tabs) {\n $(tabs).find('[data-action=\"cue\"]').each(function(index, anchor) {\n let starttime = anchor.getAttribute('data-start'),\n time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.player.addCuePoint(\n 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]),\n {\n starttime: starttime\n }\n ).catch(Notification.exeception);\n }\n }.bind(this));\n\n this.player.on('cuepoint', function(event) {\n if (event.data.starttime) {\n $(tabs).find('.videotime-highlight').removeClass('videotime-highlight');\n $(tabs).find('[data-action=\"cue\"][data-start=\"' + event.data.starttime + '\"]')\n .closest('.row')\n .addClass('videotime-highlight');\n $('.videotime-highlight').each(function() {\n if (this.offsetTop) {\n this.parentNode.scrollTo({\n top: this.offsetTop - 50,\n left: 0,\n behavior: 'smooth'\n });\n }\n });\n }\n });\n }.bind(this));\n\n // Fire view event in Moodle on first play only.\n this.player.on('play', () => {\n if (this.hasPro) {\n this.startWatchInterval();\n }\n this.view();\n return true;\n });\n\n // Features beyond this point are for pro only.\n if (!this.hasPro) {\n return;\n }\n\n // If resume is present force seek the player to that point.\n this.player.on(\"loaded\", () => {\n if (!this.instance.resume_playback || !this.instance.resume_time || this.instance.resume_time <= 0) {\n return true;\n }\n\n return this.getDuration().then((duration) => {\n let resumeTime = this.instance.resume_time;\n // Duration is often a little greater than a resume time at the end of the video.\n // A user may have watched 100 seconds when the video ends, but the duration may be\n // 100.56 seconds. BUT, sometimes the duration is rounded depending on when the\n // video loads, so it may be 101 seconds. Hence the +1 and Math.floor usage.\n if (resumeTime + 1 >= Math.floor(duration)) {\n Log.debug(\n \"VIDEO_TIME video finished, resuming at start of video.\"\n );\n resumeTime = 0;\n }\n Log.debug(\"VIDEO_TIME duration is \" + duration);\n Log.debug(\"VIDEO_TIME resuming at \" + resumeTime);\n this.setCurrentPosition(resumeTime);\n return true;\n }).fail(Notification.exception);\n });\n\n // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function.\n\n // Catch all events where video plays.\n this.player.on('play', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME play');\n }.bind(this));\n this.player.on('playing', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME playing');\n }.bind(this));\n\n // Catch all events where video stops.\n this.player.on('pause', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME pause');\n }.bind(this));\n this.player.on('stalled', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME stalled');\n }.bind(this));\n this.player.on('suspend', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME suspend');\n }.bind(this));\n this.player.on('abort', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME abort');\n }.bind(this));\n\n this.player.getPlaybackRate().then(function(playbackRate) {\n this.playbackRate = playbackRate;\n }.bind(this)).catch(Notification.exception);\n\n this.player.on('playbackratechange', function(event) {\n this.playbackRate = event.playbackRate;\n }.bind(this));\n\n // Always update internal values for percent and current time watched.\n this.player.on('timeupdate', function(event) {\n this.percent = event.percent;\n this.currentTime = event.seconds;\n if (event.seconds === event.duration) {\n this.plugins.forEach(plugin => {\n if (typeof plugin.setCurrentTime == 'function') {\n plugin.getSessions().then(session => {\n plugin.setCurrentTime(session.id, event.seconds);\n return session;\n }).catch(Notification.exception);\n }\n });\n }\n }.bind(this));\n\n // Initiate video finish procedure.\n this.player.on('ended', this.handleEnd.bind(this));\n this.player.on('pause', this.handlePause.bind(this));\n };\n\n /**\n * Handle pause\n */\n VideoTime.prototype.handlePause = function() {\n this.plugins.forEach(plugin => {\n if (typeof plugin.handlePause == 'function') {\n plugin.handlePause();\n }\n });\n };\n\n /**\n * Start interval that will periodically record user progress via Ajax.\n */\n VideoTime.prototype.handleEnd = function() {\n this.playing = false;\n Log.debug('VIDEO_TIME ended');\n if (this.plugins.length > 2) {\n this.plugins.forEach(plugin => {\n if (typeof plugin.handleEnd == 'function') {\n plugin.handleEnd();\n }\n });\n } else {\n // This moved to pro plugin, but left for compatibility.\n this.getSession().then(function(session) {\n this.setSessionState(session.id, 1).then(() => {\n return this.setPercent(session.id, 1);\n }).then(() => {\n return this.setCurrentTime(session.id, this.currentTime);\n }).then(() => {\n return this.getNextActivityButtonData(session.id).then(response => {\n let data = JSON.parse(response.data);\n\n if (data.instance && parseInt(data.instance.next_activity_auto)) {\n if (!data.is_restricted && data.hasnextcm) {\n let link = $('.aalink[href=\"' + data.nextcm_url + '\"] img').first();\n if ($('.path-course-view').length && link) {\n link.click();\n } else {\n window.location.href = data.nextcm_url;\n }\n }\n }\n\n return Templates.render('videotime/next_activity_button', JSON.parse(response.data))\n .then(function(html) {\n $('#next-activity-button').html(html);\n return true;\n });\n });\n }).catch(Notification.exception);\n }.bind(this)).catch(Notification.exception);\n }\n };\n\n /**\n * Start interval that will periodically record user progress via Ajax.\n */\n VideoTime.prototype.startWatchInterval = function() {\n this.plugins.forEach(plugin => {\n if (typeof plugin.startWatchInterval == 'function') {\n this.watchInterval = true;\n plugin.startWatchInterval();\n }\n });\n if (this.watchInterval) {\n return;\n }\n\n this.watchInterval = setInterval(function() {\n if (this.playing) {\n this.time += this.playbackRate;\n\n this.getSession().then(function(session) {\n if (this.time / this.playbackRate % this.interval === 0) {\n Log.debug('VIDEO_TIME watch_time: ' + this.time + '. percent: ' + this.percent);\n this.recordWatchTime(session.id, this.time);\n this.setPercent(session.id, this.percent);\n this.setCurrentTime(session.id, this.currentTime);\n }\n return true;\n }.bind(this)).catch(Notification.exception);\n }\n }.bind(this), 1000);\n };\n\n /**\n * Set state on session.\n *\n * @param {int} sessionId\n * @param {int} state\n * @returns {Promise}\n */\n VideoTime.prototype.setSessionState = function(sessionId, state) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_set_session_state');\n data.set('state', state);\n data.set('session_id', sessionId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_state',\n args: {\"session_id\": sessionId, state: state},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Set current watch time for video. Used for resuming.\n *\n * @param {int} sessionId\n * @param {float} currentTime\n * @returns {Promise}\n */\n VideoTime.prototype.setCurrentTime = function(sessionId, currentTime) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_set_session_current_time');\n data.set('current_time', currentTime);\n data.set('session_id', sessionId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_current_time',\n args: {\"session_id\": sessionId, \"current_time\": currentTime},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Set video watch percentage for session.\n *\n * @param {int} sessionId\n * @param {float} percent\n * @returns {Promise}\n */\n VideoTime.prototype.setPercent = function(sessionId, percent) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_set_percent');\n data.set('percent', percent);\n data.set('session_id', sessionId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_percent',\n args: {\"session_id\": sessionId, percent: percent},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Record watch time for session.\n *\n * @param {int} sessionId\n * @param {float} time\n * @returns {Promise}\n */\n VideoTime.prototype.recordWatchTime = function(sessionId, time) {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_record_watch_time');\n data.set('session_id', sessionId);\n data.set('time', time);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_record_watch_time',\n args: {\"session_id\": sessionId, time: time},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Get data for next activity button.\n *\n * @param {int} sessionId\n * @returns {Promise}\n */\n VideoTime.prototype.getNextActivityButtonData = function(sessionId) {\n if (this.instance.token) {\n // We do not support button in iframe.\n return Promise.resolve({data: '{}'});\n }\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_get_next_activity_button_data',\n args: {\"session_id\": sessionId}\n }])[0];\n };\n\n /**\n * Get VideoTime instance for this course module.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getInstance = function() {\n if (this.instance) {\n return Promise.resolve(this.instance);\n }\n\n return Ajax.call([{\n methodname: 'mod_videotime_get_videotime',\n args: {cmid: this.cmId},\n done: (response) => {\n this.instance = response;\n return this.instance;\n },\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Get time to resume video as seconds.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getResumeTime = function() {\n if (this.resumeTime) {\n return Promise.resolve(this.resumeTime);\n }\n\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_get_resume_time',\n args: {cmid: this.cmId},\n done: (response) => {\n this.resumeTime = response.seconds;\n return this.resumeTime;\n },\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Get new or existing video viewing session.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getSession = function() {\n if (this.instance.token) {\n if (!this.session) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'videotimeplugin_pro_get_new_session');\n data.set('cmid', this.cmId);\n this.session = fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n }\n\n return this.session;\n }\n if (!this.session) {\n this.session = Ajax.call([{\n methodname: 'videotimeplugin_pro_get_new_session',\n args: {cmid: this.cmId},\n fail: Notification.exception\n }])[0];\n }\n return this.session;\n };\n\n /**\n * Parse start time and set player\n *\n * @param {string} starttime\n * @returns {Promise}\n */\n VideoTime.prototype.setStartTime = function(starttime) {\n let time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.resumeTime = 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]);\n this.currentTime(this.resumeTime);\n }\n return this.player.getCurrentTime();\n };\n\n /**\n * Log the user view of video.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.view = function() {\n if (this.instance.token) {\n const url = new URL(Config.wwwroot + '/webservice/rest/server.php'),\n data = url.searchParams;\n data.set('wstoken', this.instance.token);\n data.set('moodlewsrestformat', 'json');\n data.set('wsfunction', 'mod_videotime_view_videotime');\n data.set('cmid', this.cmId);\n return fetch(url).then((response) => {\n if (!response.ok) {\n Notification.exeption('Web service error');\n }\n return response.json();\n });\n\n }\n return Ajax.call([{\n methodname: 'mod_videotime_view_videotime',\n args: {cmid: this.cmId},\n fail: Notification.exception\n }])[0];\n };\n\n /**\n * Initialize new labels and preview when editing\n */\n VideoTime.prototype.initializeNewInstances = function() {\n if (this.modulecount == $('body .activity.videotime').length) {\n return;\n }\n this.modulecount = $('body .activity.videotime').length;\n $('body .activity.videotime').each(function(index, module) {\n if (\n !$(module).find('.instancename').length\n && $(module).find('.vimeo-embed').length\n && !$(module).find('.vimeo-embed iframe').length\n ) {\n let instance = {\n cmid: Number($(module).attr('id').replace('module-', '')),\n haspro: true,\n interval: this.interval,\n uniqueid: $(module).find('.vimeo-embed').first().attr('id').replace('vimeo-embed-', '')\n };\n Templates.render('mod_videotime/videotime_instance', {\n instance: instance\n }).then(function(html, js) {\n Templates.runTemplateJS(js);\n return true;\n }).fail(Notification.exception);\n }\n }.bind(this));\n };\n\n /**\n * Get play back rate\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getPlaybackRate = function() {\n return this.player.getPlaybackRate();\n };\n\n /**\n * Get duration of video\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getDuration = function() {\n return this.player.getDuration();\n };\n\n /**\n * Set current time of player\n *\n * @param {float} secs time\n * @returns {Promise}\n */\n VideoTime.prototype.setCurrentPosition = function(secs) {\n return this.player.setCurrentTime(secs);\n };\n\n /**\n * Get current time of player\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getCurrentPosition = function() {\n return this.player.getCurrentTime();\n };\n\n return VideoTime;\n});\n"],"names":["define","$","Vimeo","Ajax","Config","Log","Templates","Notification","VideoTime","elementId","cmId","hasPro","interval","instance","player","resumeTime","session","played","playing","time","percent","currentTime","playbackRate","plugins","hasClass","addClass","document","on","this","initializeNewInstances","bind","modulecount","length","prototype","getCmId","registerPlugin","plugin","push","initialize","debug","autopause","Number","autoplay","background","byline","color","controls","dnt","height","loop","option_loop","maxheight","maxwidth","muted","portrait","pip","playsinline","responsive","speed","title","transparent","url","vimeo_url","width","URL","window","location","href","q","searchParams","get","starttime","match","setStartTime","then","find","catch","exception","addListeners","i","getPlayer","closest","each","tabs","index","anchor","getAttribute","addCuePoint","exeception","event","data","removeClass","offsetTop","parentNode","scrollTo","top","left","behavior","startWatchInterval","view","resume_playback","resume_time","getDuration","duration","Math","floor","setCurrentPosition","fail","getPlaybackRate","seconds","forEach","setCurrentTime","getSessions","id","handleEnd","handlePause","getSession","setSessionState","setPercent","getNextActivityButtonData","response","JSON","parse","parseInt","next_activity_auto","is_restricted","hasnextcm","link","nextcm_url","first","click","render","html","watchInterval","setInterval","recordWatchTime","sessionId","state","token","wwwroot","set","fetch","ok","exeption","json","call","methodname","args","Promise","resolve","getInstance","cmid","done","getResumeTime","getCurrentTime","module","attr","replace","haspro","uniqueid","js","runTemplateJS","secs","getCurrentPosition"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/videotime.js b/amd/src/videotime.js index 6069d700..369bf274 100644 --- a/amd/src/videotime.js +++ b/amd/src/videotime.js @@ -340,7 +340,7 @@ define([ this.time += this.playbackRate; this.getSession().then(function(session) { - if (this.time % this.interval === 0) { + if (this.time / this.playbackRate % this.interval === 0) { Log.debug('VIDEO_TIME watch_time: ' + this.time + '. percent: ' + this.percent); this.recordWatchTime(session.id, this.time); this.setPercent(session.id, this.percent);