Merge branch 'MDL-72603-master' of git://github.com/HuongNV13/moodle

This commit is contained in:
Sara Arjona
2021-11-03 12:18:19 +01:00
19 changed files with 448 additions and 459 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
define ("block_timeline/event_list",["jquery","core/notification","core/templates","core/paged_content_factory","core/str","core/user_date","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f,g){var h=!1,i={EMPTY_MESSAGE:"[data-region=\"empty-message\"]",ROOT:"[data-region=\"event-list-container\"]",EVENT_LIST_CONTENT:"[data-region=\"event-list-content\"]",EVENT_LIST_LOADING_PLACEHOLDER:"[data-region=\"event-list-loading-placeholder\"]",TIMELINE_BLOCK:"[data-region=\"timeline\"]",TIMELINE_SEARCH:"[data-region=\"search-input\"]"},j={EVENT_LIST_CONTENT:"block_timeline/event-list-content"},k={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,ariaLabels:{itemsperpagecomponents:"ariaeventlistpagelimit, block_timeline"}},l=function(a){a.find(i.EVENT_LIST_CONTENT).addClass("hidden");a.find(i.EMPTY_MESSAGE).removeClass("hidden")},m=function(a){a.find(i.EVENT_LIST_CONTENT).removeClass("hidden");a.find(i.EMPTY_MESSAGE).addClass("hidden")},n=function(a){a.find(i.EVENT_LIST_CONTENT).empty()},o=function(a){var b={},c={courseview:h,eventsbyday:[]};a.forEach(function(a){var c=a.timeusermidnight;if(b[c]){b[c].push(a)}else{b[c]=[a]}});Object.keys(b).forEach(function(a){var d=b[a];c.eventsbyday.push({dayTimestamp:a,events:d})});return c},p=function(a){var b=o(a),d=j.EVENT_LIST_CONTENT;return c.render(d,b)},q=function(a,b,c,d,e,f,h){var i=d!=void 0?a+d*86400:!1,j={starttime:a+c*86400,limit:b};if(e){j.aftereventid=e}if(i){j.endtime=i}if(h){j.searchvalue=h}if(f){j.courseid=f;return g.queryByCourse(j)}else{return g.queryByTime(j)}},r=function(a,b,c,d,e,g,h,i,j){var k=a.pageNumber,l=a.limit,m=k;while(!d.hasOwnProperty(m)){m--}var n=d[m],o=null;if(e&&e.hasOwnProperty(k)){o=e[k]}else{o=q(c,l+1,h,i,n,g,j)}return o.then(function(a){if(!a.events.length){b.allItemsLoaded(k);return[]}var d=document.querySelector("[data-filtername='overdue']"),e=d&&d.getAttribute("aria-current"),g=a.events.filter(function(a){if("open"==a.eventtype||"opensubmission"==a.eventtype){var b=f.getUserMidnightForTimestamp(a.timesort,c);return b>c}return!e||a.overdue}),h=g.length<=l;if(h){b.allItemsLoaded(k)}else{g.pop()}return g})},s=function(c,f,g,h,i,j,l,m,n,o){var q={1:0},s=!1,t=a.extend({},k,n);return e.get_string("ariaeventlistpagelimit","block_timeline",a.isArray(c)?c[0].value:c).then(function(a){t.ariaLabels.itemsperpage=a;t.ariaLabels.paginationnav=m;return a}).then(function(){return d.createWithLimit(c,function(c,d){var e=[];c.forEach(function(a){var c=a.pageNumber,h=r(a,d,g,q,f,i,j,l,o).then(function(a){if(a.length){s=!0;var b=a[a.length-1].id;q[c+1]=b;return p(a)}else{return a}}).catch(b.exception);e.push(h)});a.when.apply(a,e).then(function(){h.resolve(s)}).catch(function(){h.resolve(s)});return e},t)})};return{init:function init(d,e,f,g){var j=4<arguments.length&&arguments[4]!==void 0?arguments[4]:{};d=a(d);h=!!j.courseview;var k=a.Deferred(),o=d.find(i.EVENT_LIST_CONTENT),p=d.find(i.EVENT_LIST_LOADING_PLACEHOLDER),q=d.attr("data-course-id"),r=parseInt(d.attr("data-days-offset"),10),t=d.attr("data-days-limit"),u=parseInt(d.attr("data-midnight"),10),v=d.closest(i.TIMELINE_BLOCK).find(i.TIMELINE_SEARCH).val();n(d);m(d);p.removeClass("hidden");if(t!=void 0){t=parseInt(t,10)}return s(e,f,u,k,q,r,t,g,j,v).then(function(b,e){b=a(b);b.addClass("hidden");c.replaceNodeContents(o,b,e);k.then(function(a){b.removeClass("hidden");p.addClass("hidden");if(!a){l(d)}return a}).catch(function(){return!1});return b}).catch(b.exception)},rootSelector:i.ROOT}});
define ("block_timeline/event_list",["jquery","core/notification","core/templates","core/str","core/user_date","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f){var g=!1,h={EMPTY_MESSAGE:"[data-region=\"empty-message\"]",ROOT:"[data-region=\"event-list-container\"]",EVENT_LIST_CONTENT:"[data-region=\"event-list-content\"]",EVENT_LIST_WRAPPER:"[data-region=\"event-list-wrapper\"]",EVENT_LIST_LOADING_PLACEHOLDER:"[data-region=\"event-list-loading-placeholder\"]",TIMELINE_BLOCK:"[data-region=\"timeline\"]",TIMELINE_SEARCH:"[data-region=\"search-input\"]",MORE_ACTIVITIES_BUTTON:"[data-action=\"more-events\"]",MORE_ACTIVITIES_BUTTON_CONTAINER:"[data-region=\"more-events-button-container\"]"},i={EVENT_LIST_CONTENT:"block_timeline/event-list-content",MORE_ACTIVITIES_BUTTON:"block_timeline/event-list-loadmore",LOADING_ICON:"core/loading"},j=function(a){a.find(h.EVENT_LIST_CONTENT).addClass("hidden");a.find(h.EMPTY_MESSAGE).removeClass("hidden")},k=function(a){a.find(h.EVENT_LIST_CONTENT).removeClass("hidden");a.find(h.EMPTY_MESSAGE).addClass("hidden")},l=function(a){a.find(h.EVENT_LIST_CONTENT).empty()},m=function(a){var b={},c={courseview:g,eventsbyday:[]};a.forEach(function(a){var c=a.timeusermidnight;if(b[c]){b[c].push(a)}else{b[c]=[a]}});Object.keys(b).forEach(function(a){var d=b[a];c.eventsbyday.push({dayTimestamp:a,events:d})});return c},n=function(a){var b=m(a),d=i.EVENT_LIST_CONTENT;return c.render(d,b)},o=function(a,b,c,d,e,g,h){var i=d!=void 0?a+d*86400:!1,j={starttime:a+c*86400,limit:b};if(e){j.aftereventid=e}if(i){j.endtime=i}if(h){j.searchvalue=h}if(g){j.courseid=g;return f.queryByCourse(j)}else{return f.queryByTime(j)}},p=function(a,c,d,e,f,g,h,i,j){return q(a,d,e,f,g,h,i,j).then(function(a){if(a.calendarEvents.length){var b=a.calendarEvents.at(-1).id,d=a.calendarEvents.at(-1).timeusermidnight;c.resolve({hasContent:!0,lastId:b,lastTimeStamp:d,loadedAll:a.loadedAll});return n(a.calendarEvents,e)}else{c.resolve({hasContent:!1,lastId:0,lastTimeStamp:0,loadedAll:!0});return a.calendarEvents}}).catch(b.exception)},q=function(a,b,c,d,f,g,h,i){var j=o(c,b+1,g,h,d,f,i),k=[],l=!0;return j.then(function(d){if(!d.events.length){return{calendarEvents:k,loadedAll:l}}var f=document.querySelector("[data-filtername='overdue']"),g=f&&f.getAttribute("aria-current");k=d.events.filter(function(a){if("open"==a.eventtype||"opensubmission"==a.eventtype){var b=e.getUserMidnightForTimestamp(a.timesort,c);return b>c}return!g||a.overdue});l=k.length<=b;if(!l){k.pop()}if(k.length){var h=k.at(-1).id;t(a,h)}return{calendarEvents:k,loadedAll:l}})},r=function(d){var e=parseInt(d.attr("data-midnight"),10),f=d.attr("data-course-id"),g=parseInt(d.attr("data-days-offset"),10),j=d.attr("data-days-limit"),k=s(d),l=d.find(h.EVENT_LIST_WRAPPER),m=d.closest(h.TIMELINE_BLOCK).find(h.TIMELINE_SEARCH).val(),o=q(d,10,e,k,f,g,j,m);o.then(function(e){if(e.calendarEvents.length){var f=n(e.calendarEvents),g=u(d);f.then(function(b,f){b=a(b);b.find("[data-timestamp=\"".concat(g,"\"]")).remove();c.appendNodeContents(l,b.html(),f);if(!e.loadedAll){c.render(i.MORE_ACTIVITIES_BUTTON,{}).then(function(a){l.append(a);v(d,e.calendarEvents.at(-1).timeusermidnight);y(d);return a}).catch(function(){return!1})}return b}).catch(b.exception)}return e}).then(function(){return x(d)}).catch(b.exception)},s=function(a){return parseInt(a.attr("data-lazyload-offset"),10)},t=function(a,b){a.attr("data-lazyload-offset",b)},u=function(a){return parseInt(a.attr("data-timestamp"),10)},v=function(a,b){a.attr("data-timestamp",b)},w=function(a){var b=a.find(h.MORE_ACTIVITIES_BUTTON);b.prop("disabled",!0);c.render(i.LOADING_ICON,{}).then(function(a){b.append(a);return a}).catch(function(){return!1})},x=function(a){var b=a.find(h.MORE_ACTIVITIES_BUTTON_CONTAINER);b.remove()},y=function(a){var b=a.find(h.MORE_ACTIVITIES_BUTTON);b.on("click",function(){w(a);r(a)})};return{init:function init(d){var e=1<arguments.length&&arguments[1]!==void 0?arguments[1]:{};d=a(d);g=!!e.courseview;var f=a.Deferred(),m=d.find(h.EVENT_LIST_CONTENT),n=d.find(h.EVENT_LIST_LOADING_PLACEHOLDER),o=d.attr("data-course-id"),q=parseInt(d.attr("data-days-offset"),10),r=d.attr("data-days-limit"),s=parseInt(d.attr("data-midnight"),10),t=d.closest(h.TIMELINE_BLOCK).find(h.TIMELINE_SEARCH).val();l(d);k(d);n.removeClass("hidden");if(r!=void 0){r=parseInt(r,10)}return p(d,f,5,s,0,o,q,r,t).then(function(b,e){f.then(function(f){if(!f.hasContent){n.addClass("hidden");return j(d)}b=a(b);b.addClass("hidden");c.replaceNodeContents(m,b,e);b.removeClass("hidden");n.addClass("hidden");if(!f.loadedAll){c.render(i.MORE_ACTIVITIES_BUTTON,{}).then(function(a){m.append(a);v(d,f.lastTimeStamp);y(d);return a}).catch(function(){return!1})}return f}).catch(function(){return!1});return b}).catch(b.exception)},rootSelector:h.ROOT}});
//# sourceMappingURL=event_list.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("block_timeline/view_courses",["jquery","core/notification","core/custom_interaction_events","core/str","core/templates","block_timeline/event_list","core_course/repository","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f,g,h){var i={MORE_COURSES_BUTTON:"[data-action=\"more-courses\"]",MORE_COURSES_BUTTON_CONTAINER:"[data-region=\"more-courses-button-container\"]",NO_COURSES_EMPTY_MESSAGE:"[data-region=\"no-courses-empty-message\"]",COURSES_LIST:"[data-region=\"courses-list\"]",COURSE_ITEMS_LOADING_PLACEHOLDER:"[data-region=\"course-items-loading-placeholder\"]",COURSE_EVENTS_CONTAINER:"[data-region=\"course-events-container\"]",COURSE_NAME:"[data-region=\"course-name\"]",LOADING_ICON:".loading-icon",TIMELINE_BLOCK:"[data-region=\"timeline\"]",TIMELINE_SEARCH:"[data-region=\"search-input\"]"},j={COURSE_ITEMS:"block_timeline/course-items",LOADING_ICON:"core/loading"},k=5,l=86400,m={courseview:!0},n=function(a){a.find(i.COURSE_ITEMS_LOADING_PLACEHOLDER).addClass("hidden")},o=function(a){a.find(i.MORE_COURSES_BUTTON_CONTAINER).addClass("hidden")},p=function(a){a.find(i.MORE_COURSES_BUTTON_CONTAINER).removeClass("hidden")},q=function(a){var b=a.find(i.MORE_COURSES_BUTTON);b.prop("disabled",!0);e.render(j.LOADING_ICON,{}).then(function(a){b.append(a);return a}).catch(function(){return!1})},r=function(a){var b=a.find(i.MORE_COURSES_BUTTON);b.prop("disabled",!1);b.find(i.LOADING_ICON).remove()},s=function(a){a.find(i.NO_COURSES_EMPTY_MESSAGE).removeClass("hidden")},t=function(a,b){var c=a.find(i.COURSES_LIST);e.appendNodeContents(c,b,"")},u=function(a){return 0<a.find(i.COURSE_EVENTS_CONTAINER).length},v=function(a){return parseInt(a.attr("data-offset"),10)},w=function(a,b){a.attr("data-offset",b)},x=function(a){return parseInt(a.attr("data-limit"),10)},y=function(a){return parseInt(a.attr("data-days-offset"),10)},z=function(a){var b=a.attr("data-days-limit");return b!=void 0?parseInt(b,10):void 0},A=function(a){return parseInt(a.attr("data-midnight"),10)},B=function(a){var b=A(a),c=y(a);return b+c*l},C=function(a){var b=A(a),c=z(a);return c!=void 0?b+c*l:!1},D=function(a,b,c,d,e){var f={courseids:a,starttime:b,limit:c};if(d){f.endtime=d}if(e){f.searchvalue=e}return h.queryByCourses(f)},E=function(a){return a.data("last-event-load-time")},F=function(a,b){a.data("last-event-load-time",b)},G=function(a,b){return E(a)>b},H=function(a,b,c,d){var e=a.map(function(a){return a.id});return D(e,b,k+1,c,d)},I=function(a,b,c,d,f){return e.render(j.COURSE_ITEMS,{courses:a,midnight:c,hasdaysoffset:!0,hasdayslimit:f!=void 0,daysoffset:d,dayslimit:f,nodayslimit:f==void 0}).then(function(a){n(b);if(a){t(b,a)}else{if(!u(b)){s(b)}}return a}).then(function(c){if(a.length<2){o(b)}else{p(b)}return c}).catch(function(){n(b)})},J=function(c){var e=v(c),h=x(c);return g.getEnrolledCoursesByTimelineClassification("inprogress",h,e,"fullname asc").then(function(b){var e=Date.now(),g=b.courses,h=b.nextoffset,j=y(c),l=z(c),n=A(c),o=B(c),p=C(c),q=c.closest(i.TIMELINE_BLOCK).find(i.TIMELINE_SEARCH).val();w(c,h);var r=H(g,o,p,q),s=I(g,c,n,j,l);return a.when(r,s).then(function(b){if(G(c,e)){return b}g.forEach(function(e){var g=e.id,h=[],i=c.find("[data-region=\"course-events-container\"][data-course-id=\""+g+"\"]"),j=i.find(f.rootSelector),l=b.groupedbycourse.filter(function(a){return a.courseid==g});if(l.length){h=l[0].events}var n=a.Deferred().resolve({events:h}).promise();d.get_string("ariaeventlistpaginationnavcourses","block_timeline",e.fullnamedisplay).then(function(a){f.init(j,k,{1:n},a,m);return a}).catch(function(){f.init(j,k,{1:n},void 0,m)})});return b})}).catch(b.exception)},K=function(c){var e=Date.now(),g=B(c),h=C(c),j=c.find(i.COURSE_EVENTS_CONTAINER),l=j.map(function(){return a(this).attr("data-course-id")}).get(),n=c.closest(i.TIMELINE_BLOCK).find(i.TIMELINE_SEARCH).val();F(c,e);return D(l,g,k+1,h,n).then(function(b){if(G(c,e)){return b}j.each(function(c,e){e=a(e);var g=e.attr("data-course-id"),h=e.find(i.COURSE_NAME).text(),j=e.find(f.rootSelector),l=a.Deferred(),n=[],o=b.groupedbycourse.filter(function(a){return a.courseid==g});if(o.length){n=o[0].events}l.resolve({events:n});d.get_string("ariaeventlistpaginationnavcourses","block_timeline",h).then(function(a){f.init(j,k,{1:l.promise()},a,m);return a}).catch(function(){f.init(j,k,{1:l.promise()},void 0,m)})});return b}).catch(b.exception)},L=function(a){c.define(a,[c.events.activate]);a.on(c.events.activate,i.MORE_COURSES_BUTTON,function(b,c){q(a);J(a).then(function(){r(a)}).catch(function(){r(a)});if(c){c.originalEvent.preventDefault();c.originalEvent.stopPropagation()}b.stopPropagation()})},M=function(a){if(!a.attr("data-seen")){if(u(a)){K(a)}else{J(a)}a.attr("data-seen",!0)}};return{init:function init(b){b=a(b);F(b,Date.now());if(b.hasClass("active")){J(b);b.attr("data-seen",!0)}L(b)},reset:function reset(a){a.removeAttr("data-seen");if(a.hasClass("active")){M(a)}},shown:M}});
define ("block_timeline/view_courses",["jquery","core/notification","core/custom_interaction_events","core/templates","block_timeline/event_list","core_course/repository","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f,g){var h={MORE_COURSES_BUTTON:"[data-action=\"more-courses\"]",MORE_COURSES_BUTTON_CONTAINER:"[data-region=\"more-courses-button-container\"]",NO_COURSES_EMPTY_MESSAGE:"[data-region=\"no-courses-empty-message\"]",COURSES_LIST:"[data-region=\"courses-list\"]",COURSE_ITEMS_LOADING_PLACEHOLDER:"[data-region=\"course-items-loading-placeholder\"]",COURSE_EVENTS_CONTAINER:"[data-region=\"course-events-container\"]",COURSE_NAME:"[data-region=\"course-name\"]",LOADING_ICON:".loading-icon",TIMELINE_BLOCK:"[data-region=\"timeline\"]",TIMELINE_SEARCH:"[data-region=\"search-input\"]"},i={COURSE_ITEMS:"block_timeline/course-items",LOADING_ICON:"core/loading"},j=5,k=86400,l={courseview:!0},m=function(a){a.find(h.COURSE_ITEMS_LOADING_PLACEHOLDER).addClass("hidden")},n=function(a){a.find(h.MORE_COURSES_BUTTON_CONTAINER).addClass("hidden")},o=function(a){a.find(h.MORE_COURSES_BUTTON_CONTAINER).removeClass("hidden")},p=function(a){var b=a.find(h.MORE_COURSES_BUTTON);b.prop("disabled",!0);d.render(i.LOADING_ICON,{}).then(function(a){b.append(a);return a}).catch(function(){return!1})},q=function(a){var b=a.find(h.MORE_COURSES_BUTTON);b.prop("disabled",!1);b.find(h.LOADING_ICON).remove()},r=function(a){a.find(h.NO_COURSES_EMPTY_MESSAGE).removeClass("hidden")},s=function(a,b){var c=a.find(h.COURSES_LIST);d.appendNodeContents(c,b,"")},t=function(a){return 0<a.find(h.COURSE_EVENTS_CONTAINER).length},u=function(a){return parseInt(a.attr("data-offset"),10)},v=function(a,b){a.attr("data-offset",b)},w=function(a){return parseInt(a.attr("data-limit"),10)},x=function(a){return parseInt(a.attr("data-days-offset"),10)},y=function(a){var b=a.attr("data-days-limit");return b!=void 0?parseInt(b,10):void 0},z=function(a){return parseInt(a.attr("data-midnight"),10)},A=function(a){var b=z(a),c=x(a);return b+c*k},B=function(a){var b=z(a),c=y(a);return c!=void 0?b+c*k:!1},C=function(a,b,c,d,e){var f={courseids:a,starttime:b,limit:c};if(d){f.endtime=d}if(e){f.searchvalue=e}return g.queryByCourses(f)},D=function(a){return a.data("last-event-load-time")},E=function(a,b){a.data("last-event-load-time",b)},F=function(a,b){return D(a)>b},G=function(a,b,c,d){var e=a.map(function(a){return a.id});return C(e,b,j+1,c,d)},H=function(a,b,c,e,f){return d.render(i.COURSE_ITEMS,{courses:a,midnight:c,hasdaysoffset:!0,hasdayslimit:f!=void 0,daysoffset:e,dayslimit:f,nodayslimit:f==void 0}).then(function(a){m(b);if(a){s(b,a)}else{if(!t(b)){r(b)}}return a}).then(function(c){if(a.length<2){n(b)}else{o(b)}return c}).catch(function(){m(b)})},I=function(c){var d=u(c),g=w(c);return f.getEnrolledCoursesByTimelineClassification("inprogress",g,d,"fullname asc").then(function(b){var d=Date.now(),f=b.courses,g=b.nextoffset,i=x(c),j=y(c),k=z(c),m=A(c),n=B(c),o=c.closest(h.TIMELINE_BLOCK).find(h.TIMELINE_SEARCH).val();v(c,g);var p=G(f,m,n,o),q=H(f,c,k,i,j);return a.when(p,q).then(function(a){if(F(c,d)){return a}f.forEach(function(a){var b=a.id,d=c.find("[data-region=\"course-events-container\"][data-course-id=\""+b+"\"]"),f=d.find(e.rootSelector);e.init(f,l)});return a})}).catch(b.exception)},J=function(c){var d=Date.now(),f=A(c),g=B(c),i=c.find(h.COURSE_EVENTS_CONTAINER),k=i.map(function(){return a(this).attr("data-course-id")}).get(),m=c.closest(h.TIMELINE_BLOCK).find(h.TIMELINE_SEARCH).val();E(c,d);return C(k,f,j+1,g,m).then(function(b){if(F(c,d)){return b}i.each(function(b,c){c=a(c);var d=c.find(e.rootSelector);e.init(d,l)});return b}).catch(b.exception)},K=function(a){c.define(a,[c.events.activate]);a.on(c.events.activate,h.MORE_COURSES_BUTTON,function(b,c){p(a);I(a).then(function(){q(a)}).catch(function(){q(a)});if(c){c.originalEvent.preventDefault();c.originalEvent.stopPropagation()}b.stopPropagation()})},L=function(a){if(!a.attr("data-seen")){if(t(a)){J(a)}else{I(a)}a.attr("data-seen",!0)}};return{init:function init(b){b=a(b);E(b,Date.now());if(b.hasClass("active")){I(b);b.attr("data-seen",!0)}K(b)},reset:function reset(a){a.removeAttr("data-seen");if(a.hasClass("active")){L(a)}},shown:L}});
//# sourceMappingURL=view_courses.min.js.map
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("block_timeline/view_dates",["jquery","core/str","block_timeline/event_list","core/pubsub","core/paged_content_events"],function(a,b,c,d,e){var f={EVENT_LIST_CONTAINER:"[data-region=\"event-list-container\"]"},g=[5,10,25],h=function(a){var b=parseInt(a.data("limit"),10),c=!1,d=g.map(function(a){if(b==a){c=!0}return{value:a,active:b==a}});if(!c){d[0].active=!0}return d},i=function(b,c){var f=c+e.SET_ITEMS_PER_PAGE_LIMIT;d.subscribe(f,function(c){a(b).data("limit",c)})},j=function(d){var e=d.find(f.EVENT_LIST_CONTAINER),g=a(e).attr("id")+"user_block_timeline"+Math.random();i(d,g);var j=h(d),k={persistentLimitKey:"block_timeline_user_limit_preference",eventNamespace:g};b.get_string("ariaeventlistpaginationnavdates","block_timeline").then(function(a){c.init(e,j,{},a,k);return a}).catch(function(){c.init(e,j,{},"",k)})};return{init:function init(b){b=a(b);if(b.hasClass("active")){j(b);b.attr("data-seen",!0)}},reset:function reset(a){a.removeAttr("data-seen");if(a.hasClass("active")){j(a);a.attr("data-seen",!0)}},shown:function shown(a){if(!a.attr("data-seen")){j(a);a.attr("data-seen",!0)}}}});
define ("block_timeline/view_dates",["jquery","block_timeline/event_list","core/pubsub","core/paged_content_events"],function(a,b,c,d){var e={EVENT_LIST_CONTAINER:"[data-region=\"event-list-container\"]"},f=function(b,e){var f=e+d.SET_ITEMS_PER_PAGE_LIMIT;c.subscribe(f,function(c){a(b).data("limit",c)})},g=function(c){var d=c.find(e.EVENT_LIST_CONTAINER),g=a(d).attr("id")+"user_block_timeline"+Math.random();f(c,g);b.init(d,{persistentLimitKey:"block_timeline_user_limit_preference",eventNamespace:g})};return{init:function init(b){b=a(b);if(b.hasClass("active")){g(b);b.attr("data-seen",!0)}},reset:function reset(a){a.removeAttr("data-seen");if(a.hasClass("active")){g(a);a.attr("data-seen",!0)}},shown:function shown(a){if(!a.attr("data-seen")){g(a);a.attr("data-seen",!0)}}}});
//# sourceMappingURL=view_dates.min.js.map
File diff suppressed because one or more lines are too long
+283 -239
View File
@@ -26,7 +26,6 @@ define(
'jquery',
'core/notification',
'core/templates',
'core/paged_content_factory',
'core/str',
'core/user_date',
'block_timeline/calendar_events_repository'
@@ -35,7 +34,6 @@ function(
$,
Notification,
Templates,
PagedContentFactory,
Str,
UserDate,
CalendarEventsRepository
@@ -48,24 +46,24 @@ function(
EMPTY_MESSAGE: '[data-region="empty-message"]',
ROOT: '[data-region="event-list-container"]',
EVENT_LIST_CONTENT: '[data-region="event-list-content"]',
EVENT_LIST_WRAPPER: '[data-region="event-list-wrapper"]',
EVENT_LIST_LOADING_PLACEHOLDER: '[data-region="event-list-loading-placeholder"]',
TIMELINE_BLOCK: '[data-region="timeline"]',
TIMELINE_SEARCH: '[data-region="search-input"]'
TIMELINE_SEARCH: '[data-region="search-input"]',
MORE_ACTIVITIES_BUTTON: '[data-action="more-events"]',
MORE_ACTIVITIES_BUTTON_CONTAINER: '[data-region="more-events-button-container"]'
};
var TEMPLATES = {
EVENT_LIST_CONTENT: 'block_timeline/event-list-content'
EVENT_LIST_CONTENT: 'block_timeline/event-list-content',
MORE_ACTIVITIES_BUTTON: 'block_timeline/event-list-loadmore',
LOADING_ICON: 'core/loading'
};
// We want the paged content controls below the paged content area
// and the controls should be ignored while data is loading.
var DEFAULT_PAGED_CONTENT_CONFIG = {
ignoreControlWhileLoading: true,
controlPlacementBottom: true,
ariaLabels: {
itemsperpagecomponents: 'ariaeventlistpagelimit, block_timeline',
}
};
/** @type {number} The total items will be shown on the first load. */
const DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD = 5;
/** @type {number} The total items will be shown when click on the Show more activities button. */
const DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD = 10;
/**
* Hide the content area and display the empty content message.
@@ -211,219 +209,12 @@ function(
};
/**
* Handle a single page request from the paged content. Uses the given page data to request
* the events from the server.
* Create a lazy-loading region for the calendar events in the given root element.
*
* Checks the given preloadedPages before sending a request to the server to make sure we
* don't load data unnecessarily.
*
* @param {object} pageData A single page data (see core/paged_content_pages for more info).
* @param {object} actions Paged content actions (see core/paged_content_pages for more info).
* @param {Number} midnight The user's midnight time in unix timestamp.
* @param {object} lastIds The last event ID for each loaded page. Page number is key, id is value.
* @param {object} preloadedPages An object of preloaded page data. Page number as key, data promise as value.
* @param {int|undefined} courseId Course ID to restrict events to
* @param {Number} daysOffset How many days (from midnight) to offset the results from
* @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to
* @param {string|undefined} searchValue Search value
* @return {object} jQuery promise resolved with calendar events.
* @param {object} root The event list container element.
* @param {object} additionalConfig Additional config options to pass to pagedContentFactory.
*/
var loadEventsFromPageData = function(
pageData,
actions,
midnight,
lastIds,
preloadedPages,
courseId,
daysOffset,
daysLimit,
searchValue
) {
var pageNumber = pageData.pageNumber;
var limit = pageData.limit;
var lastPageNumber = pageNumber;
// This is here to protect us if, for some reason, the pages
// are loaded out of order somehow and we don't have a reference
// to the previous page. In that case, scan back to find the most
// recent page we've seen.
while (!lastIds.hasOwnProperty(lastPageNumber)) {
lastPageNumber--;
}
// Use the last id of the most recent page.
var lastId = lastIds[lastPageNumber];
var eventsPromise = null;
if (preloadedPages && preloadedPages.hasOwnProperty(pageNumber)) {
// This page has been preloaded so use that rather than load the values
// again.
eventsPromise = preloadedPages[pageNumber];
} else {
// Load one more than the given limit so that we can tell if there
// is more content to load after this.
eventsPromise = load(midnight, limit + 1, daysOffset, daysLimit, lastId, courseId, searchValue);
}
return eventsPromise.then(function(result) {
if (!result.events.length) {
// If we didn't get any events back then tell the paged content
// that we're done loading.
actions.allItemsLoaded(pageNumber);
return [];
}
// Determine if the overdue filter is applied.
const overdueFilter = document.querySelector("[data-filtername='overdue']");
const filterByOverdue = (overdueFilter && overdueFilter.getAttribute('aria-current'));
var calendarEvents = result.events.filter(function(event) {
if (event.eventtype == "open" || event.eventtype == "opensubmission") {
var dayTimestamp = UserDate.getUserMidnightForTimestamp(event.timesort, midnight);
return dayTimestamp > midnight;
}
// When filtering by overdue, we fetch all events due today, in case any have elapsed already and are overdue.
// This means if filtering by overdue, some events fetched might not be required (eg if due later today).
return (!filterByOverdue || event.overdue);
});
// We expect to receive limit + 1 events back from the server.
// Any less means there are no more events to load.
var loadedAll = calendarEvents.length <= limit;
if (loadedAll) {
// Tell the pagination that everything is loaded.
actions.allItemsLoaded(pageNumber);
} else {
// Remove the last element from the array because it isn't
// needed in this result set.
calendarEvents.pop();
}
return calendarEvents;
});
};
/**
* Use the paged content factory to create a paged content element for showing
* the event list. We only provide a page limit to the factory because we don't
* know exactly how many pages we'll need. This creates a paging bar with just
* next/previous buttons.
*
* This function specifies the callback for loading the event data that the user
* is requesting.
*
* @param {int|array} pageLimit A single limit or list of limits as options for the paged content
* @param {object} preloadedPages An object of preloaded page data. Page number as key, data promise as value.
* @param {Number} midnight The user's midnight time in unix timestamp.
* @param {object} firstLoad A jQuery promise to be resolved after the first set of data is loaded.
* @param {int|undefined} courseId Course ID to restrict events to
* @param {Number} daysOffset How many days (from midnight) to offset the results from
* @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to
* @param {string} paginationAriaLabel String to set as the aria label for the pagination bar.
* @param {object} additionalConfig Additional config options to pass to pagedContentFactory
* @param {string|undefined} searchValue Search value
* @return {object} jQuery promise.
*/
var createPagedContent = function(
pageLimit,
preloadedPages,
midnight,
firstLoad,
courseId,
daysOffset,
daysLimit,
paginationAriaLabel,
additionalConfig,
searchValue
) {
// Remember the last event id we loaded on each page because we can't
// use the offset value since the backend can skip events if the user doesn't
// have the capability to see them. Instead we load the next page of events
// based on the last seen event id.
var lastIds = {'1': 0};
var hasContent = false;
var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG, additionalConfig);
return Str.get_string(
'ariaeventlistpagelimit',
'block_timeline',
$.isArray(pageLimit) ? pageLimit[0].value : pageLimit
)
.then(function(string) {
config.ariaLabels.itemsperpage = string;
config.ariaLabels.paginationnav = paginationAriaLabel;
return string;
})
.then(function() {
return PagedContentFactory.createWithLimit(
pageLimit,
function(pagesData, actions) {
var promises = [];
pagesData.forEach(function(pageData) {
var pageNumber = pageData.pageNumber;
// Load the page data.
var pagePromise = loadEventsFromPageData(
pageData,
actions,
midnight,
lastIds,
preloadedPages,
courseId,
daysOffset,
daysLimit,
searchValue
).then(function(calendarEvents) {
if (calendarEvents.length) {
// Remember that we've loaded content.
hasContent = true;
// Remember the last id we've seen.
var lastEventId = calendarEvents[calendarEvents.length - 1].id;
// Record the id that the next page will need to start from.
lastIds[pageNumber + 1] = lastEventId;
// Get the HTML and JS for these calendar events.
return render(calendarEvents);
} else {
return calendarEvents;
}
})
.catch(Notification.exception);
promises.push(pagePromise);
});
$.when.apply($, promises).then(function() {
// Tell the calling code that the first page has been loaded
// and whether it contains any content.
firstLoad.resolve(hasContent);
return;
})
.catch(function() {
firstLoad.resolve(hasContent);
});
return promises;
},
config
);
});
};
/**
* Create a paged content region for the calendar events in the given root element.
* The content of the root element are replaced with a new paged content section
* each time this function is called.
*
* This function will be called each time the offset or limit values are changed to
* reload the event list region.
*
* @param {object} root The event list container element
* @param {int|array} pageLimit A single limit or list of limits as options for the paged content
* @param {object} preloadedPages An object of preloaded page data. Page number as key, data promise as value.
* @param {string} paginationAriaLabel String to set as the aria label for the pagination bar.
* @param {object} additionalConfig Additional config options to pass to pagedContentFactory
*/
var init = function(root, pageLimit, preloadedPages, paginationAriaLabel, additionalConfig = {}) {
var init = function(root, additionalConfig = {}) {
root = $(root);
courseview = !!additionalConfig.courseview;
@@ -453,31 +244,42 @@ function(
daysLimit = parseInt(daysLimit, 10);
}
// Created the paged content element.
return createPagedContent(pageLimit, preloadedPages, midnight, firstLoad, courseId, daysOffset, daysLimit,
paginationAriaLabel, additionalConfig, searchValue)
// Create the lazy loading content element.
return createLazyLoadingContent(root, firstLoad,
DEFAULT_LAZY_LOADING_ITEMS_FIRST_LOAD, midnight, 0, courseId, daysOffset, daysLimit, searchValue)
.then(function(html, js) {
html = $(html);
// Hide the content for now.
html.addClass('hidden');
// Replace existing elements with the newly created paged content.
// If we're reinitialising an existing event list this will replace
// the old event list (including removing any event handlers).
Templates.replaceNodeContents(eventListContent, html, js);
firstLoad.then(function(data) {
if (!data.hasContent) {
loadingPlaceholder.addClass('hidden');
// If we didn't get any data then show the empty data message.
return hideContent(root);
}
html = $(html);
// Hide the content for now.
html.addClass('hidden');
// Replace existing elements with the newly created lazy-loading region.
Templates.replaceNodeContents(eventListContent, html, js);
firstLoad.then(function(hasContent) {
// Prevent changing page elements too much by only showing the content
// once we've loaded some data for the first time. This allows our
// fancy loading placeholder to shine.
html.removeClass('hidden');
loadingPlaceholder.addClass('hidden');
if (!hasContent) {
// If we didn't get any data then show the empty data message.
hideContent(root);
if (!data.loadedAll) {
Templates.render(TEMPLATES.MORE_ACTIVITIES_BUTTON, {}).then(function(html) {
eventListContent.append(html);
setLastTimestamp(root, data.lastTimeStamp);
// Init the event handler.
initEventListener(root);
return html;
}).catch(function() {
return false;
});
}
return hasContent;
return data;
})
.catch(function() {
return false;
@@ -488,6 +290,248 @@ function(
.catch(Notification.exception);
};
/**
* Create a lazy-loading content element for showing the event list for the initial load.
*
* @param {object} root The event list container element.
* @param {object} firstLoad A jQuery promise to be resolved after the first set of data is loaded.
* @param {int} itemLimit Limit the number of items.
* @param {Number} midnight The user's midnight time in unix timestamp.
* @param {int} lastId The last event ID for each loaded page. Page number is key, id is value.
* @param {int|undefined} courseId Course ID to restrict events to.
* @param {Number} daysOffset How many days (from midnight) to offset the results from.
* @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to.
* @param {string|undefined} searchValue Search value.
* @return {object} jQuery promise resolved with calendar events.
*/
const createLazyLoadingContent = (root, firstLoad, itemLimit, midnight, lastId,
courseId, daysOffset, daysLimit, searchValue) => {
return loadEventsForLazyLoading(
root,
itemLimit,
midnight,
lastId,
courseId,
daysOffset,
daysLimit,
searchValue
).then(data => {
if (data.calendarEvents.length) {
const lastEventId = data.calendarEvents.at(-1).id;
const lastTimeStamp = data.calendarEvents.at(-1).timeusermidnight;
firstLoad.resolve({
hasContent: true,
lastId: lastEventId,
lastTimeStamp: lastTimeStamp,
loadedAll: data.loadedAll
});
return render(data.calendarEvents, midnight);
} else {
firstLoad.resolve({
hasContent: false,
lastId: 0,
lastTimeStamp: 0,
loadedAll: true
});
return data.calendarEvents;
}
}).catch(Notification.exception);
};
/**
* Handle the request from the lazy-loading region.
* Uses the given data like course id, offset... to request the events from the server.
*
* @param {object} root The event list container element.
* @param {int} itemLimit Limit the number of items.
* @param {Number} midnight The user's midnight time in unix timestamp.
* @param {int} lastId The last event ID for each loaded page.
* @param {int|undefined} courseId Course ID to restrict events to.
* @param {Number} daysOffset How many days (from midnight) to offset the results from.
* @param {int|undefined} daysLimit How many dates (from midnight) to limit the result to.
* @param {string|undefined} searchValue Search value.
* @return {object} jQuery promise resolved with calendar events.
*/
const loadEventsForLazyLoading = (root, itemLimit, midnight, lastId, courseId, daysOffset, daysLimit, searchValue) => {
// Load one more than the given limit so that we can tell if there
// is more content to load after this.
const eventsPromise = load(midnight, itemLimit + 1, daysOffset, daysLimit, lastId, courseId, searchValue);
let calendarEvents = [];
let loadedAll = true;
return eventsPromise.then(result => {
if (!result.events.length) {
return {calendarEvents, loadedAll};
}
// Determine if the overdue filter is applied.
const overdueFilter = document.querySelector("[data-filtername='overdue']");
const filterByOverdue = (overdueFilter && overdueFilter.getAttribute('aria-current'));
calendarEvents = result.events.filter(event => {
if (event.eventtype == 'open' || event.eventtype == 'opensubmission') {
const dayTimestamp = UserDate.getUserMidnightForTimestamp(event.timesort, midnight);
return dayTimestamp > midnight;
}
// When filtering by overdue, we fetch all events due today, in case any have elapsed already and are overdue.
// This means if filtering by overdue, some events fetched might not be required (eg if due later today).
return (!filterByOverdue || event.overdue);
});
loadedAll = calendarEvents.length <= itemLimit;
if (!loadedAll) {
// Remove the last element from the array because it isn't
// needed in this result set.
calendarEvents.pop();
}
if (calendarEvents.length) {
const lastEventId = calendarEvents.at(-1).id;
setOffset(root, lastEventId);
}
return {calendarEvents, loadedAll};
});
};
/**
* Load new events and append to current list.
*
* @param {object} root The event list container element.
*/
const loadMoreEvents = root => {
const midnight = parseInt(root.attr('data-midnight'), 10);
const courseId = root.attr('data-course-id');
const daysOffset = parseInt(root.attr('data-days-offset'), 10);
const daysLimit = root.attr('data-days-limit');
const lastId = getOffset(root);
const eventListWrapper = root.find(SELECTORS.EVENT_LIST_WRAPPER);
const searchValue = root.closest(SELECTORS.TIMELINE_BLOCK).find(SELECTORS.TIMELINE_SEARCH).val();
const eventsPromise = loadEventsForLazyLoading(
root,
DEFAULT_LAZY_LOADING_ITEMS_OTHER_LOAD,
midnight,
lastId,
courseId,
daysOffset,
daysLimit,
searchValue
);
eventsPromise.then(data => {
if (data.calendarEvents.length) {
const renderPromise = render(data.calendarEvents);
const lastTimestamp = getLastTimestamp(root);
renderPromise.then((html, js) => {
html = $(html);
// Remove the date heading if it has the same value as the previous one.
html.find(`[data-timestamp="${lastTimestamp}"]`).remove();
Templates.appendNodeContents(eventListWrapper, html.html(), js);
if (!data.loadedAll) {
Templates.render(TEMPLATES.MORE_ACTIVITIES_BUTTON, {}).then(html => {
eventListWrapper.append(html);
setLastTimestamp(root, data.calendarEvents.at(-1).timeusermidnight);
// Init the event handler.
initEventListener(root);
return html;
}).catch(() => {
return false;
});
}
return html;
}).catch(Notification.exception);
}
return data;
}).then(() => {
return disableMoreActivitiesButtonLoading(root);
}).catch(Notification.exception);
};
/**
* Return the offset value for lazy loading fetching.
*
* @param {object} element The event list container element.
* @return {Number} Offset value.
*/
const getOffset = element => {
return parseInt(element.attr('data-lazyload-offset'), 10);
};
/**
* Set the offset value for lazy loading fetching.
*
* @param {object} element The event list container element.
* @param {Number} offset Offset value.
*/
const setOffset = (element, offset) => {
element.attr('data-lazyload-offset', offset);
};
/**
* Return the timestamp value for lazy loading fetching.
*
* @param {object} element The event list container element.
* @return {Number} Timestamp value.
*/
const getLastTimestamp = element => {
return parseInt(element.attr('data-timestamp'), 10);
};
/**
* Set the timestamp value for lazy loading fetching.
*
* @param {object} element The event list container element.
* @param {Number} timestamp Timestamp value.
*/
const setLastTimestamp = (element, timestamp) => {
element.attr('data-timestamp', timestamp);
};
/**
* Add the "Show more activities" button and remove and loading spinner.
*
* @param {object} root The event list container element.
*/
const enableMoreActivitiesButtonLoading = root => {
const loadMoreButton = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON);
loadMoreButton.prop('disabled', true);
Templates.render(TEMPLATES.LOADING_ICON, {}).then(html => {
loadMoreButton.append(html);
return html;
}).catch(() => {
// It's not important if this false so just do so silently.
return false;
});
};
/**
* Remove the "Show more activities" button and remove and loading spinner.
*
* @param {object} root The event list container element.
*/
const disableMoreActivitiesButtonLoading = root => {
const loadMoreButtonContainer = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON_CONTAINER);
loadMoreButtonContainer.remove();
};
/**
* Event initialise.
*
* @param {object} root The event list container element.
*/
const initEventListener = root => {
const loadMoreButton = root.find(SELECTORS.MORE_ACTIVITIES_BUTTON);
loadMoreButton.on('click', () => {
enableMoreActivitiesButtonLoading(root);
loadMoreEvents(root);
});
};
return {
init: init,
rootSelector: SELECTORS.ROOT,
+2 -52
View File
@@ -25,7 +25,6 @@ define(
'jquery',
'core/notification',
'core/custom_interaction_events',
'core/str',
'core/templates',
'block_timeline/event_list',
'core_course/repository',
@@ -35,7 +34,6 @@ function(
$,
Notification,
CustomEvents,
Str,
Templates,
EventList,
CourseRepository,
@@ -424,33 +422,11 @@ function(
// correct course event list.
courses.forEach(function(course) {
var courseId = course.id;
var events = [];
var containerSelector = '[data-region="course-events-container"][data-course-id="' + courseId + '"]';
var courseEventsContainer = root.find(containerSelector);
var eventListRoot = courseEventsContainer.find(EventList.rootSelector);
var courseGroups = eventsByCourse.groupedbycourse.filter(function(group) {
return group.courseid == courseId;
});
if (courseGroups.length) {
// Get the events for this course.
events = courseGroups[0].events;
}
// Create a preloaded page to pass to the event list because we've already
// loaded the first page of events.
var pageOnePreload = $.Deferred().resolve({events: events}).promise();
// Initialise the event list pagination area for this course.
Str.get_string('ariaeventlistpaginationnavcourses', 'block_timeline', course.fullnamedisplay)
.then(function(string) {
EventList.init(eventListRoot, COURSE_EVENT_LIMIT, {'1': pageOnePreload}, string, additionalConfig);
return string;
})
.catch(function() {
// An error is ok, just render with the default string.
EventList.init(eventListRoot, COURSE_EVENT_LIMIT, {'1': pageOnePreload}, undefined,
additionalConfig);
});
EventList.init(eventListRoot, additionalConfig);
});
return eventsByCourse;
@@ -488,35 +464,9 @@ function(
courseEventsContainers.each(function(index, container) {
container = $(container);
var courseId = container.attr('data-course-id');
var courseName = container.find(SELECTORS.COURSE_NAME).text();
var eventListContainer = container.find(EventList.rootSelector);
var pageDeferred = $.Deferred();
var events = [];
var courseGroups = eventsByCourse.groupedbycourse.filter(function(group) {
return group.courseid == courseId;
});
if (courseGroups.length) {
// Get the events just for this course.
events = courseGroups[0].events;
}
pageDeferred.resolve({events: events});
// Re-initialise the events list with the preloaded events we just got from
// the server.
Str.get_string('ariaeventlistpaginationnavcourses', 'block_timeline', courseName)
.then(function(string) {
EventList.init(eventListContainer, COURSE_EVENT_LIMIT, {'1': pageDeferred.promise()},
string, additionalConfig);
return string;
})
.catch(function() {
// Ignore a failure to load the string. Just render with the default string.
EventList.init(eventListContainer, COURSE_EVENT_LIMIT, {'1': pageDeferred.promise()},
undefined, additionalConfig);
});
EventList.init(eventListContainer, additionalConfig);
});
return eventsByCourse;
+1 -41
View File
@@ -23,14 +23,12 @@
define(
[
'jquery',
'core/str',
'block_timeline/event_list',
'core/pubsub',
'core/paged_content_events'
],
function(
$,
Str,
EventList,
PubSub,
PagedContentEvents
@@ -40,35 +38,6 @@ function(
EVENT_LIST_CONTAINER: '[data-region="event-list-container"]',
};
var DEFAULT_PAGE_LIMIT = [5, 10, 25];
/**
* Generate a paged content array of limits taking into account user preferences
*
* @param {object} root The root element for the timeline dates view.
* @return {array} Array of limit objects
*/
var getPagingLimits = function(root) {
var limitPref = parseInt(root.data('limit'), 10);
var isDefaultSet = false;
var limits = DEFAULT_PAGE_LIMIT.map(function(value) {
if (limitPref == value) {
isDefaultSet = true;
}
return {
value: value,
active: limitPref == value
};
});
if (!isDefaultSet) {
limits[0].active = true;
}
return limits;
};
/**
* Setup the listeners for the timeline block
*
@@ -92,20 +61,11 @@ function(
var namespace = $(eventListContainer).attr('id') + "user_block_timeline" + Math.random();
registerEventListeners(root, namespace);
var limits = getPagingLimits(root);
var config = {
persistentLimitKey: "block_timeline_user_limit_preference",
eventNamespace: namespace
};
Str.get_string('ariaeventlistpaginationnavdates', 'block_timeline')
.then(function(string) {
EventList.init(eventListContainer, limits, {}, string, config);
return string;
})
.catch(function() {
// Ignore if we can't load the string. Still init the event list.
EventList.init(eventListContainer, limits, {}, "", config);
});
EventList.init(eventListContainer, config);
};
/**
+7 -4
View File
@@ -25,14 +25,12 @@
$string['ariadayfilter'] = 'Filter timeline by date';
$string['ariadayfilteroption'] = '{$a} filter option';
$string['ariaeventlistitem'] = '{$a->name} activity in {$a->course} is due on {$a->date}';
$string['ariaeventlistpagelimit'] = 'Show {$a} activities per page';
$string['ariaeventlistpaginationnavdates'] = 'Timeline activities pagination';
$string['ariaeventlistpaginationnavcourses'] = 'Timeline activities for course {$a} pagination';
$string['ariaviewselector'] = 'Sort timeline items';
$string['ariaviewselectoroption'] = '{$a} sort option';
$string['clearsearch'] = 'Clear search';
$string['duedate'] = 'Due date';
$string['morecourses'] = 'More courses';
$string['moreactivities'] = 'Show more activities';
$string['morecourses'] = 'Show more courses';
$string['timeline:myaddinstance'] = 'Add a new timeline block to Dashboard';
$string['nocoursesinprogress'] = 'No in-progress courses';
$string['noevents'] = 'No activities require action';
@@ -51,3 +49,8 @@ $string['viewcourse'] = 'View course';
$string['privacy:metadata:timelinesortpreference'] = 'The user sort preference for the timeline block.';
$string['privacy:metadata:timelinefilterpreference'] = 'The user day filter preference for the timeline block.';
$string['privacy:metadata:timelinelimitpreference'] = 'The user page limit preference for the timeline block.';
// Deprecated since Moodle 4.0.
$string['ariaeventlistpagelimit'] = 'Show {$a} activities per page';
$string['ariaeventlistpaginationnavdates'] = 'Timeline activities pagination';
$string['ariaeventlistpaginationnavcourses'] = 'Timeline activities for course {$a} pagination';
+3
View File
@@ -0,0 +1,3 @@
ariaeventlistpagelimit,block_timeline
ariaeventlistpaginationnavdates,block_timeline
ariaeventlistpaginationnavcourses,block_timeline
@@ -63,9 +63,9 @@
]
}
}}
<div class="pb-2">
<div class="pb-2" data-region="event-list-wrapper">
{{#eventsbyday}}
<div class="mt-3">
<div class="mt-3" data-region="event-list-content-date" data-timestamp="{{dayTimestamp}}">
<h5 class="h6 d-inline {{^courseview}}font-weight-bold{{/courseview}}">{{#userdate}} {{dayTimestamp}}, {{#str}} strftimedaydate, core_langconfig {{/str}} {{/userdate}}</h5>
</div>
{{> block_timeline/event-list-items }}
@@ -0,0 +1,31 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template block_timeline/event-list-loadmore
This template renders a show more activities button.
Example context (json):
{
}
}}
<div class="pt-1 pb-2" data-region="more-events-button-container">
<button type="button" class="btn btn-secondary btn-sm" data-action="more-events">
{{#str}} moreactivities, block_timeline {{/str}}
</button>
</div>
@@ -30,8 +30,8 @@
<div class="bg-pulse-grey mt-1" style="width: 100px; height: 30px; margin-left: auto; margin-right: auto"></div>
</div>
<ul class="list-group unstyled" data-region="courses-list"></ul>
<div class="hidden text-xs-left text-left pt-3" data-region="more-courses-button-container">
<button type="button" class="btn btn-secondary" data-action="more-courses">
<div class="hidden text-xs-center text-center pt-3" data-region="more-courses-button-container">
<button type="button" class="btn btn-primary" data-action="more-courses">
{{#str}} morecourses, block_timeline {{/str}}
<span class="hidden" data-region="loading-icon-container">
{{> core/loading }}
@@ -44,7 +44,7 @@ Feature: The timeline block allows users to see upcoming courses
When I click on "Sort by courses" "link" in the "Timeline" "block"
Then I should see "Course 1" in the "Timeline" "block"
And I should see "Course 2" in the "Timeline" "block"
And I should see "More courses" in the "Timeline" "block"
And I should see "Show more courses" in the "Timeline" "block"
And "Test choice 1" "link" should exist in the "Timeline" "block"
And I should see "Choice closes" in the "Timeline" "block"
And "Test feedback 1" "link" should exist in the "Timeline" "block"
@@ -64,7 +64,7 @@ Feature: The timeline block allows users to see upcoming courses
And I click on "All" "link" in the "Timeline" "block"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
And I click on "Sort by courses" "link" in the "Timeline" "block"
When I click on "More courses" "button" in the "Timeline" "block"
When I click on "Show more courses" "button" in the "Timeline" "block"
Then I should see "Course 3" in the "Timeline" "block"
And I should see "Course 2" in the "Timeline" "block"
And I should see "Course 1" in the "Timeline" "block"
@@ -78,7 +78,7 @@ Feature: The timeline block allows users to see upcoming courses
And "Test assign 2" "link" should exist in the "Timeline" "block"
And I should see "Assignment is due" in the "Timeline" "block"
And I should see "Choice closes" in the "Timeline" "block"
And I should not see "More courses" in the "Timeline" "block"
And I should not see "Show more courses" in the "Timeline" "block"
And I should not see "Course 4" in the "Timeline" "block"
And "Test choice 2" "link" should not exist in the "Timeline" "block"
And I should not see "Test feedback 4" in the "Timeline" "block"
@@ -92,7 +92,7 @@ Feature: The timeline block allows users to see upcoming courses
When I reload the page
Then I should see "Course 1" in the "Timeline" "block"
And I should see "Course 2" in the "Timeline" "block"
And I should see "More courses" in the "Timeline" "block"
And I should see "Show more courses" in the "Timeline" "block"
And "Test choice 1" "link" should exist in the "Timeline" "block"
And "Test feedback 1" "link" should exist in the "Timeline" "block"
And "Test feedback 5" "link" should exist in the "Timeline" "block"
@@ -111,7 +111,7 @@ Feature: The timeline block allows users to see upcoming courses
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
And I click on "All" "link" in the "Timeline" "block"
When I reload the page
And I click on "More courses" "button" in the "Timeline" "block"
And I click on "Show more courses" "button" in the "Timeline" "block"
Then I should see "Course 3" in the "Timeline" "block"
And I should see "Course 2" in the "Timeline" "block"
And I should see "Course 1" in the "Timeline" "block"
@@ -121,7 +121,7 @@ Feature: The timeline block allows users to see upcoming courses
And "Test feedback 2" "link" should exist in the "Timeline" "block"
And "Test feedback 3" "link" should exist in the "Timeline" "block"
And "Test assign 1" "link" should exist in the "Timeline" "block"
And I should not see "More courses" in the "Timeline" "block"
And I should not see "Show more courses" in the "Timeline" "block"
And I should not see "Course 4" in the "Timeline" "block"
And "Test choice 2" "link" should not exist in the "Timeline" "block"
And "Test feedback 4" "link" should not exist in the "Timeline" "block"
@@ -142,7 +142,7 @@ Feature: The timeline block allows users to see upcoming courses
When I click on "All" "link" in the "Timeline" "block"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
And I click on "Sort by courses" "link" in the "Timeline" "block"
And I click on "More courses" "button" in the "Timeline" "block"
And I click on "Show more courses" "button" in the "Timeline" "block"
Then "Test assign 1" "link" should exist in the "Timeline" "block"
And "Test feedback 2" "link" should exist in the "Timeline" "block"
@@ -80,39 +80,15 @@ Feature: The timeline block allows users to see upcoming activities
And I should see "Course 2 · Feedback closes" in the "Timeline" "block"
And "Test choice 2" "link" should not exist in the "Timeline" "block"
And "Test feedback 2" "link" should not exist in the "Timeline" "block"
And I click on "[data-region='paging-bar'] [data-control='next'] [data-region='page-link']" "css_element" in the "Timeline" "block"
And I click on "Show more activities" "button"
And "Test feedback 2" "link" should exist in the "Timeline" "block"
And I should see "Course 1 · Feedback closes" in the "Timeline" "block"
And "Test choice 3" "link" should exist in the "Timeline" "block"
And I should see "Course 3 · Choice closes" in the "Timeline" "block"
And "Test feedback 3" "link" should exist in the "Timeline" "block"
And I should see "Course 3 · Feedback closes" in the "Timeline" "block"
And I should not see "Test assign 1" in the "Timeline" "block"
And I should not see "Test feedback 1" in the "Timeline" "block"
And I should not see "Test choice 1" in the "Timeline" "block"
And I should not see "Test choice 2" in the "Timeline" "block"
Scenario: All in date view no next
Given I log in as "student1"
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
And I click on "All" "link" in the "Timeline" "block"
And I click on "5" "button" in the "Timeline" "block"
When I click on "25" "link" in the "Timeline" "block"
Then "Test assign 1" "link" should exist in the "Timeline" "block"
And I should see "Course 1 · Assignment is due" in the "Timeline" "block"
And "Test assign 2" "link" should exist in the "Timeline" "block"
And I should see "Course 2 · Assignment is due" in the "Timeline" "block"
And "Test feedback 1" "link" should exist in the "Timeline" "block"
And "Test feedback 4" "link" should exist in the "Timeline" "block"
And I should see "Course 2 · Feedback closes" in the "Timeline" "block"
And "Test choice 1" "link" should exist in the "Timeline" "block"
And I should see "Course 2 · Choice closes" in the "Timeline" "block"
And "Test choice 3" "link" should exist in the "Timeline" "block"
And I should see "Course 3 · Choice closes" in the "Timeline" "block"
And "Test feedback 3" "link" should exist in the "Timeline" "block"
And I should see "Course 3 · Feedback closes" in the "Timeline" "block"
And "Test feedback 2" "link" should exist in the "Timeline" "block"
And I should see "Course 1 · Feedback closes" in the "Timeline" "block"
And I should see "Test assign 1" in the "Timeline" "block"
And I should see "Test feedback 1" in the "Timeline" "block"
And I should see "Test choice 1" in the "Timeline" "block"
And I should see "Test choice 3" in the "Timeline" "block"
And I should see "Test feedback 3" in the "Timeline" "block"
And I should not see "Test choice 2" in the "Timeline" "block"
Scenario: Persistent All in date view
@@ -132,17 +108,15 @@ Feature: The timeline block allows users to see upcoming activities
And I should see "Course 2 · Feedback closes" in the "Timeline" "block"
And I should not see "Test choice 2" in the "Timeline" "block"
And I should not see "Test feedback 2" in the "Timeline" "block"
And I click on "[data-region='paging-bar'] [data-control='next']" "css_element" in the "Timeline" "block"
And I click on "Show more activities" "button"
And "Test feedback 2" "link" should exist in the "Timeline" "block"
And I should see "Course 1 · Feedback closes" in the "Timeline" "block"
And "Test choice 3" "link" should exist in the "Timeline" "block"
And I should see "Course 3 · Choice closes" in the "Timeline" "block"
And "Test feedback 3" "link" should exist in the "Timeline" "block"
And I should see "Course 3 · Feedback closes" in the "Timeline" "block"
And I should not see "Test assign 1" in the "Timeline" "block"
And I should not see "Test feedback 1" in the "Timeline" "block"
And I should not see "Test choice 1" in the "Timeline" "block"
And I should see "Test assign 1" in the "Timeline" "block"
And I should see "Test feedback 1" in the "Timeline" "block"
And I should see "Test feedback 3" in the "Timeline" "block"
And I should see "Test choice 1" in the "Timeline" "block"
And I should not see "Test choice 2" in the "Timeline" "block"
And I should see "Test choice 3" in the "Timeline" "block"
Scenario: Persistent Overdue in date view
Given I log in as "student1"
@@ -165,9 +139,6 @@ Feature: The timeline block allows users to see upcoming activities
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
And I click on "Overdue" "link" in the "Timeline" "block"
And I reload the page
# Expand to 25 results, to ensure we see the earliest and latest timeline items.
And I click on "Show 5 activities per page" "button" in the "Timeline" "block"
And I click on "25" "link"
And "Test assign 1" "link" should exist in the "Timeline" "block"
And "Test feedback 2" "link" should not exist in the "Timeline" "block"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
@@ -178,4 +149,5 @@ Feature: The timeline block allows users to see upcoming activities
And I click on "Sort timeline items" "button" in the "Timeline" "block"
And I click on "Sort by dates" "link" in the "Timeline" "block"
Then "Test assign 1" "link" should exist in the "Timeline" "block"
And I click on "Show more activities" "button"
And "Test feedback 2" "link" should exist in the "Timeline" "block"
@@ -0,0 +1,90 @@
@block @block_timeline @javascript
Feature: The timeline block allows users to use the lazy loading to view more activities
Background:
Given the following "users" exist:
| username | firstname | lastname | email | idnumber |
| student1 | Student | 1 | student1@example.com | S1 |
And the following "courses" exist:
| fullname | shortname | category | startdate | enddate |
| Course 1 | C1 | 0 | ##yesterday## | ##last day of next month## |
| Course 2 | C2 | 0 | ##yesterday## | ##last day of next month## |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
And the following "activities" exist:
| activity | course | idnumber | name | intro | timeopen | timeclose |
| choice | C1 | choice1 | Test choice 1 | Test choice description | ##yesterday## | ##tomorrow## |
| choice | C1 | choice2 | Test choice 2 | Test choice description | ##yesterday## | ##+1 days## |
| choice | C1 | choice3 | Test choice 3 | Test choice description | ##yesterday## | ##+2 days## |
| choice | C1 | choice4 | Test choice 4 | Test choice description | ##yesterday## | ##+3 days## |
| choice | C1 | choice5 | Test choice 5 | Test choice description | ##yesterday## | ##+4 days## |
| choice | C1 | choice6 | Test choice 6 | Test choice description | ##yesterday## | ##+5 days## |
| choice | C1 | choice7 | Test choice 7 | Test choice description | ##yesterday## | ##+6 days## |
| choice | C1 | choice8 | Test choice 8 | Test choice description | ##yesterday## | ##+7 days## |
| choice | C1 | choice9 | Test choice 9 | Test choice description | ##yesterday## | ##+8 days## |
| choice | C1 | choice10 | Test choice 10 | Test choice description | ##yesterday## | ##+9 days## |
| choice | C2 | choice10 | Test choice 11 | Test choice description | ##yesterday## | ##+9 days## |
And the following "activities" exist:
| activity | course | idnumber | name | intro | timeopen | duedate |
| assign | C1 | assign1 | Test assign 1 | Test assign description | ##1 month ago## | ##yesterday## |
Scenario: Lazy loading for date view
Given I log in as "student1"
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
When I click on "All" "link" in the "Timeline" "block"
Then I should see "Test choice 1" in the "Timeline" "block"
And "Test assign 1" "link" should exist in the "Timeline" "block"
And "Test choice 1" "link" should exist in the "Timeline" "block"
And "Test choice 2" "link" should exist in the "Timeline" "block"
And "Test choice 3" "link" should exist in the "Timeline" "block"
And "Test choice 4" "link" should exist in the "Timeline" "block"
And "Test choice 5" "link" should not exist in the "Timeline" "block"
And "Test choice 6" "link" should not exist in the "Timeline" "block"
And "Test choice 7" "link" should not exist in the "Timeline" "block"
And "Test choice 8" "link" should not exist in the "Timeline" "block"
And "Test choice 9" "link" should not exist in the "Timeline" "block"
And "Test choice 10" "link" should not exist in the "Timeline" "block"
And "Test choice 11" "link" should not exist in the "Timeline" "block"
And I click on "Show more activities" "button" in the "[data-region='view-dates']" "css_element"
And "Test choice 5" "link" should exist in the "Timeline" "block"
And "Test choice 6" "link" should exist in the "Timeline" "block"
And "Test choice 7" "link" should exist in the "Timeline" "block"
And "Test choice 8" "link" should exist in the "Timeline" "block"
And "Test choice 9" "link" should exist in the "Timeline" "block"
And "Test choice 10" "link" should exist in the "Timeline" "block"
And "Test choice 11" "link" should exist in the "Timeline" "block"
Scenario: Lazy loading for course view
Given I log in as "student1"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
When I click on "Sort by courses" "link" in the "Timeline" "block"
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
And I click on "All" "link" in the "Timeline" "block"
And "Test choice 1" "link" should exist in the "Timeline" "block"
And "Test choice 2" "link" should exist in the "Timeline" "block"
And "Test choice 3" "link" should exist in the "Timeline" "block"
And "Test choice 4" "link" should exist in the "Timeline" "block"
And "Test choice 5" "link" should exist in the "Timeline" "block"
And "Test choice 11" "link" should exist in the "Timeline" "block"
And "Test choice 6" "link" should not exist in the "Timeline" "block"
And "Test choice 7" "link" should not exist in the "Timeline" "block"
And "Test choice 8" "link" should not exist in the "Timeline" "block"
And "Test choice 9" "link" should not exist in the "Timeline" "block"
And "Test choice 10" "link" should not exist in the "Timeline" "block"
And I click on "Show more activities" "button" in the "[data-region='view-courses']" "css_element"
And "Test choice 6" "link" should exist in the "Timeline" "block"
And "Test choice 7" "link" should exist in the "Timeline" "block"
And "Test choice 8" "link" should exist in the "Timeline" "block"
And "Test choice 9" "link" should exist in the "Timeline" "block"
And "Test choice 10" "link" should exist in the "Timeline" "block"
Scenario: The lazy loading button will not be shown if the number of events is smaller than 5
Given I log in as "student1"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
And I click on "Sort by dates" "link" in the "Timeline" "block"
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
When I click on "Overdue" "link" in the "Timeline" "block"
Then "Test assign 1" "link" should exist in the "Timeline" "block"
And "Show more activities" "button" should not exist in the "[data-region='view-courses']" "css_element"
@@ -1,64 +0,0 @@
@block @block_timeline @javascript
Feature: The timeline block allows user persistence of their page limits
Background:
Given the following "users" exist:
| username | firstname | lastname | email | idnumber |
| student1 | Student | 1 | student1@example.com | S1 |
And the following "courses" exist:
| fullname | shortname | category | startdate | enddate |
| Course 1 | C1 | 0 | ##1 month ago## | ##15 days ago## |
| Course 2 | C2 | 0 | ##yesterday## | ##tomorrow## |
| Course 3 | C3 | 0 | ##first day of next month## | ##last day of next month## |
| Course 4 | C4 | 0 | ##first day of next month## | ##last day of next month## |
| Course 5 | C5 | 0 | ##first day of next month## | ##last day of next month## |
| Course 6 | C6 | 0 | ##first day of next month## | ##last day of next month## |
And the following "activities" exist:
| activity | course | idnumber | name | intro | timeopen | timeclose |
| choice | C2 | choice1 | Test choice 1 | Test choice description | ##yesterday## | ##tomorrow## |
| choice | C1 | choice2 | Test choice 2 | Test choice description | ##1 month ago## | ##15 days ago## |
| choice | C3 | choice3 | Test choice 3 | Test choice description | ##first day of +5 months## | ##last day of +5 months## |
| feedback | C2 | feedback1 | Test feedback 1 | Test feedback description | ##yesterday## | ##tomorrow## |
| feedback | C1 | feedback2 | Test feedback 2 | Test feedback description | ##first day of +10 months## | ##last day of +10 months## |
| feedback | C3 | feedback3 | Test feedback 3 | Test feedback description | ##first day of +5 months## | ##last day of +5 months## |
And the following "activities" exist:
| activity | course | idnumber | name | intro | timeopen | duedate |
| assign | C1 | assign1 | Test assign 1 | Test assign description | ##1 month ago## | ##yesterday## |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
Scenario: Toggle the page limit 5 - 25
Given I log in as "student1"
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
And I click on "All" "link" in the "Timeline" "block"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
And I click on "Sort by dates" "link" in the "Timeline" "block"
When I click on "5" "button" in the "Timeline" "block"
And I click on "25" "link"
Then I should see "Test feedback 2" in the "Timeline" "block"
And I reload the page
Then I should see "Test feedback 2" in the "Timeline" "block"
And I log out
Scenario: Toggle the page limit 25 - 5
Given I log in as "student1"
And I click on "Filter timeline by date" "button" in the "Timeline" "block"
And I click on "All" "link" in the "Timeline" "block"
And I click on "Sort timeline items" "button" in the "Timeline" "block"
And I click on "Sort by dates" "link" in the "Timeline" "block"
When I click on "5" "button" in the "Timeline" "block"
And I click on "25" "link"
And I should see "Test feedback 2" in the "Timeline" "block"
And I change window size to "large"
And I click on "25" "button" in the "Timeline" "block"
And I click on "5" "link" in the "[data-region='timeline'] [data-region='paging-control-limit-container'] .dropdown-menu" "css_element"
Then I should not see "Test feedback 2" in the "Timeline" "block"
And I reload the page
And I should not see "Test feedback 2" in the "Timeline" "block"
And I log out
@@ -91,5 +91,5 @@ Feature: The timeline block allows users to search for upcoming activities
And I should see "Test choice 4" in the "Timeline" "block"
And I should see "Test choice 5" in the "Timeline" "block"
And I should not see "Test choice 6" in the "Timeline" "block"
And I click on "[data-control='next']" "css_element" in the "Timeline" "block"
And I click on "Show more activities" "button"
And I should see "Test choice 6" in the "Timeline" "block"