Merge branch 'MDL-61138-master-require-context-id' of git://github.com/ryanwyllie/moodle
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
define(["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter"},d=function(a,b){return b=b||[],!(!b.length||b.indexOf(a)===-1)},e=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},f=function(b,c,d){b.off("keydown."+c).on("keydown."+c,function(b){e(b)||b.keyCode==d&&a(b.target).trigger(c,[{originalEvent:b}])})},g=function(d){d.off("click.cie.activate").on("click.cie.activate",function(b){a(b.target).trigger(c.activate,[{originalEvent:b}])}),d.off("keydown.cie.activate").on("keydown.cie.activate",function(d){e(d)||d.keyCode!=b.enter&&d.keyCode!=b.space||a(d.target).trigger(c.activate,[{originalEvent:d}])})},h=function(d){d.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(d){e(d)||d.keyCode!=b.enter&&d.keyCode!=b.space||a(d.target).trigger(c.keyboardActivate,[{originalEvent:d}])})},i=function(a){f(a,c.escape,b.escape)},j=function(a){f(a,c.down,b.arrowDown)},k=function(a){f(a,c.up,b.arrowUp)},l=function(a){f(a,c.home,b.home)},m=function(a){f(a,c.end,b.end)},n=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;f(d,c.next,e)},o=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;f(d,c.previous,e)},p=function(a){f(a,c.asterix,b.asterix)},q=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();0===d&&a.trigger(c.scrollTop,[{originalEvent:b}])})},r=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;d+e>=f&&a.trigger(c.scrollBottom,[{originalEvent:b}])})},s=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),g="DOMMouseScroll"==b.type?b.originalEvent.detail*-40:b.originalEvent.wheelDelta,h=g>0;return!h&&-g>e-f-d?(a.scrollTop(e),b.stopPropagation(),b.preventDefault(),b.returnValue=!1,a.trigger(c.scrollLock,[{originalEvent:b}]),!1):!(h&&g>d)||(a.scrollTop(0),b.stopPropagation(),b.preventDefault(),b.returnValue=!1,a.trigger(c.scrollLock,[{originalEvent:b}]),!1)})},t=function(d){d.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(d){d.ctrlKey&&d.keyCode==b.pageUp&&a(d.target).trigger(c.ctrlPageUp,[{originalEvent:d}])})},u=function(d){d.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(d){d.ctrlKey&&d.keyCode==b.pageDown&&a(d.target).trigger(c.ctrlPageDown,[{originalEvent:d}])})},v=function(a){f(a,c.enter,b.enter)},w=function(){var a={};return a[c.activate]=g,a[c.keyboardActivate]=h,a[c.escape]=i,a[c.down]=j,a[c.up]=k,a[c.home]=l,a[c.end]=m,a[c.next]=n,a[c.previous]=o,a[c.asterix]=p,a[c.scrollLock]=s,a[c.scrollTop]=q,a[c.scrollBottom]=r,a[c.ctrlPageUp]=t,a[c.ctrlPageDown]=u,a[c.enter]=v,a},x=function(b,c){b=a(b),c=c||[],b.length&&c.length&&a.each(w(),function(a,e){d(a,c)&&e(b)})};return{define:x,events:c}});
|
||||
define(["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter"},d={},e=function(a,b){return b=b||[],!(!b.length||b.indexOf(a)===-1)},f=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},g=function(b,c){var e="";return c.hasOwnProperty("originalEvent")?(e="triggeredCustom_"+b,c.originalEvent.hasOwnProperty(e)?void 0:(c.originalEvent[e]=!0,void a(c.target).trigger(b,[{originalEvent:c}]))):(e=""+b+c.type+c.timeStamp,void(d.hasOwnProperty(e)||(d[e]=!0,a(c.target).trigger(b,[{originalEvent:c}]))))},h=function(a,b,c){a.off("keydown."+b).on("keydown."+b,function(a){f(a)||a.keyCode==c&&g(b,a)})},i=function(a){a.off("click.cie.activate").on("click.cie.activate",function(a){g(c.activate,a)}),a.off("keydown.cie.activate").on("keydown.cie.activate",function(a){f(a)||a.keyCode!=b.enter&&a.keyCode!=b.space||g(c.activate,a)})},j=function(a){a.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(a){f(a)||a.keyCode!=b.enter&&a.keyCode!=b.space||g(c.keyboardActivate,a)})},k=function(a){h(a,c.escape,b.escape)},l=function(a){h(a,c.down,b.arrowDown)},m=function(a){h(a,c.up,b.arrowUp)},n=function(a){h(a,c.home,b.home)},o=function(a){h(a,c.end,b.end)},p=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;h(d,c.next,e)},q=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;h(d,c.previous,e)},r=function(a){h(a,c.asterix,b.asterix)},s=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();0===d&&g(c.scrollTop,b)})},t=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;d+e>=f&&g(c.scrollBottom,b)})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?b.originalEvent.detail*-40:b.originalEvent.wheelDelta,i=h>0;return!i&&-h>e-f-d?(a.scrollTop(e),b.stopPropagation(),b.preventDefault(),b.returnValue=!1,g(c.scrollLock,b),!1):!(i&&h>d)||(a.scrollTop(0),b.stopPropagation(),b.preventDefault(),b.returnValue=!1,g(c.scrollLock,b),!1)})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){a.ctrlKey&&a.keyCode==b.pageUp&&g(c.ctrlPageUp,a)})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){a.ctrlKey&&a.keyCode==b.pageDown&&g(c.ctrlPageDown,a)})},x=function(a){h(a,c.enter,b.enter)},y=function(){var a={};return a[c.activate]=i,a[c.keyboardActivate]=j,a[c.escape]=k,a[c.down]=l,a[c.up]=m,a[c.home]=n,a[c.end]=o,a[c.next]=p,a[c.previous]=q,a[c.asterix]=r,a[c.scrollLock]=u,a[c.scrollTop]=s,a[c.scrollBottom]=t,a[c.ctrlPageUp]=v,a[c.ctrlPageDown]=w,a[c.enter]=x,a},z=function(b,c){b=a(b),c=c||[],b.length&&c.length&&a.each(y(),function(a,d){e(a,c)&&d(b)})};return{define:z,events:c}});
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
define(["jquery","core/modal_events","core/modal_registry","core/modal","core/modal_save_cancel","core/modal_confirm","core/modal_cancel","core/templates","core/notification","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h,i,j){var k={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CONFIRM:"core/modal_save_cancel",CANCEL:"core/modal_cancel"},l={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CONFIRM:"CONFIRM",CANCEL:"CANCEL"};c.register(l.DEFAULT,d,k.DEFAULT),c.register(l.SAVE_CANCEL,e,k.SAVE_CANCEL),c.register(l.CONFIRM,f,k.CONFIRM),c.register(l.CANCEL,g,k.CANCEL);var m=function(a,c){if("undefined"!=typeof c){var d=null;if(Array.isArray(c)){var e=c[1];c=c[0],j.define(c,[j.events.activate]),c.on(j.events.activate,e,function(b,c){d=b.currentTarget,a.then(function(a){return a.show(),a}),c.originalEvent.preventDefault()})}else j.define(c,[j.events.activate]),c.on(j.events.activate,function(b,c){d=b.currentTarget,a.then(function(a){return a.show(),a}),c.originalEvent.preventDefault()});a.then(function(a){return a.getRoot().on(b.hidden,function(){null!==d&&d.focus()}),a})}},n=function(b,c){c=a(c);var d=b.module,e=new d(c);return e},o=function(b,c,d){var e=b.template,f=h.render(e,c).then(function(c){var d=a(c);return n(b,d)}).fail(i.exception);return m(f,d),f},p=function(a,b){var d=a.type||l.DEFAULT,e=!!a.large,f=null,g={};return f=c.get(d),f||i.exception({message:"Unable to find modal of type: "+d}),"undefined"!=typeof a.templateContext&&(g=a.templateContext),o(f,g,b).then(function(b){return"undefined"!=typeof a.title&&b.setTitle(a.title),"undefined"!=typeof a.body&&b.setBody(a.body),"undefined"!=typeof a.footer&&b.setFooter(a.footer),e&&b.setLarge(),b})};return{create:p,types:l}});
|
||||
define(["jquery","core/modal_events","core/modal_registry","core/modal","core/modal_save_cancel","core/modal_confirm","core/modal_cancel","core/templates","core/notification","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h,i,j){var k={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CONFIRM:"core/modal_save_cancel",CANCEL:"core/modal_cancel"},l={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CONFIRM:"CONFIRM",CANCEL:"CANCEL"};c.register(l.DEFAULT,d,k.DEFAULT),c.register(l.SAVE_CANCEL,e,k.SAVE_CANCEL),c.register(l.CONFIRM,f,k.CONFIRM),c.register(l.CANCEL,g,k.CANCEL);var m=function(c,d,e){var f=null,g="function"==typeof e.preShowCallback,h=function(b,d){f=a(b.currentTarget),c.then(function(a){return g&&e.preShowCallback(f,a),a.show(),a}),d.originalEvent.preventDefault()};if(Array.isArray(d)){var i=d[1];d=d[0],j.define(d,[j.events.activate]),d.on(j.events.activate,i,h)}else j.define(d,[j.events.activate]),d.on(j.events.activate,h);c.then(function(a){return a.getRoot().on(b.hidden,function(){null!==f&&f.focus()}),a})},n=function(b,c){c=a(c);var d=b.module,e=new d(c);return e},o=function(b,c){var d=b.template,e=h.render(d,c).then(function(c){var d=a(c);return n(b,d)}).fail(i.exception);return e},p=function(a,b){var d=a.type||l.DEFAULT,e=!!a.large,f=null,g={};f=c.get(d),f||i.exception({message:"Unable to find modal of type: "+d}),"undefined"!=typeof a.templateContext&&(g=a.templateContext);var h=o(f,g).then(function(b){return"undefined"!=typeof a.title&&b.setTitle(a.title),"undefined"!=typeof a.body&&b.setBody(a.body),"undefined"!=typeof a.footer&&b.setFooter(a.footer),e&&b.setLarge(),b});return"undefined"!=typeof b&&m(h,b,a),h};return{create:p,types:l}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
define([],function(){return{SHOW_PAGES:"core-paged-content-show-pages"}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
define(["jquery","core/templates","core/notification","core/paged_content_pages"],function(a,b,c,d){var e={PAGED_CONTENT:"core/paged_content"},f=function(a,b){for(var c={itemsperpage:b,previous:{},next:{},pages:[]},d=1;d<=a;d++){var e={number:d,page:""+d};1===d&&(e.active=!0),c.pages.push(e)}return c},g=function(a,b,c){var d={options:[]},e=0,f=0,g=a;c.hasOwnProperty("maxPages")&&(g=c.maxPages);for(var h=1;h<=g;h++){var i=0;h<=2?(i=b,f=b):(f=2*f,i=f),e+=i;var j={itemcount:i,content:e};1===h&&(j.active=!0),d.options.push(j)}return d},h=function(a,b,c){var d={pagingbar:!1,pagingdropdown:!1,skipjs:!0};return c.hasOwnProperty("dropdown")&&c.dropdown?d.pagingdropdown=g(a,b,c):d.pagingbar=f(a,b),d},i=function(a,b){var c=1;if(a>0){var d=a%b;d?(a-=d,c=a/b+1):c=a/b}return c},j=function(f,g,j,k){"undefined"==typeof k&&(k={});var l=a.Deferred(),m=i(f,g),n=h(m,g,k);return b.render(e.PAGED_CONTENT,n).then(function(b,c){b=a(b);var e=b,f=b.find(d.rootSelector);d.init(f,e,j),l.resolve(b,c)}).fail(function(a){l.reject(a)}).fail(c.exception),l},k=function(a,b,c,d){"undefined"==typeof d&&(d={});var e=a.length;return j(e,b,function(b){var d=[];return b.forEach(function(b){var c=b.offset,f=b.limit?c+b.limit:e,g=a.slice(c,f);d.push(g)}),c(d)},d)};return{createFromAjax:j,createFromStaticList:k}});
|
||||
+1
@@ -0,0 +1 @@
|
||||
define(["jquery","core/templates","core/notification","core/paged_content_events"],function(a,b,c,d){var e={ROOT:'[data-region="page-container"]',PAGE_REGION:'[data-region="paged-content-page"]',ACTIVE_PAGE_REGION:'[data-region="paged-content-page"].active'},f={PAGING_CONTENT_ITEM:"core/paged_content_page",LOADING:"core/overlay_loading"},g=function(a,b){return a.find('[data-page="'+b+'"]')},h=function(d){var e=a.Deferred();return b.render(f.LOADING,{visible:!0}).then(function(b){var c=a(b),f=setTimeout(function(){d.css("position","relative"),c.appendTo(d)},100);e.always(function(){clearTimeout(f),c.remove(),d.css("position","")})}).fail(c.exception),e},i=function(d,e,h){var i=a.Deferred();return e.then(function(a,e){b.render(f.PAGING_CONTENT_ITEM,{page:h,content:a}).then(function(a){b.appendNodeContents(d,a,e);var c=g(d,h);i.resolve(c)}).fail(function(a){i.reject(a)}).fail(c.exception)}).fail(function(a){i.reject(a)}).fail(c.exception),i},j=function(b,d,f){var j=[],k=[],l=a.Deferred();if(d.forEach(function(a){var c=a.pageNumber,d=g(b,c);d.length?j.push(d):k.push(a)}),k.length&&"function"==typeof f){var m=f(k),n=m.map(function(a,c){return i(b,a,k[c].pageNumber)});a.when.apply(a,n).then(function(){var a=Array.prototype.slice.call(arguments);l.resolve(a)}).fail(function(a){l.reject(a)}).fail(c.exception)}else l.resolve([]);var o=h(b);l.then(function(a){var c=j.concat(a);b.find(e.PAGE_REGION).addClass("hidden"),c.forEach(function(a){a.removeClass("hidden")})}).fail(c.exception).always(function(){o.resolve()})},k=function(b,c,e){b=a(b),c=a(c),c.on(d.SHOW_PAGES,function(a,c){j(b,c,e)})};return{init:k,rootSelector:e.ROOT}});
|
||||
@@ -0,0 +1 @@
|
||||
define(["jquery","core/custom_interaction_events","core/paged_content_events"],function(a,b,c){var d={ROOT:'[data-region="paging-bar"]',PAGE:"[data-page]",PAGE_ITEM:'[data-region="page-item"]',ACTIVE_PAGE_ITEM:'[data-region="page-item"].active'},e=function(a,b){return a.find(d.PAGE_ITEM+'[data-page-number="'+b+'"]')},f=function(a){var b=a.find(d.PAGE).last();return b?parseInt(b.attr("data-page-number"),10):null},g=function(a){var b=a.find(d.ACTIVE_PAGE_ITEM);return b.length?h(a,b):null},h=function(a,b){if(void 0!=b.attr("data-page"))return parseInt(b.attr("data-page-number"),10);var c=1,d=null;switch(b.attr("data-control")){case"first":c=1;break;case"last":c=f(a);break;case"next":d=g(a);var e=f(a);c=d&&d<e?d+1:e;break;case"previous":d=g(a),c=d&&d>1?d-1:1;break;default:c=1}return parseInt(c,10)},i=function(a){return parseInt(a.attr("data-items-per-page"),10)},j=function(b){b.each(function(b,c){c=a(c),c.attr("data-page-number",b+1)})},k=function(a,b){var f=b==g(a),h=i(a),j=(b-1)*h;if(!f){a.find(d.PAGE_ITEM).removeClass("active");var k=e(a,b);k.addClass("active")}a.trigger(c.SHOW_PAGES,[[{pageNumber:b,limit:h,offset:j}]])},l=function(c){c=a(c);var e=c.find(d.PAGE);j(e);var f=g(c);f&&k(c,f),b.define(c,[b.events.activate]),c.on(b.events.activate,d.PAGE_ITEM,function(b,e){var f=a(b.target).closest(d.PAGE_ITEM),g=h(c,f);k(c,g),e.originalEvent.preventDefault(),e.originalEvent.stopPropagation()})};return{init:l,rootSelector:d.ROOT}});
|
||||
@@ -0,0 +1 @@
|
||||
define(["jquery","core/custom_interaction_events","core/paged_content_events"],function(a,b,c){var d={ROOT:'[data-region="paging-dropdown-container"]',DROPDOWN_ITEM:'[data-region="dropdown-item"]',DROPDOWN_TOGGLE:'[data-region="dropdown-toggle"]',ACTIVE_DROPDOWN_ITEM:'[data-region="dropdown-item"].active',CARET:'[data-region="caret"]'},e=function(a){return parseInt(a.attr("data-page-number"),10)},f=function(a){return a.find(d.DROPDOWN_ITEM)},g=function(b,c){var d=e(c);return f(b).filter(function(b,c){return e(a(c))<d})},h=function(a){return parseInt(a.attr("data-item-count"),10)},i=function(b,c){if(void 0!=c.attr("data-offset"))return parseInt(c.attr("data-offset"),10);var d=0;return g(b,c).each(function(b,c){c=a(c),d+=h(c)}),c.attr("data-offset",d),d},j=function(a){return a.find(d.ACTIVE_DROPDOWN_ITEM)},k=function(b,c){return c.map(function(c,d){return d=a(d),{pageNumber:e(d),limit:h(d),offset:i(b,d)}}).get()},l=function(b){b.each(function(b,c){c=a(c),c.attr("data-page-number",b+1)})},m=function(a,b){var e=g(a,b),f=e.add(b),h=k(a,f),i=a.find(d.DROPDOWN_TOGGLE),l=i.find(d.CARET);j(a).removeClass("active"),b.addClass("active"),i.html(b.text()),i.append(l),a.trigger(c.SHOW_PAGES,[h])},n=function(c){c=a(c);var e=f(c);l(e);var g=j(c);g.length&&m(c,g),b.define(c,[b.events.activate]),c.on(b.events.activate,d.DROPDOWN_ITEM,function(b,e){var f=a(b.target).closest(d.DROPDOWN_ITEM);m(c,f),e.originalEvent.preventDefault()})};return{init:n,rootSelector:d.ROOT}});
|
||||
@@ -44,6 +44,10 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
ctrlPageDown: 'cie:ctrlPageDown',
|
||||
enter: 'cie:enter',
|
||||
};
|
||||
// Static cache of jQuery events that have been handled. This should
|
||||
// only be populated by JavaScript generated events (which will keep it
|
||||
// fairly small).
|
||||
var triggeredEvents = {};
|
||||
|
||||
/**
|
||||
* Check if the caller has asked for the given event type to be
|
||||
@@ -77,6 +81,48 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger the custom event for the given jQuery event.
|
||||
*
|
||||
* This function will only fire the custom event if one hasn't already been
|
||||
* fired for the jQuery event.
|
||||
*
|
||||
* This is to prevent multiple custom event handlers triggering multiple
|
||||
* custom events for a single jQuery event as it bubbles up the stack.
|
||||
*
|
||||
* @param {string} eventName The name of the custom event
|
||||
* @param {event} e The jQuery event
|
||||
* @return {void}
|
||||
*/
|
||||
var triggerEvent = function(eventName, e) {
|
||||
var eventTypeKey = "";
|
||||
|
||||
if (!e.hasOwnProperty('originalEvent')) {
|
||||
// This is a jQuery event generated from JavaScript not a browser event so
|
||||
// we need to build the cache key for the event.
|
||||
eventTypeKey = "" + eventName + e.type + e.timeStamp;
|
||||
|
||||
if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {
|
||||
// If we haven't seen this jQuery event before then fire a custom
|
||||
// event for it and remember the event for later.
|
||||
triggeredEvents[eventTypeKey] = true;
|
||||
$(e.target).trigger(eventName, [{originalEvent: e}]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
eventTypeKey = "triggeredCustom_" + eventName;
|
||||
if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {
|
||||
// If this is a jQuery event generated by the browser then set a
|
||||
// property on the original event to track that we've seen it before.
|
||||
// The property is set on the original event because it's the only part
|
||||
// of the jQuery event that is maintained through multiple event handlers.
|
||||
e.originalEvent[eventTypeKey] = true;
|
||||
$(e.target).trigger(eventName, [{originalEvent: e}]);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a keyboard event that ignores modifier keys.
|
||||
*
|
||||
@@ -90,7 +136,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
element.off('keydown.' + event).on('keydown.' + event, function(e) {
|
||||
if (!isModifierPressed(e)) {
|
||||
if (e.keyCode == keyCode) {
|
||||
$(e.target).trigger(event, [{originalEvent: e}]);
|
||||
triggerEvent(event, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -106,12 +152,12 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
*/
|
||||
var addActivateListener = function(element) {
|
||||
element.off('click.cie.activate').on('click.cie.activate', function(e) {
|
||||
$(e.target).trigger(events.activate, [{originalEvent: e}]);
|
||||
triggerEvent(events.activate, e);
|
||||
});
|
||||
element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {
|
||||
if (!isModifierPressed(e)) {
|
||||
if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {
|
||||
$(e.target).trigger(events.activate, [{originalEvent: e}]);
|
||||
triggerEvent(events.activate, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -129,7 +175,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {
|
||||
if (!isModifierPressed(e)) {
|
||||
if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {
|
||||
$(e.target).trigger(events.keyboardActivate, [{originalEvent: e}]);
|
||||
triggerEvent(events.keyboardActivate, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -250,7 +296,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {
|
||||
var scrollTop = element.scrollTop();
|
||||
if (scrollTop === 0) {
|
||||
element.trigger(events.scrollTop, [{originalEvent: e}]);
|
||||
triggerEvent(events.scrollTop, e);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -270,7 +316,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
var scrollHeight = element[0].scrollHeight;
|
||||
|
||||
if (scrollTop + innerHeight >= scrollHeight) {
|
||||
element.trigger(events.scrollBottom, [{originalEvent: e}]);
|
||||
triggerEvent(events.scrollBottom, e);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -302,7 +348,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
e.preventDefault();
|
||||
e.returnValue = false;
|
||||
// Fire the scroll lock event.
|
||||
element.trigger(events.scrollLock, [{originalEvent: e}]);
|
||||
triggerEvent(events.scrollLock, e);
|
||||
|
||||
return false;
|
||||
} else if (up && delta > scrollTop) {
|
||||
@@ -312,7 +358,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
e.preventDefault();
|
||||
e.returnValue = false;
|
||||
// Fire the scroll lock event.
|
||||
element.trigger(events.scrollLock, [{originalEvent: e}]);
|
||||
triggerEvent(events.scrollLock, e);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -333,7 +379,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {
|
||||
if (e.ctrlKey) {
|
||||
if (e.keyCode == keyCodes.pageUp) {
|
||||
$(e.target).trigger(events.ctrlPageUp, [{originalEvent: e}]);
|
||||
triggerEvent(events.ctrlPageUp, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -351,7 +397,7 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
|
||||
element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {
|
||||
if (e.ctrlKey) {
|
||||
if (e.keyCode == keyCodes.pageDown) {
|
||||
$(e.target).trigger(events.ctrlPageDown, [{originalEvent: e}]);
|
||||
triggerEvent(events.ctrlPageDown, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -60,49 +60,55 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
|
||||
* @method setUpTrigger
|
||||
* @param {Promise} modalPromise The modal instance
|
||||
* @param {object} triggerElement The jQuery element to open the modal
|
||||
* @param {object} modalConfig The modal configuration given to the factory
|
||||
*/
|
||||
var setUpTrigger = function(modalPromise, triggerElement) {
|
||||
if (typeof triggerElement != 'undefined') {
|
||||
// The element that actually shows the modal.
|
||||
var actualTriggerElement = null;
|
||||
if (Array.isArray(triggerElement)) {
|
||||
var selector = triggerElement[1];
|
||||
triggerElement = triggerElement[0];
|
||||
|
||||
CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
|
||||
triggerElement.on(CustomEvents.events.activate, selector, function(e, data) {
|
||||
actualTriggerElement = e.currentTarget;
|
||||
modalPromise.then(function(modal) {
|
||||
modal.show();
|
||||
|
||||
return modal;
|
||||
});
|
||||
data.originalEvent.preventDefault();
|
||||
});
|
||||
} else {
|
||||
CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
|
||||
triggerElement.on(CustomEvents.events.activate, function(e, data) {
|
||||
actualTriggerElement = e.currentTarget;
|
||||
modalPromise.then(function(modal) {
|
||||
modal.show();
|
||||
|
||||
return modal;
|
||||
});
|
||||
data.originalEvent.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
var setUpTrigger = function(modalPromise, triggerElement, modalConfig) {
|
||||
// The element that actually shows the modal.
|
||||
var actualTriggerElement = null;
|
||||
// Check if the client has provided a callback function to be called
|
||||
// before the modal is displayed.
|
||||
var hasPreShowCallback = (typeof modalConfig.preShowCallback == 'function');
|
||||
// Function to handle the trigger element being activated.
|
||||
var triggeredCallback = function(e, data) {
|
||||
actualTriggerElement = $(e.currentTarget);
|
||||
modalPromise.then(function(modal) {
|
||||
modal.getRoot().on(ModalEvents.hidden, function() {
|
||||
// Focus on the trigger element that actually launched the modal.
|
||||
if (actualTriggerElement !== null) {
|
||||
actualTriggerElement.focus();
|
||||
}
|
||||
});
|
||||
if (hasPreShowCallback) {
|
||||
// If the client provided a pre-show callback then execute
|
||||
// it now before showing the modal.
|
||||
modalConfig.preShowCallback(actualTriggerElement, modal);
|
||||
}
|
||||
|
||||
modal.show();
|
||||
|
||||
return modal;
|
||||
});
|
||||
data.originalEvent.preventDefault();
|
||||
};
|
||||
|
||||
// The trigger element can either be a single element or it can be an
|
||||
// element + selector pair to create a delegated event handler to trigger
|
||||
// the modal.
|
||||
if (Array.isArray(triggerElement)) {
|
||||
var selector = triggerElement[1];
|
||||
triggerElement = triggerElement[0];
|
||||
|
||||
CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
|
||||
triggerElement.on(CustomEvents.events.activate, selector, triggeredCallback);
|
||||
} else {
|
||||
CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
|
||||
triggerElement.on(CustomEvents.events.activate, triggeredCallback);
|
||||
}
|
||||
|
||||
modalPromise.then(function(modal) {
|
||||
modal.getRoot().on(ModalEvents.hidden, function() {
|
||||
// Focus on the trigger element that actually launched the modal.
|
||||
if (actualTriggerElement !== null) {
|
||||
actualTriggerElement.focus();
|
||||
}
|
||||
});
|
||||
|
||||
return modal;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -112,7 +118,6 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
|
||||
* @method createFromElement
|
||||
* @param {object} registryConf A config from the ModalRegistry
|
||||
* @param {object} modalElement The modal HTML jQuery object
|
||||
* @param {object} triggerElement The trigger HTML jQuery object
|
||||
* @return {object} Modal instance
|
||||
*/
|
||||
var createFromElement = function(registryConf, modalElement) {
|
||||
@@ -125,15 +130,14 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
|
||||
|
||||
/**
|
||||
* Create the correct modal instance for the given type, including loading
|
||||
* the correct template and setting up the trigger relationship with the
|
||||
* trigger element.
|
||||
* the correct template.
|
||||
*
|
||||
* @method createFromType
|
||||
* @param {object} registryConf A config from the ModalRegistry
|
||||
* @param {object} triggerElement The trigger HTML jQuery object
|
||||
* @param {object} templateContext The context to render the template with
|
||||
* @return {promise} Resolved with a Modal instance
|
||||
*/
|
||||
var createFromType = function(registryConf, templateContext, triggerElement) {
|
||||
var createFromType = function(registryConf, templateContext) {
|
||||
var templateName = registryConf.template;
|
||||
|
||||
var modalPromise = Templates.render(templateName, templateContext)
|
||||
@@ -143,8 +147,6 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
|
||||
setUpTrigger(modalPromise, triggerElement);
|
||||
|
||||
return modalPromise;
|
||||
};
|
||||
|
||||
@@ -172,7 +174,7 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
|
||||
templateContext = modalConfig.templateContext;
|
||||
}
|
||||
|
||||
return createFromType(registryConf, templateContext, triggerElement)
|
||||
var modalPromise = createFromType(registryConf, templateContext)
|
||||
.then(function(modal) {
|
||||
if (typeof modalConfig.title != 'undefined') {
|
||||
modal.setTitle(modalConfig.title);
|
||||
@@ -192,6 +194,12 @@ define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
|
||||
|
||||
return modal;
|
||||
});
|
||||
|
||||
if (typeof triggerElement != 'undefined') {
|
||||
setUpTrigger(modalPromise, triggerElement, modalConfig);
|
||||
}
|
||||
|
||||
return modalPromise;
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Javascript to load and render the paging bar.
|
||||
*
|
||||
* @module core/paging_bar
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([], function() {
|
||||
return {
|
||||
SHOW_PAGES: 'core-paged-content-show-pages',
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,280 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Factory to create a paged content widget.
|
||||
*
|
||||
* @module core/paged_content_factory
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'jquery',
|
||||
'core/templates',
|
||||
'core/notification',
|
||||
'core/paged_content_pages'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
Templates,
|
||||
Notification,
|
||||
PagedContent
|
||||
) {
|
||||
var TEMPLATES = {
|
||||
PAGED_CONTENT: 'core/paged_content'
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the context to render the paging bar template with based on the number
|
||||
* of pages to show.
|
||||
*
|
||||
* @param {int} numberOfPages How many pages to have in the paging bar.
|
||||
* @param {int} itemsPerPage How many items will be shown per page.
|
||||
* @return {object} The template context.
|
||||
*/
|
||||
var buildPagingBarTemplateContext = function(numberOfPages, itemsPerPage) {
|
||||
var context = {
|
||||
"itemsperpage": itemsPerPage,
|
||||
"previous": {},
|
||||
"next": {},
|
||||
"pages": []
|
||||
};
|
||||
|
||||
for (var i = 1; i <= numberOfPages; i++) {
|
||||
var page = {
|
||||
number: i,
|
||||
page: "" + i,
|
||||
};
|
||||
|
||||
// Make the first page active by default.
|
||||
if (i === 1) {
|
||||
page.active = true;
|
||||
}
|
||||
|
||||
context.pages.push(page);
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the context to render the paging dropdown template with based on the number
|
||||
* of pages to show and items per page.
|
||||
*
|
||||
* This control is rendered with a gradual increase of the items per page to
|
||||
* limit the number of pages in the dropdown. Each page will show twice as much
|
||||
* as the previous page (except for the first two pages).
|
||||
*
|
||||
* For example:
|
||||
* Number of pages = 3
|
||||
* Items per page = 25
|
||||
* Would render a dropdown will 4 options:
|
||||
* 25
|
||||
* 50
|
||||
* 100
|
||||
* All
|
||||
*
|
||||
* @param {int} numberOfPages How many options to have in the dropdown.
|
||||
* @param {int} itemsPerPage How many items will be shown per page.
|
||||
* @param {object} config Configuration options provided by the client.
|
||||
* @return {object} The template context.
|
||||
*/
|
||||
var buildPagingDropdownTemplateContext = function(numberOfPages, itemsPerPage, config) {
|
||||
var context = {
|
||||
options: []
|
||||
};
|
||||
|
||||
var totalItems = 0;
|
||||
var lastIncrease = 0;
|
||||
var maxPages = numberOfPages;
|
||||
|
||||
if (config.hasOwnProperty('maxPages')) {
|
||||
maxPages = config.maxPages;
|
||||
}
|
||||
|
||||
for (var i = 1; i <= maxPages; i++) {
|
||||
var itemCount = 0;
|
||||
|
||||
if (i <= 2) {
|
||||
itemCount = itemsPerPage;
|
||||
lastIncrease = itemsPerPage;
|
||||
} else {
|
||||
lastIncrease = lastIncrease * 2;
|
||||
itemCount = lastIncrease;
|
||||
}
|
||||
|
||||
totalItems += itemCount;
|
||||
var option = {
|
||||
itemcount: itemCount,
|
||||
content: totalItems
|
||||
};
|
||||
|
||||
// Make the first option active by default.
|
||||
if (i === 1) {
|
||||
option.active = true;
|
||||
}
|
||||
|
||||
context.options.push(option);
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the context to render the paged content template with based on the number
|
||||
* of pages to show, items per page, and configuration option.
|
||||
*
|
||||
* By default the code will render a paging bar for the paging controls unless
|
||||
* otherwise specified in the provided config.
|
||||
*
|
||||
* @param {int} numberOfPages How many pages to have.
|
||||
* @param {int} itemsPerPage How many items will be shown per page.
|
||||
* @param {object} config Configuration options provided by the client.
|
||||
* @return {object} The template context.
|
||||
*/
|
||||
var buildTemplateContext = function(numberOfPages, itemsPerPage, config) {
|
||||
var context = {
|
||||
pagingbar: false,
|
||||
pagingdropdown: false,
|
||||
skipjs: true
|
||||
};
|
||||
|
||||
if (config.hasOwnProperty('dropdown') && config.dropdown) {
|
||||
context.pagingdropdown = buildPagingDropdownTemplateContext(numberOfPages, itemsPerPage, config);
|
||||
} else {
|
||||
context.pagingbar = buildPagingBarTemplateContext(numberOfPages, itemsPerPage);
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the number of pages required for the given number of items and
|
||||
* how many of each item should appear on a page.
|
||||
*
|
||||
* @param {int} numberOfItems How many items in total.
|
||||
* @param {int} itemsPerPage How many items will be shown per page.
|
||||
* @return {int} The number of pages required.
|
||||
*/
|
||||
var calculateNumberOfPages = function(numberOfItems, itemsPerPage) {
|
||||
var numberOfPages = 1;
|
||||
|
||||
if (numberOfItems > 0) {
|
||||
var partial = numberOfItems % itemsPerPage;
|
||||
|
||||
if (partial) {
|
||||
numberOfItems -= partial;
|
||||
numberOfPages = (numberOfItems / itemsPerPage) + 1;
|
||||
} else {
|
||||
numberOfPages = numberOfItems / itemsPerPage;
|
||||
}
|
||||
}
|
||||
|
||||
return numberOfPages;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a paged content widget where the complete list of items is not loaded
|
||||
* up front but will instead be loaded by an ajax request (or similar).
|
||||
*
|
||||
* The client code must provide a callback function which loads and renders the
|
||||
* items for each page. See PagedContent.init for more details.
|
||||
*
|
||||
* The function will return a deferred that is resolved with a jQuery object
|
||||
* for the HTML content and a string for the JavaScript.
|
||||
*
|
||||
* The current list of configuration options available are:
|
||||
* dropdown {bool} True to render the page control as a dropdown (paging bar is default).
|
||||
*
|
||||
* @param {int} numberOfItems How many items are there in total.
|
||||
* @param {int} itemsPerPage How many items will be shown per page.
|
||||
* @param {function} renderPagesContentCallback Callback for loading and rendering the items.
|
||||
* @param {object} config Configuration options provided by the client.
|
||||
* @return {promise} Resolved with jQuery HTML and string JS.
|
||||
*/
|
||||
var createFromAjax = function(numberOfItems, itemsPerPage, renderPagesContentCallback, config) {
|
||||
if (typeof config == 'undefined') {
|
||||
config = {};
|
||||
}
|
||||
|
||||
var deferred = $.Deferred();
|
||||
var numberOfPages = calculateNumberOfPages(numberOfItems, itemsPerPage);
|
||||
var templateContext = buildTemplateContext(numberOfPages, itemsPerPage, config);
|
||||
|
||||
Templates.render(TEMPLATES.PAGED_CONTENT, templateContext)
|
||||
.then(function(html, js) {
|
||||
html = $(html);
|
||||
|
||||
var container = html;
|
||||
var pagedContent = html.find(PagedContent.rootSelector);
|
||||
|
||||
PagedContent.init(pagedContent, container, renderPagesContentCallback);
|
||||
|
||||
deferred.resolve(html, js);
|
||||
return;
|
||||
})
|
||||
.fail(function(exception) {
|
||||
deferred.reject(exception);
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a paged content widget where the complete list of items is loaded
|
||||
* up front.
|
||||
*
|
||||
* The client code must provide a callback function which renders the
|
||||
* items for each page. The callback will be provided with an array where each
|
||||
* value in the array is a the list of items to render for the page.
|
||||
*
|
||||
* The function will return a deferred that is resolved with a jQuery object
|
||||
* for the HTML content and a string for the JavaScript.
|
||||
*
|
||||
* The current list of configuration options available are:
|
||||
* dropdown {bool} True to render the page control as a dropdown (paging bar is default).
|
||||
*
|
||||
* @param {array} contentItems The list of items to paginate.
|
||||
* @param {int} itemsPerPage How many items will be shown per page.
|
||||
* @param {function} renderContentCallback Callback for rendering the items for the page.
|
||||
* @param {object} config Configuration options provided by the client.
|
||||
* @return {promise} Resolved with jQuery HTML and string JS.
|
||||
*/
|
||||
var createFromStaticList = function(contentItems, itemsPerPage, renderContentCallback, config) {
|
||||
if (typeof config == 'undefined') {
|
||||
config = {};
|
||||
}
|
||||
|
||||
var numberOfItems = contentItems.length;
|
||||
return createFromAjax(numberOfItems, itemsPerPage, function(pagesData) {
|
||||
var contentToRender = [];
|
||||
pagesData.forEach(function(pageData) {
|
||||
var begin = pageData.offset;
|
||||
var end = pageData.limit ? begin + pageData.limit : numberOfItems;
|
||||
var items = contentItems.slice(begin, end);
|
||||
contentToRender.push(items);
|
||||
});
|
||||
|
||||
return renderContentCallback(contentToRender);
|
||||
}, config);
|
||||
};
|
||||
|
||||
return {
|
||||
createFromAjax: createFromAjax,
|
||||
createFromStaticList: createFromStaticList
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,283 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Javascript for showing/hiding pages of content.
|
||||
*
|
||||
* @module core/paged_content_pages
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'jquery',
|
||||
'core/templates',
|
||||
'core/notification',
|
||||
'core/paged_content_events'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
Templates,
|
||||
Notification,
|
||||
PagedContentEvents
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
ROOT: '[data-region="page-container"]',
|
||||
PAGE_REGION: '[data-region="paged-content-page"]',
|
||||
ACTIVE_PAGE_REGION: '[data-region="paged-content-page"].active'
|
||||
};
|
||||
|
||||
var TEMPLATES = {
|
||||
PAGING_CONTENT_ITEM: 'core/paged_content_page',
|
||||
LOADING: 'core/overlay_loading'
|
||||
};
|
||||
|
||||
/**
|
||||
* Find a page by the number.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {Number} pageNumber The number of the page to be found.
|
||||
* @returns {jQuery} The page.
|
||||
*/
|
||||
var findPage = function(root, pageNumber) {
|
||||
return root.find('[data-page="' + pageNumber + '"]');
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the loading spinner until the returned deferred is resolved by the
|
||||
* calling code.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @returns {promise} The page.
|
||||
*/
|
||||
var startLoading = function(root) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
Templates.render(TEMPLATES.LOADING, {visible: true})
|
||||
.then(function(html) {
|
||||
var loadingSpinner = $(html);
|
||||
// Put this in a timer to give the calling code 100 milliseconds
|
||||
// to render the content before we show the loading spinner. This
|
||||
// helps prevent a loading icon flicker on close to instant
|
||||
// rendering.
|
||||
var timerId = setTimeout(function() {
|
||||
root.css('position', 'relative');
|
||||
loadingSpinner.appendTo(root);
|
||||
}, 100);
|
||||
|
||||
deferred.always(function() {
|
||||
clearTimeout(timerId);
|
||||
// Remove the loading spinner when our deferred is resolved
|
||||
// by the calling code.
|
||||
loadingSpinner.remove();
|
||||
root.css('position', '');
|
||||
return;
|
||||
});
|
||||
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render the result of the page promise in a paged content page.
|
||||
*
|
||||
* This function returns a promise that is resolved with the new paged content
|
||||
* page.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {promise} pagePromise The promise resolved with HTML and JS to render in the page.
|
||||
* @param {int} pageNumber The page number.
|
||||
* @returns {promise} The page.
|
||||
*/
|
||||
var renderPagePromise = function(root, pagePromise, pageNumber) {
|
||||
var deferred = $.Deferred();
|
||||
pagePromise.then(function(html, pageJS) {
|
||||
// When we get the contents to be rendered we can pass it in as the
|
||||
// content for a new page.
|
||||
Templates.render(TEMPLATES.PAGING_CONTENT_ITEM, {
|
||||
page: pageNumber,
|
||||
content: html
|
||||
})
|
||||
.then(function(html) {
|
||||
// Make sure the JS we got from the page promise is being added
|
||||
// to the page when we render the page.
|
||||
Templates.appendNodeContents(root, html, pageJS);
|
||||
var page = findPage(root, pageNumber);
|
||||
deferred.resolve(page);
|
||||
return;
|
||||
})
|
||||
.fail(function(exception) {
|
||||
deferred.reject(exception);
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
|
||||
return;
|
||||
})
|
||||
.fail(function(exception) {
|
||||
deferred.reject(exception);
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make one or more pages visible based on the SHOW_PAGES event. The show
|
||||
* pages event provides data containing which pages should be shown as well
|
||||
* as the limit and offset values for loading the items for each of those pages.
|
||||
*
|
||||
* The renderPagesContentCallback is provided this list of data to know which
|
||||
* pages to load. E.g. the data to load 2 pages might look like:
|
||||
* [
|
||||
* {
|
||||
* pageNumber: 1,
|
||||
* limit: 5,
|
||||
* offset: 0
|
||||
* },
|
||||
* {
|
||||
* pageNumber: 2,
|
||||
* limit: 5,
|
||||
* offset: 5
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* The renderPagesContentCallback should return an array of promises, one for
|
||||
* each page in the pages data, that is resolved with the HTML and JS for that page.
|
||||
*
|
||||
* If the renderPagesContentCallback is not provided then it is assumed that
|
||||
* all pages have been rendered prior to initialising this module.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {Number} pagesData The data for which pages need to be visible.
|
||||
* @param {function} renderPagesContentCallback Render pages content.
|
||||
*/
|
||||
var showPages = function(root, pagesData, renderPagesContentCallback) {
|
||||
var existingPages = [];
|
||||
var newPageData = [];
|
||||
var newPagesPromise = $.Deferred();
|
||||
|
||||
// Check which of the pages being requests have previously been rendered
|
||||
// so that we only ask for new pages to be rendered by the callback.
|
||||
pagesData.forEach(function(pageData) {
|
||||
var pageNumber = pageData.pageNumber;
|
||||
var existingPage = findPage(root, pageNumber);
|
||||
if (existingPage.length) {
|
||||
existingPages.push(existingPage);
|
||||
} else {
|
||||
newPageData.push(pageData);
|
||||
}
|
||||
});
|
||||
|
||||
if (newPageData.length && typeof renderPagesContentCallback === 'function') {
|
||||
// If we have pages we haven't previously seen then ask the client code
|
||||
// to render them for us by calling the callback.
|
||||
var promises = renderPagesContentCallback(newPageData);
|
||||
// After the client has finished rendering each of the pages being asked
|
||||
// for then begin our rendering process to put that content into paged
|
||||
// content pages.
|
||||
var renderPagePromises = promises.map(function(promise, index) {
|
||||
// Create our promise for when our rendering will be completed.
|
||||
return renderPagePromise(root, promise, newPageData[index].pageNumber);
|
||||
});
|
||||
// After each of our rendering promises have been completed then we can
|
||||
// give all of the new pages to the next bit of code for handling.
|
||||
$.when.apply($, renderPagePromises)
|
||||
.then(function() {
|
||||
var newPages = Array.prototype.slice.call(arguments);
|
||||
// Resolve the promise with the list of newly rendered pages.
|
||||
newPagesPromise.resolve(newPages);
|
||||
return;
|
||||
})
|
||||
.fail(function(exception) {
|
||||
newPagesPromise.reject(exception);
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
} else {
|
||||
// If there aren't any pages to load then immediately resolve the promise.
|
||||
newPagesPromise.resolve([]);
|
||||
}
|
||||
|
||||
var loadingPromise = startLoading(root);
|
||||
newPagesPromise.then(function(newPages) {
|
||||
// Once all of the new pages have been created then add them to any
|
||||
// existing pages we have.
|
||||
var pagesToShow = existingPages.concat(newPages);
|
||||
// Hide all existing pages.
|
||||
root.find(SELECTORS.PAGE_REGION).addClass('hidden');
|
||||
// Show each of the pages that were requested.
|
||||
pagesToShow.forEach(function(page) {
|
||||
page.removeClass('hidden');
|
||||
});
|
||||
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception)
|
||||
.always(function() {
|
||||
loadingPromise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the module to listen for SHOW_PAGES events and render the
|
||||
* appropriate pages using the provided renderPagesContentCallback function.
|
||||
*
|
||||
* The renderPagesContentCallback is provided a list of data to know which
|
||||
* pages to load.
|
||||
* E.g. the data to load 2 pages might look like:
|
||||
* [
|
||||
* {
|
||||
* pageNumber: 1,
|
||||
* limit: 5,
|
||||
* offset: 0
|
||||
* },
|
||||
* {
|
||||
* pageNumber: 2,
|
||||
* limit: 5,
|
||||
* offset: 5
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* The renderPagesContentCallback should return an array of promises, one for
|
||||
* each page in the pages data, that is resolved with the HTML and JS for that page.
|
||||
*
|
||||
* If the renderPagesContentCallback is not provided then it is assumed that
|
||||
* all pages have been rendered prior to initialising this module.
|
||||
*
|
||||
* The event element is the element to listen for the paged content events on.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {object} eventElement The element to listen for events on.
|
||||
* @param {function} renderPagesContentCallback Render pages content.
|
||||
*/
|
||||
var init = function(root, eventElement, renderPagesContentCallback) {
|
||||
root = $(root);
|
||||
eventElement = $(eventElement);
|
||||
|
||||
eventElement.on(PagedContentEvents.SHOW_PAGES, function(e, pagesData) {
|
||||
showPages(root, pagesData, renderPagesContentCallback);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
rootSelector: SELECTORS.ROOT,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,228 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Javascript to enhance the paged content paging bar.
|
||||
*
|
||||
* @module core/paging_bar
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'jquery',
|
||||
'core/custom_interaction_events',
|
||||
'core/paged_content_events'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
CustomEvents,
|
||||
PagedContentEvents
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
ROOT: '[data-region="paging-bar"]',
|
||||
PAGE: '[data-page]',
|
||||
PAGE_ITEM: '[data-region="page-item"]',
|
||||
ACTIVE_PAGE_ITEM: '[data-region="page-item"].active'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the page element by number.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {Number} pageNumber The page number.
|
||||
* @return {jQuery}
|
||||
*/
|
||||
var getPageByNumber = function(root, pageNumber) {
|
||||
return root.find(SELECTORS.PAGE_ITEM + '[data-page-number="' + pageNumber + '"]');
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the last page number.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @return {int}
|
||||
*/
|
||||
var getLastPageNumber = function(root) {
|
||||
var lastPage = root.find(SELECTORS.PAGE).last();
|
||||
if (lastPage) {
|
||||
return parseInt(lastPage.attr('data-page-number'), 10);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the active page number.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @returns {int} The page number
|
||||
*/
|
||||
var getActivePageNumber = function(root) {
|
||||
var activePage = root.find(SELECTORS.ACTIVE_PAGE_ITEM);
|
||||
|
||||
if (activePage.length) {
|
||||
return getPageNumber(root, activePage);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the page number.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {object} page The page.
|
||||
* @returns {int} The page number
|
||||
*/
|
||||
var getPageNumber = function(root, page) {
|
||||
if (page.attr('data-page') != undefined) {
|
||||
// If it's an actual page then we can just use the page number
|
||||
// attribute.
|
||||
return parseInt(page.attr('data-page-number'), 10);
|
||||
}
|
||||
|
||||
var pageNumber = 1;
|
||||
var activePageNumber = null;
|
||||
|
||||
switch (page.attr('data-control')) {
|
||||
case 'first':
|
||||
pageNumber = 1;
|
||||
break;
|
||||
|
||||
case 'last':
|
||||
pageNumber = getLastPageNumber(root);
|
||||
break;
|
||||
|
||||
case 'next':
|
||||
activePageNumber = getActivePageNumber(root);
|
||||
var lastPage = getLastPageNumber(root);
|
||||
if (activePageNumber && activePageNumber < lastPage) {
|
||||
pageNumber = activePageNumber + 1;
|
||||
} else {
|
||||
pageNumber = lastPage;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'previous':
|
||||
activePageNumber = getActivePageNumber(root);
|
||||
if (activePageNumber && activePageNumber > 1) {
|
||||
pageNumber = activePageNumber - 1;
|
||||
} else {
|
||||
pageNumber = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pageNumber = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure we return an int not a string.
|
||||
return parseInt(pageNumber, 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the limit of items for each page.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @returns {int}
|
||||
*/
|
||||
var getLimit = function(root) {
|
||||
return parseInt(root.attr('data-items-per-page'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set page numbers on each of the given items. Page numbers are set
|
||||
* from 1..n (where n is the number of items).
|
||||
*
|
||||
* @param {jQuery} items A jQuery list of items.
|
||||
*/
|
||||
var generatePageNumbers = function(items) {
|
||||
items.each(function(index, item) {
|
||||
item = $(item);
|
||||
item.attr('data-page-number', index + 1);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Make the paging bar item for the given page number visible and fire
|
||||
* the SHOW_PAGES paged content event to tell any listening content to
|
||||
* update.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
* @param {int} pageNumber The number for the page to show.
|
||||
* @param {object} page The page.
|
||||
*/
|
||||
var showPage = function(root, pageNumber) {
|
||||
var isSamePage = pageNumber == getActivePageNumber(root);
|
||||
var limit = getLimit(root);
|
||||
var offset = (pageNumber - 1) * limit;
|
||||
|
||||
if (!isSamePage) {
|
||||
// We only need to toggle the active class if the user didn't click
|
||||
// on the already active page.
|
||||
root.find(SELECTORS.PAGE_ITEM).removeClass('active');
|
||||
var page = getPageByNumber(root, pageNumber);
|
||||
page.addClass('active');
|
||||
}
|
||||
|
||||
// This event requires a payload that contains a list of all pages that
|
||||
// were activated. In the case of the paging bar we only show one page at
|
||||
// a time.
|
||||
root.trigger(PagedContentEvents.SHOW_PAGES, [[{
|
||||
pageNumber: pageNumber,
|
||||
limit: limit,
|
||||
offset: offset
|
||||
}]]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the paging bar.
|
||||
* @param {object} root The root element.
|
||||
*/
|
||||
var init = function(root) {
|
||||
root = $(root);
|
||||
var pages = root.find(SELECTORS.PAGE);
|
||||
generatePageNumbers(pages);
|
||||
|
||||
var activePageNumber = getActivePageNumber(root);
|
||||
if (activePageNumber) {
|
||||
// If the the paging bar was rendered with an active page selected
|
||||
// then make sure we fired off the event to tell the content page to
|
||||
// show.
|
||||
showPage(root, activePageNumber);
|
||||
}
|
||||
|
||||
CustomEvents.define(root, [
|
||||
CustomEvents.events.activate
|
||||
]);
|
||||
|
||||
root.on(CustomEvents.events.activate, SELECTORS.PAGE_ITEM, function(e, data) {
|
||||
var page = $(e.target).closest(SELECTORS.PAGE_ITEM);
|
||||
var pageNumber = getPageNumber(root, page);
|
||||
showPage(root, pageNumber);
|
||||
|
||||
data.originalEvent.preventDefault();
|
||||
data.originalEvent.stopPropagation();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
rootSelector: SELECTORS.ROOT,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,237 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Javascript to manage the paging dropdown control.
|
||||
*
|
||||
* @module core/paged_content_paging_dropdown
|
||||
* @copyright 2018 Ryan Wyllie <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'jquery',
|
||||
'core/custom_interaction_events',
|
||||
'core/paged_content_events'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
CustomEvents,
|
||||
PagedContentEvents
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
ROOT: '[data-region="paging-dropdown-container"]',
|
||||
DROPDOWN_ITEM: '[data-region="dropdown-item"]',
|
||||
DROPDOWN_TOGGLE: '[data-region="dropdown-toggle"]',
|
||||
ACTIVE_DROPDOWN_ITEM: '[data-region="dropdown-item"].active',
|
||||
CARET: '[data-region="caret"]'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the page number.
|
||||
*
|
||||
* @param {jquery} item The dropdown item.
|
||||
* @returns {int}
|
||||
*/
|
||||
var getPageNumber = function(item) {
|
||||
return parseInt(item.attr('data-page-number'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all paging dropdown items.
|
||||
*
|
||||
* @param {jquery} root The root element.
|
||||
* @returns {jquery} A jquery object with all items.
|
||||
*/
|
||||
var getAllItems = function(root) {
|
||||
return root.find(SELECTORS.DROPDOWN_ITEM);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all paging dropdown items with lower page numbers than the given
|
||||
* dropdown item.
|
||||
*
|
||||
* @param {jquery} root The root element.
|
||||
* @param {jquery} item The dropdown item.
|
||||
* @returns {jquery} A jquery object with all items.
|
||||
*/
|
||||
var getPreviousItems = function(root, item) {
|
||||
var pageNumber = getPageNumber(item);
|
||||
return getAllItems(root).filter(function(index, element) {
|
||||
return getPageNumber($(element)) < pageNumber;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of items to be loaded for the dropdown item.
|
||||
*
|
||||
* @param {jquery} item The dropdown item.
|
||||
* @returns {int}
|
||||
*/
|
||||
var getLimit = function(item) {
|
||||
return parseInt(item.attr('data-item-count'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the offset of items from the start of the itemset for the given
|
||||
* dropdown item.
|
||||
*
|
||||
* @param {jquery} root The root element.
|
||||
* @param {jquery} item The dropdown item.
|
||||
* @returns {int}
|
||||
*/
|
||||
var getOffset = function(root, item) {
|
||||
if (item.attr('data-offset') != undefined) {
|
||||
return parseInt(item.attr('data-offset'), 10);
|
||||
}
|
||||
|
||||
var offset = 0;
|
||||
|
||||
getPreviousItems(root, item).each(function(index, prevItem) {
|
||||
prevItem = $(prevItem);
|
||||
offset += getLimit(prevItem);
|
||||
});
|
||||
|
||||
item.attr('data-offset', offset);
|
||||
return offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the active dropdown item.
|
||||
*
|
||||
* @param {jquery} root The root element.
|
||||
* @returns {jquery} The active dropdown item.
|
||||
*/
|
||||
var getActiveItem = function(root) {
|
||||
return root.find(SELECTORS.ACTIVE_DROPDOWN_ITEM);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the event payload for the list of dropdown items. The event payload
|
||||
* is an array of objects with one object per dropdown item.
|
||||
*
|
||||
* Each payload object contains the page number, limit, and offset for the
|
||||
* corresponding dropdown item.
|
||||
*
|
||||
* For example: If we had 3 dropdown items with incrementing page numbers loading
|
||||
* 25 items per page then the generated payload would look like:
|
||||
* [
|
||||
* {
|
||||
* pageNumber: 1,
|
||||
* limit: 25,
|
||||
* offset: 0
|
||||
* },
|
||||
* {
|
||||
* pageNumber: 2,
|
||||
* limit: 25,
|
||||
* offset: 25
|
||||
* },
|
||||
* {
|
||||
* pageNumber: 3,
|
||||
* limit: 25,
|
||||
* offset: 50
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* @param {jquery} root The root element.
|
||||
* @param {jquery} items The dropdown items.
|
||||
* @returns {object[]} The payload for the event.
|
||||
*/
|
||||
var generateEventPayload = function(root, items) {
|
||||
return items.map(function(index, item) {
|
||||
item = $(item);
|
||||
return {
|
||||
pageNumber: getPageNumber(item),
|
||||
limit: getLimit(item),
|
||||
offset: getOffset(root, item),
|
||||
};
|
||||
}).get();
|
||||
};
|
||||
|
||||
/**
|
||||
* Add page number attributes to each of the given items. The page numbers
|
||||
* start at 1 and increment by 1 for each item, e.g. 1, 2, 3 etc.
|
||||
*
|
||||
* @param {jquery} items The dropdown items.
|
||||
*/
|
||||
var generatePageNumbers = function(items) {
|
||||
items.each(function(index, item) {
|
||||
item = $(item);
|
||||
item.attr('data-page-number', index + 1);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Make the given item active by setting the active class on it and firing
|
||||
* the SHOW_PAGES event for the paged content to show the appropriate
|
||||
* pages.
|
||||
*
|
||||
* @param {jquery} root The root element.
|
||||
* @param {jquery} item The dropdown item.
|
||||
*/
|
||||
var setActiveItem = function(root, item) {
|
||||
var prevItems = getPreviousItems(root, item);
|
||||
var allItems = prevItems.add(item);
|
||||
var eventPayload = generateEventPayload(root, allItems);
|
||||
var toggle = root.find(SELECTORS.DROPDOWN_TOGGLE);
|
||||
var caret = toggle.find(SELECTORS.CARET);
|
||||
|
||||
getActiveItem(root).removeClass('active');
|
||||
item.addClass('active');
|
||||
|
||||
// Update the dropdown toggle to show which item is selected.
|
||||
toggle.html(item.text());
|
||||
// Bootstrap 2 compatibility.
|
||||
toggle.append(caret);
|
||||
// Fire the event to tell the content to update.
|
||||
root.trigger(PagedContentEvents.SHOW_PAGES, [eventPayload]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the module by firing the SHOW_PAGES event for an existing
|
||||
* active page found and setting up the event listener for the user to select
|
||||
* new pages.
|
||||
*
|
||||
* @param {object} root The root element.
|
||||
*/
|
||||
var init = function(root) {
|
||||
root = $(root);
|
||||
var items = getAllItems(root);
|
||||
generatePageNumbers(items);
|
||||
|
||||
var activeItem = getActiveItem(root);
|
||||
if (activeItem.length) {
|
||||
// Fire the first event for the content to make sure it's visible.
|
||||
setActiveItem(root, activeItem);
|
||||
}
|
||||
|
||||
CustomEvents.define(root, [
|
||||
CustomEvents.events.activate
|
||||
]);
|
||||
|
||||
root.on(CustomEvents.events.activate, SELECTORS.DROPDOWN_ITEM, function(e, data) {
|
||||
var item = $(e.target).closest(SELECTORS.DROPDOWN_ITEM);
|
||||
setActiveItem(root, item);
|
||||
|
||||
data.originalEvent.preventDefault();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
rootSelector: SELECTORS.ROOT,
|
||||
};
|
||||
});
|
||||
@@ -1146,6 +1146,13 @@ $functions = array(
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_question_get_random_question_summaries' => array(
|
||||
'classname' => 'core_question_external',
|
||||
'methodname' => 'get_random_question_summaries',
|
||||
'description' => 'Get the random question set for a criteria',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_rating_get_item_ratings' => array(
|
||||
'classname' => 'core_rating_external',
|
||||
'methodname' => 'get_item_ratings',
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
{{!
|
||||
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 core/paged_content
|
||||
|
||||
This template renders each of the content regions for a paginated
|
||||
content section.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"pagingbar": {
|
||||
"itemsperpage": 1,
|
||||
"previous": true,
|
||||
"next": true,
|
||||
"first": true,
|
||||
"last": true,
|
||||
"pages": [
|
||||
{
|
||||
"page": "1",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"url": "#",
|
||||
"page": "2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"active": true,
|
||||
"page": 1,
|
||||
"content": "<p>Some page 1 content</p>"
|
||||
},
|
||||
{
|
||||
"page": 2,
|
||||
"content": "<p>Some page 2 content</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div id="paged-content-container-{{uniqid}}" data-region="paged-content-container">
|
||||
{{#pagingbar}}
|
||||
{{> core/paged_content_paging_bar }}
|
||||
{{/pagingbar}}
|
||||
{{#pagingdropdown}}
|
||||
{{> core/paged_content_paging_dropdown }}
|
||||
{{/pagingdropdown}}
|
||||
{{> core/paged_content_pages }}
|
||||
</div>
|
||||
{{^skipjs}}
|
||||
{{#js}}
|
||||
require(
|
||||
[
|
||||
'jquery',
|
||||
'core/paged_content_pages'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
PagedContent
|
||||
) {
|
||||
var container = $("#paged-content-container-{{uniqid}}");
|
||||
var pagingContent = container.find(PagedContent.rootSelector);
|
||||
|
||||
PagedContent.init(pagingContent, container);
|
||||
});
|
||||
{{/js}}
|
||||
{{/skipjs}}
|
||||
@@ -0,0 +1,36 @@
|
||||
{{!
|
||||
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 core/paged_content_page
|
||||
|
||||
This template renders the content of a page. It is to be used with
|
||||
the paging bar or paging dropdown to toggle visibility of the content items.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"active": true,
|
||||
"page": 1,
|
||||
"content": "<p>Some page content</p>"
|
||||
}
|
||||
}}
|
||||
<div data-region="paged-content-page"
|
||||
data-page="{{page}}"
|
||||
class="{{^active}}hidden{{/active}} {{$classes}}{{/classes}}">
|
||||
{{$content}}
|
||||
{{{content}}}
|
||||
{{/content}}
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
{{!
|
||||
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 core/paged_content_pages
|
||||
|
||||
This template renders each of the content regions for a paginated
|
||||
content section.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"active": true,
|
||||
"page": 1,
|
||||
"content": "<p>Some page content</p>"
|
||||
},
|
||||
{
|
||||
"page": 2,
|
||||
"content": "<p>Some page content</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div id="{{$pagingcontentid}}page-container-{{uniqid}}{{/pagingcontentid}}" data-region="page-container">
|
||||
{{#pages}}
|
||||
{{$paged-content-page}}
|
||||
{{> core/paged_content_page }}
|
||||
{{/paged-content-page}}
|
||||
{{/pages}}
|
||||
</div>
|
||||
@@ -0,0 +1,97 @@
|
||||
{{!
|
||||
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 core/paged_content_paging_bar
|
||||
|
||||
This template renders the bootstrap style paging bar to control a paged
|
||||
content section.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"itemsperpage": 2,
|
||||
"previous": true,
|
||||
"next": true,
|
||||
"first": true,
|
||||
"last": true,
|
||||
"pages": [
|
||||
{
|
||||
"url": "#",
|
||||
"page": "1",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"url": "#",
|
||||
"page": "2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<nav aria-label="{{label}}"
|
||||
id="{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}"
|
||||
data-region="paging-bar"
|
||||
data-items-per-page="{{itemsperpage}}">
|
||||
|
||||
<ul class="pagination">
|
||||
{{#previous}}
|
||||
{{< core/paged_content_paging_bar_item }}
|
||||
{{$item-content}}
|
||||
<span aria-hidden="true">«</span>
|
||||
<span class="sr-only">{{#str}}previous{{/str}}</span>
|
||||
{{/item-content}}
|
||||
{{$attributes}}data-control="previous"{{/attributes}}
|
||||
{{/ core/paged_content_paging_bar_item }}
|
||||
{{/previous}}
|
||||
{{#first}}
|
||||
{{< core/paged_content_paging_bar_item }}
|
||||
{{$item-content}}
|
||||
<span aria-hidden="true">{{#str}}first{{/str}}</span>
|
||||
<span class="sr-only">{{#str}}first{{/str}}</span>
|
||||
{{/item-content}}
|
||||
{{$attributes}}data-control="first"{{/attributes}}
|
||||
{{/ core/paged_content_paging_bar_item }}
|
||||
{{/first}}
|
||||
{{#pages}}
|
||||
{{< core/paged_content_paging_bar_item }}
|
||||
{{$attributes}}data-page="true"{{/attributes}}
|
||||
{{/ core/paged_content_paging_bar_item }}
|
||||
{{/pages}}
|
||||
{{#last}}
|
||||
{{< core/paged_content_paging_bar_item }}
|
||||
{{$item-content}}
|
||||
<span aria-hidden="true">{{#str}}last{{/str}}</span>
|
||||
<span class="sr-only">{{#str}}last{{/str}}</span>
|
||||
{{/item-content}}
|
||||
{{$attributes}}data-control="last"{{/attributes}}
|
||||
{{/ core/paged_content_paging_bar_item }}
|
||||
{{/last}}
|
||||
{{#next}}
|
||||
{{< core/paged_content_paging_bar_item }}
|
||||
{{$item-content}}
|
||||
<span aria-hidden="true">»</span>
|
||||
<span class="sr-only">{{#str}}next{{/str}}</span>
|
||||
{{/item-content}}
|
||||
{{$attributes}}data-control="next"{{/attributes}}
|
||||
{{/ core/paged_content_paging_bar_item }}
|
||||
{{/next}}
|
||||
</ul>
|
||||
</nav>
|
||||
{{#js}}
|
||||
require(['jquery', 'core/paged_content_paging_bar'], function($, PagingControl) {
|
||||
var root = $('#{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}');
|
||||
PagingControl.init(root);
|
||||
});
|
||||
{{/js}}
|
||||
@@ -0,0 +1,41 @@
|
||||
{{!
|
||||
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 core/paged_content_paging_bar_item
|
||||
|
||||
This template renders a single item in the paging bar.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"url": "#",
|
||||
"number": 1,
|
||||
"page": "1",
|
||||
"active": true
|
||||
}
|
||||
}}
|
||||
<li class="page-item {{#active}}active{{/active}} {{#disabled}}disabled{{/disabled}}"
|
||||
data-region="page-item"
|
||||
{{$attributes}}{{/attributes}}>
|
||||
|
||||
<a href="{{#url}}{{.}}{{/url}}{{^url}}#{{/url}}"
|
||||
class="page-link"
|
||||
data-region="page-link">
|
||||
{{$item-content}}
|
||||
{{{page}}}
|
||||
{{/item-content}}
|
||||
</a>
|
||||
</li>
|
||||
@@ -0,0 +1,75 @@
|
||||
{{!
|
||||
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 core/paged_content_paging_dropdown
|
||||
|
||||
This template renders the bootstrap style dropdown menu to control
|
||||
paged content.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"options": [
|
||||
{
|
||||
"itemcount": 25,
|
||||
"content": "25",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"itemcount": 25,
|
||||
"content": "50"
|
||||
},
|
||||
{
|
||||
"itemcount": 50,
|
||||
"content": "100"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="dropdown m-b-1"
|
||||
id="paging-dropdown-{{uniqid}}"
|
||||
data-region="paging-dropdown-container">
|
||||
|
||||
<button class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdown-menu-button-{{uniqid}}"
|
||||
data-region="dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
|
||||
{{#options}}
|
||||
{{#active}}
|
||||
{{{content}}}
|
||||
{{/active}}
|
||||
{{/options}}
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown-menu-button-{{uniqid}}">
|
||||
{{#options}}
|
||||
{{> core/paged_content_paging_dropdown_item }}
|
||||
{{/options}}
|
||||
{{< core/paged_content_paging_dropdown_item }}
|
||||
{{$itemcount}}0{{/itemcount}}
|
||||
{{$content}}{{#str}} all {{/str}}{{/content}}
|
||||
{{/ core/paged_content_paging_dropdown_item }}
|
||||
</div>
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['jquery', 'core/paged_content_paging_dropdown'], function($, PagingControl) {
|
||||
var root = $('#paging-dropdown-{{uniqid}}');
|
||||
PagingControl.init(root);
|
||||
});
|
||||
{{/js}}
|
||||
@@ -0,0 +1,35 @@
|
||||
{{!
|
||||
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 core/paged_content_paging_dropdown_item
|
||||
|
||||
This template renders a single item in the paging dropdown menu.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"itemcount": 25,
|
||||
"content": "25",
|
||||
"active": true
|
||||
}
|
||||
}}
|
||||
<a class="dropdown-item {{#active}}active{{/active}} {{#disabled}}disabled{{/disabled}} {{$classes}}{{/classes}}"
|
||||
data-region="dropdown-item"
|
||||
data-item-count="{{$itemcount}}{{itemcount}}{{/itemcount}}"
|
||||
href="#">
|
||||
|
||||
{{$content}}{{{content}}}{{/content}}
|
||||
</a>
|
||||
Reference in New Issue
Block a user