mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 08:22:07 +02:00
Merge branch 'MDL-66373-master-2' of https://github.com/Chocolate-lightning/moodle_forum-project
This commit is contained in:
commit
fcc1facdca
@ -1371,4 +1371,82 @@ class core_calendar_external extends external_api {
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the specified dates into unix timestamps.
|
||||
*
|
||||
* @param array $datetimes Array of arrays containing date time details, each in the format:
|
||||
* ['year' => a, 'month' => b, 'day' => c,
|
||||
* 'hour' => d (optional), 'minute' => e (optional), 'key' => 'x' (optional)]
|
||||
* @return array Provided array of dates converted to unix timestamps
|
||||
* @throws moodle_exception If one or more of the dates provided does not convert to a valid timestamp.
|
||||
*/
|
||||
public static function get_timestamps($datetimes) {
|
||||
$params = self::validate_parameters(self::get_timestamps_parameters(), ['data' => $datetimes]);
|
||||
|
||||
$type = \core_calendar\type_factory::get_calendar_instance();
|
||||
$timestamps = ['timestamps' => []];
|
||||
|
||||
foreach ($params['data'] as $key => $datetime) {
|
||||
$hour = $datetime['hour'] ?? 0;
|
||||
$minute = $datetime['minute'] ?? 0;
|
||||
|
||||
try {
|
||||
$timestamp = $type->convert_to_timestamp(
|
||||
$datetime['year'], $datetime['month'], $datetime['day'], $hour, $minute);
|
||||
|
||||
$timestamps['timestamps'][] = [
|
||||
'key' => $datetime['key'] ?? $key,
|
||||
'timestamp' => $timestamp,
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw new moodle_exception('One or more of the dates provided were invalid');
|
||||
}
|
||||
}
|
||||
|
||||
return $timestamps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the parameters for get_timestamps.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function get_timestamps_parameters() {
|
||||
return new external_function_parameters ([
|
||||
'data' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
[
|
||||
'key' => new external_value(PARAM_ALPHANUMEXT, 'key', VALUE_OPTIONAL),
|
||||
'year' => new external_value(PARAM_INT, 'year'),
|
||||
'month' => new external_value(PARAM_INT, 'month'),
|
||||
'day' => new external_value(PARAM_INT, 'day'),
|
||||
'hour' => new external_value(PARAM_INT, 'hour', VALUE_OPTIONAL),
|
||||
'minute' => new external_value(PARAM_INT, 'minute', VALUE_OPTIONAL),
|
||||
]
|
||||
)
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the timestamps return format.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function get_timestamps_returns() {
|
||||
return new external_single_structure(
|
||||
[
|
||||
'timestamps' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
[
|
||||
'key' => new external_value(PARAM_ALPHANUMEXT, 'Timestamp key'),
|
||||
'timestamp' => new external_value(PARAM_INT, 'Unix timestamp'),
|
||||
]
|
||||
)
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2696,4 +2696,87 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
);
|
||||
$this->assertEquals(['user', 'course', 'group'], $data['allowedeventtypes']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_timestamps with string keys, with and without optional hour/minute values.
|
||||
*/
|
||||
public function test_get_timestamps_string_keys() {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$time1 = new DateTime('2018-12-30 00:00:00');
|
||||
$time2 = new DateTime('2019-03-27 23:59:00');
|
||||
|
||||
$dates = [
|
||||
[
|
||||
'key' => 'from',
|
||||
'year' => $time1->format('Y'),
|
||||
'month' => $time1->format('m'),
|
||||
'day' => $time1->format('d'),
|
||||
],
|
||||
[
|
||||
'key' => 'to',
|
||||
'year' => $time2->format('Y'),
|
||||
'month' => (int) $time2->format('m'),
|
||||
'day' => $time2->format('d'),
|
||||
'hour' => $time2->format('H'),
|
||||
'minute' => $time2->format('i'),
|
||||
],
|
||||
];
|
||||
|
||||
$expectedtimestamps = [
|
||||
'from' => $time1->getTimestamp(),
|
||||
'to' => $time2->getTimestamp(),
|
||||
];
|
||||
|
||||
$result = core_calendar_external::get_timestamps($dates);
|
||||
|
||||
$this->assertEquals(['timestamps'], array_keys($result));
|
||||
$this->assertEquals(2, count($result['timestamps']));
|
||||
|
||||
foreach ($result['timestamps'] as $data) {
|
||||
$this->assertTrue(in_array($data['key'], ['from', 'to']));
|
||||
$this->assertEquals($expectedtimestamps[$data['key']], $data['timestamp']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_timestamps with no keys specified, with and without optional hour/minute values.
|
||||
*/
|
||||
public function test_get_timestamps_no_keys() {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$time1 = new DateTime('2018-12-30 00:00:00');
|
||||
$time2 = new DateTime('2019-03-27 23:59:00');
|
||||
|
||||
$dates = [
|
||||
[
|
||||
'year' => $time1->format('Y'),
|
||||
'month' => $time1->format('m'),
|
||||
'day' => $time1->format('d'),
|
||||
],
|
||||
[
|
||||
'year' => $time2->format('Y'),
|
||||
'month' => (int) $time2->format('m'),
|
||||
'day' => $time2->format('d'),
|
||||
'hour' => $time2->format('H'),
|
||||
'minute' => $time2->format('i'),
|
||||
],
|
||||
];
|
||||
|
||||
$expectedtimestamps = [
|
||||
0 => $time1->getTimestamp(),
|
||||
1 => $time2->getTimestamp(),
|
||||
];
|
||||
|
||||
$result = core_calendar_external::get_timestamps($dates);
|
||||
|
||||
$this->assertEquals(['timestamps'], array_keys($result));
|
||||
$this->assertEquals(2, count($result['timestamps']));
|
||||
|
||||
foreach ($result['timestamps'] as $data) {
|
||||
$this->assertEquals($expectedtimestamps[$data['key']], $data['timestamp']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ information provided here is intended especially for developers.
|
||||
* calendar_cron()
|
||||
* calendar_get_mini()
|
||||
* calendar_get_upcoming()
|
||||
* Added core_calendar_external::get_timestamps(), which allows an array containing an arbitrary number of arrays of
|
||||
date/time data to be converted and returned as timestamps, along with an optional key.
|
||||
|
||||
=== 3.6 ===
|
||||
* calendar_get_default_courses() function now has optional $userid parameter.
|
||||
|
@ -261,6 +261,14 @@ $functions = array(
|
||||
'type' => 'read',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
|
||||
),
|
||||
'core_calendar_get_timestamps' => [
|
||||
'classname' => 'core_calendar_external',
|
||||
'methodname' => 'get_timestamps',
|
||||
'description' => 'Fetch unix timestamps for given date times.',
|
||||
'classpath' => 'calendar/externallib.php',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
],
|
||||
'core_cohort_add_cohort_members' => array(
|
||||
'classname' => 'core_cohort_external',
|
||||
'methodname' => 'add_cohort_members',
|
||||
|
@ -1,2 +1,2 @@
|
||||
define ("forumreport_summary/filters",["exports","jquery","core/popper","core/custom_interaction_events","forumreport_summary/selectors"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=f(b);c=f(c);d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}var g=function(a){var f=(0,b.default)(a);(0,b.default)(document).ready(function(){(0,b.default)(".loading-icon").hide();(0,b.default)("#summaryreport").removeClass("hidden")});var g=function(a){var c=(0,b.default)("#filtersform").attr("action");if(a){a.preventDefault();var d=a.target.search.substr(1);c+="&"+d}(0,b.default)("#filtersform").attr("action",c);(0,b.default)("#filtersform").submit()};(0,b.default)(".resettable").on("click","a",function(a){g(a)});(0,b.default)("thead").on("click","a",function(a){g(a)});(0,b.default)(".pagination").on("click","a",function(a){g(a)});var h=function(a){(0,b.default)(a).addClass("hidden");g(!1)};f.on(d.default.events.activate,e.default.filters.group.selectall,function(){var b=a.querySelectorAll(e.default.filters.group.checkbox+":not(:checked)");b.forEach(function(a){a.checked=!0})});f.on(d.default.events.activate,e.default.filters.group.clear,function(){var b=a.querySelectorAll(e.default.filters.group.checkbox+":checked");b.forEach(function(a){a.checked=!1})});f.on(d.default.events.activate,e.default.filters.group.trigger,function(){var b=a.querySelector(e.default.filters.group.trigger),d=a.querySelector(e.default.filters.group.popover);new c.default(b,d,{placement:"bottom"});d.classList.remove("hidden");b.classList.add("btn-outline-primary");b.classList.remove("btn-primary");b.setAttribute("aria-expanded",!0)});f.on(d.default.events.activate,e.default.filters.group.save,function(){h("#filter-groups-popover")})};a.init=g});
|
||||
define ("forumreport_summary/filters",["exports","jquery","core/popper","core/custom_interaction_events","forumreport_summary/selectors","core/yui","core/ajax"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=h(b);c=h(c);d=h(d);e=h(e);f=h(f);g=h(g);function h(a){return a&&a.__esModule?a:{default:a}}var i=function(a){var h=(0,b.default)(a);(0,b.default)(document).ready(function(){(0,b.default)(".loading-icon").hide();(0,b.default)("#summaryreport").removeClass("hidden")});var i=function(a){var c=(0,b.default)("#filtersform").attr("action");if(a){a.preventDefault();var d=a.target.search.substr(1);c+="&"+d}(0,b.default)("#filtersform").attr("action",c);(0,b.default)("#filtersform").submit()};(0,b.default)(".resettable").on("click","a",function(a){i(a)});(0,b.default)("thead").on("click","a",function(a){i(a)});(0,b.default)(".pagination").on("click","a",function(a){i(a)});var j=function(a){(0,b.default)(a).addClass("hidden");i(!1)},k=function(a){var b=document.querySelector(a),d=document.querySelector(e.default.filters.date.calendar);d.style.removeProperty("z-index");new c.default(b,d,{placement:"bottom"})},l=function(a){if(document.querySelector("[data-openfilter=\"true\"]")){return!1}a.target.setAttribute("data-openfilter","true");return!0};h.on(d.default.events.activate,e.default.filters.group.selectall,function(){var b=a.querySelectorAll(e.default.filters.group.checkbox+":not(:checked)");b.forEach(function(a){a.checked=!0})});h.on(d.default.events.activate,e.default.filters.group.clear,function(){var b=a.querySelectorAll(e.default.filters.group.checkbox+":checked");b.forEach(function(a){a.checked=!1})});h.on(d.default.events.activate,e.default.filters.group.trigger,function(b){if(!l(b)){return!1}var d=a.querySelector(e.default.filters.group.trigger),f=a.querySelector(e.default.filters.group.popover);new c.default(d,f,{placement:"bottom"});f.classList.remove("hidden");d.classList.add("btn-outline-primary");d.classList.remove("btn-primary");d.setAttribute("aria-expanded",!0);return!0});h.on(d.default.events.activate,e.default.filters.group.save,function(){j("#filter-groups-popover")});h.on(d.default.events.activate,e.default.filters.date.trigger,function(b){if(!l(b)){return!1}var d=a.querySelector(e.default.filters.date.trigger),f=a.querySelector(e.default.filters.date.popover);new c.default(d,f,{placement:"bottom"});f.classList.remove("hidden");f.querySelector("[name=\"filterdatefrompopover[enabled]\"]").focus();d.classList.add("btn-outline-primary");d.classList.remove("btn-primary");d.setAttribute("aria-expanded",!0);return!0});h.on(d.default.events.activate,e.default.filters.date.save,function(){var b=document.forms.filtersform,c=a.querySelector(e.default.filters.date.popover),d=c.querySelector("[name=\"filterdatefrompopover[enabled]\"]").checked?1:0,h=c.querySelector("[name=\"filterdatetopopover[enabled]\"]").checked?1:0;f.default.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()});if(!d&&!h){b.elements["datefrom[timestamp]"].value=0;b.elements["datefrom[enabled]"].value=d;b.elements["dateto[timestamp]"].value=0;b.elements["dateto[enabled]"].value=h;j("#filter-dates-popover")}else{var i={data:[]};if(d){i.data.push({key:"from",year:c.querySelector("[name=\"filterdatefrompopover[year]\"]").value,month:c.querySelector("[name=\"filterdatefrompopover[month]\"]").value,day:c.querySelector("[name=\"filterdatefrompopover[day]\"]").value,hour:0,minute:0})}if(h){i.data.push({key:"to",year:c.querySelector("[name=\"filterdatetopopover[year]\"]").value,month:c.querySelector("[name=\"filterdatetopopover[month]\"]").value,day:c.querySelector("[name=\"filterdatetopopover[day]\"]").value,hour:23,minute:59})}g.default.call([{methodname:"core_calendar_get_timestamps",args:i}])[0].done(function(a){var c=0,e=0;a.timestamps.forEach(function(a){if("from"===a.key){c=a.timestamp}else if("to"===a.key){e=a.timestamp}});if(0<e&&c>e){var f=document.getElementById("dates-filter-warning");f.classList.remove("hidden");f.classList.add("d-block")}else{b.elements["datefrom[timestamp]"].value=c;b.elements["datefrom[enabled]"].value=d;b.elements["dateto[timestamp]"].value=e;b.elements["dateto[enabled]"].value=h;j("#filter-dates-popover")}})}});h.on(d.default.events.activate,e.default.filters.date.calendariconfrom,function(){k(e.default.filters.date.calendariconfrom)});h.on(d.default.events.activate,e.default.filters.date.calendariconto,function(){k(e.default.filters.date.calendariconto)})};a.init=i});
|
||||
//# sourceMappingURL=filters.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
define ("forumreport_summary/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={filters:{group:{checkbox:"[data-region=\"filter-groups\"] input[type=\"checkbox\"]",clear:"[data-region=\"filter-groups\"] .filter-clear",popover:"#filter-groups-popover",save:"[data-region=\"filter-groups\"] .filter-save",selectall:"[data-region=\"filter-groups\"] .select-all",trigger:"#filter-groups-button"}}};return a.default});
|
||||
define ("forumreport_summary/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={filters:{group:{checkbox:"[data-region=\"filter-groups\"] input[type=\"checkbox\"]",clear:"[data-region=\"filter-groups\"] .filter-clear",popover:"#filter-groups-popover",save:"[data-region=\"filter-groups\"] .filter-save",selectall:"[data-region=\"filter-groups\"] .select-all",trigger:"#filter-groups-button"},date:{calendar:"#dateselector-calendar-panel",calendariconfrom:"#id_filterdatefrompopover_calendar",calendariconto:"#id_filterdatetopopover_calendar",popover:"#filter-dates-popover",save:"[data-region=\"filter-dates\"] .filter-save",trigger:"#filter-dates-button"}}};return a.default});
|
||||
//# sourceMappingURL=selectors.min.js.map
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sources":["../src/selectors.js"],"names":["filters","group","checkbox","clear","popover","save","selectall","trigger"],"mappings":"yJAwBe,CACXA,OAAO,CAAE,CACLC,KAAK,CAAE,CACHC,QAAQ,CAAE,0DADP,CAEHC,KAAK,CAAE,+CAFJ,CAGHC,OAAO,CAAE,wBAHN,CAIHC,IAAI,CAAE,8CAJH,CAKHC,SAAS,CAAE,6CALR,CAMHC,OAAO,CAAE,uBANN,CADF,CADE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module containing the selectors for the forum summary report.\n *\n * @module forumreport_summary/selectors\n * @package forumreport_summary\n * @copyright 2019 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n filters: {\n group: {\n checkbox: '[data-region=\"filter-groups\"] input[type=\"checkbox\"]',\n clear: '[data-region=\"filter-groups\"] .filter-clear',\n popover: '#filter-groups-popover',\n save: '[data-region=\"filter-groups\"] .filter-save',\n selectall: '[data-region=\"filter-groups\"] .select-all',\n trigger: '#filter-groups-button',\n }\n }\n};\n"],"file":"selectors.min.js"}
|
||||
{"version":3,"sources":["../src/selectors.js"],"names":["filters","group","checkbox","clear","popover","save","selectall","trigger","date","calendar","calendariconfrom","calendariconto"],"mappings":"yJAwBe,CACXA,OAAO,CAAE,CACLC,KAAK,CAAE,CACHC,QAAQ,CAAE,0DADP,CAEHC,KAAK,CAAE,+CAFJ,CAGHC,OAAO,CAAE,wBAHN,CAIHC,IAAI,CAAE,8CAJH,CAKHC,SAAS,CAAE,6CALR,CAMHC,OAAO,CAAE,uBANN,CADF,CASLC,IAAI,CAAE,CACFC,QAAQ,CAAE,8BADR,CAEFC,gBAAgB,CAAE,oCAFhB,CAGFC,cAAc,CAAE,kCAHd,CAIFP,OAAO,CAAE,uBAJP,CAKFC,IAAI,CAAE,6CALJ,CAMFE,OAAO,CAAE,sBANP,CATD,CADE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module containing the selectors for the forum summary report.\n *\n * @module forumreport_summary/selectors\n * @package forumreport_summary\n * @copyright 2019 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n filters: {\n group: {\n checkbox: '[data-region=\"filter-groups\"] input[type=\"checkbox\"]',\n clear: '[data-region=\"filter-groups\"] .filter-clear',\n popover: '#filter-groups-popover',\n save: '[data-region=\"filter-groups\"] .filter-save',\n selectall: '[data-region=\"filter-groups\"] .select-all',\n trigger: '#filter-groups-button',\n },\n date: {\n calendar: '#dateselector-calendar-panel',\n calendariconfrom: '#id_filterdatefrompopover_calendar',\n calendariconto: '#id_filterdatetopopover_calendar',\n popover: '#filter-dates-popover',\n save: '[data-region=\"filter-dates\"] .filter-save',\n trigger: '#filter-dates-button',\n }\n }\n};\n"],"file":"selectors.min.js"}
|
@ -26,6 +26,8 @@ import $ from 'jquery';
|
||||
import Popper from 'core/popper';
|
||||
import CustomEvents from 'core/custom_interaction_events';
|
||||
import Selectors from 'forumreport_summary/selectors';
|
||||
import Y from 'core/yui';
|
||||
import Ajax from 'core/ajax';
|
||||
|
||||
export const init = (root) => {
|
||||
let jqRoot = $(root);
|
||||
@ -40,8 +42,8 @@ export const init = (root) => {
|
||||
// Generic filter handlers.
|
||||
|
||||
// Called to override click event to trigger a proper generate request with filtering.
|
||||
var generateWithFilters = (event) => {
|
||||
var newLink = $('#filtersform').attr('action');
|
||||
const generateWithFilters = (event) => {
|
||||
let newLink = $('#filtersform').attr('action');
|
||||
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
@ -70,7 +72,7 @@ export const init = (root) => {
|
||||
});
|
||||
|
||||
// Submit report via filter
|
||||
var submitWithFilter = (containerelement) => {
|
||||
const submitWithFilter = (containerelement) => {
|
||||
// Close the container (eg popover).
|
||||
$(containerelement).addClass('hidden');
|
||||
|
||||
@ -78,6 +80,25 @@ export const init = (root) => {
|
||||
generateWithFilters(false);
|
||||
};
|
||||
|
||||
// Use popper to override date mform calendar position.
|
||||
const updateCalendarPosition = (referenceid) => {
|
||||
let referenceElement = document.querySelector(referenceid),
|
||||
popperContent = document.querySelector(Selectors.filters.date.calendar);
|
||||
|
||||
popperContent.style.removeProperty("z-index");
|
||||
new Popper(referenceElement, popperContent, {placement: 'bottom'});
|
||||
};
|
||||
|
||||
// Call when opening filter to ensure only one can be activated.
|
||||
const canOpenFilter = (event) => {
|
||||
if (document.querySelector('[data-openfilter="true"]')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event.target.setAttribute('data-openfilter', "true");
|
||||
return true;
|
||||
};
|
||||
|
||||
// Groups filter specific handlers.
|
||||
|
||||
// Event handler for clicking select all groups.
|
||||
@ -98,9 +119,13 @@ export const init = (root) => {
|
||||
});
|
||||
|
||||
// Event handler for showing groups filter popover.
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.trigger, function() {
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.trigger, function(event) {
|
||||
if (!canOpenFilter(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create popover.
|
||||
var referenceElement = root.querySelector(Selectors.filters.group.trigger),
|
||||
let referenceElement = root.querySelector(Selectors.filters.group.trigger),
|
||||
popperContent = root.querySelector(Selectors.filters.group.popover);
|
||||
|
||||
new Popper(referenceElement, popperContent, {placement: 'bottom'});
|
||||
@ -114,10 +139,128 @@ export const init = (root) => {
|
||||
|
||||
// Let screen readers know that it's now expanded.
|
||||
referenceElement.setAttribute('aria-expanded', true);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Event handler to click save groups filter.
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.group.save, function() {
|
||||
submitWithFilter('#filter-groups-popover');
|
||||
});
|
||||
|
||||
// Dates filter specific handlers.
|
||||
|
||||
// Event handler for showing dates filter popover.
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.trigger, function(event) {
|
||||
if (!canOpenFilter(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create popover.
|
||||
let referenceElement = root.querySelector(Selectors.filters.date.trigger),
|
||||
popperContent = root.querySelector(Selectors.filters.date.popover);
|
||||
|
||||
new Popper(referenceElement, popperContent, {placement: 'bottom'});
|
||||
|
||||
// Show popover and move focus.
|
||||
popperContent.classList.remove('hidden');
|
||||
popperContent.querySelector('[name="filterdatefrompopover[enabled]"]').focus();
|
||||
|
||||
// Change to outlined button.
|
||||
referenceElement.classList.add('btn-outline-primary');
|
||||
referenceElement.classList.remove('btn-primary');
|
||||
|
||||
// Let screen readers know that it's now expanded.
|
||||
referenceElement.setAttribute('aria-expanded', true);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Event handler to save dates filter.
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.save, function() {
|
||||
// Populate the hidden form inputs to submit the data.
|
||||
let filtersForm = document.forms.filtersform;
|
||||
const datesPopover = root.querySelector(Selectors.filters.date.popover);
|
||||
const fromEnabled = datesPopover.querySelector('[name="filterdatefrompopover[enabled]"]').checked ? 1 : 0;
|
||||
const toEnabled = datesPopover.querySelector('[name="filterdatetopopover[enabled]"]').checked ? 1 : 0;
|
||||
|
||||
// Disable the mform checker to prevent unsubmitted form warning to the user when closing the popover.
|
||||
Y.use('moodle-core-formchangechecker', function() {
|
||||
M.core_formchangechecker.reset_form_dirty_state();
|
||||
});
|
||||
|
||||
if (!fromEnabled && !toEnabled) {
|
||||
// Update the elements in the filter form.
|
||||
filtersForm.elements['datefrom[timestamp]'].value = 0;
|
||||
filtersForm.elements['datefrom[enabled]'].value = fromEnabled;
|
||||
filtersForm.elements['dateto[timestamp]'].value = 0;
|
||||
filtersForm.elements['dateto[enabled]'].value = toEnabled;
|
||||
|
||||
// Submit the filter values and re-generate report.
|
||||
submitWithFilter('#filter-dates-popover');
|
||||
} else {
|
||||
let args = {data: []};
|
||||
|
||||
if (fromEnabled) {
|
||||
args.data.push({
|
||||
'key': 'from',
|
||||
'year': datesPopover.querySelector('[name="filterdatefrompopover[year]"]').value,
|
||||
'month': datesPopover.querySelector('[name="filterdatefrompopover[month]"]').value,
|
||||
'day': datesPopover.querySelector('[name="filterdatefrompopover[day]"]').value,
|
||||
'hour': 0,
|
||||
'minute': 0
|
||||
});
|
||||
}
|
||||
|
||||
if (toEnabled) {
|
||||
args.data.push({
|
||||
'key': 'to',
|
||||
'year': datesPopover.querySelector('[name="filterdatetopopover[year]"]').value,
|
||||
'month': datesPopover.querySelector('[name="filterdatetopopover[month]"]').value,
|
||||
'day': datesPopover.querySelector('[name="filterdatetopopover[day]"]').value,
|
||||
'hour': 23,
|
||||
'minute': 59
|
||||
});
|
||||
}
|
||||
|
||||
const request = {
|
||||
methodname: 'core_calendar_get_timestamps',
|
||||
args: args
|
||||
};
|
||||
|
||||
Ajax.call([request])[0].done(function(result) {
|
||||
let fromTimestamp = 0,
|
||||
toTimestamp = 0;
|
||||
|
||||
result['timestamps'].forEach(function(data){
|
||||
if (data.key === 'from') {
|
||||
fromTimestamp = data.timestamp;
|
||||
} else if (data.key === 'to') {
|
||||
toTimestamp = data.timestamp;
|
||||
}
|
||||
});
|
||||
|
||||
// Display an error if the from date is later than the do date.
|
||||
if (toTimestamp > 0 && fromTimestamp > toTimestamp) {
|
||||
const warningdiv = document.getElementById('dates-filter-warning');
|
||||
warningdiv.classList.remove('hidden');
|
||||
warningdiv.classList.add('d-block');
|
||||
} else {
|
||||
filtersForm.elements['datefrom[timestamp]'].value = fromTimestamp;
|
||||
filtersForm.elements['datefrom[enabled]'].value = fromEnabled;
|
||||
filtersForm.elements['dateto[timestamp]'].value = toTimestamp;
|
||||
filtersForm.elements['dateto[enabled]'].value = toEnabled;
|
||||
|
||||
// Submit the filter values and re-generate report.
|
||||
submitWithFilter('#filter-dates-popover');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.calendariconfrom, function() {
|
||||
updateCalendarPosition(Selectors.filters.date.calendariconfrom);
|
||||
});
|
||||
|
||||
jqRoot.on(CustomEvents.events.activate, Selectors.filters.date.calendariconto, function() {
|
||||
updateCalendarPosition(Selectors.filters.date.calendariconto);
|
||||
});
|
||||
};
|
||||
|
@ -31,6 +31,14 @@ export default {
|
||||
save: '[data-region="filter-groups"] .filter-save',
|
||||
selectall: '[data-region="filter-groups"] .select-all',
|
||||
trigger: '#filter-groups-button',
|
||||
},
|
||||
date: {
|
||||
calendar: '#dateselector-calendar-panel',
|
||||
calendariconfrom: '#id_filterdatefrompopover_calendar',
|
||||
calendariconto: '#id_filterdatetopopover_calendar',
|
||||
popover: '#filter-dates-popover',
|
||||
save: '[data-region="filter-dates"] .filter-save',
|
||||
trigger: '#filter-dates-button',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
53
mod/forum/report/summary/classes/form/dates_filter_form.php
Normal file
53
mod/forum/report/summary/classes/form/dates_filter_form.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* The mform used by the forum summary report dates filter.
|
||||
*
|
||||
* @package forumreport_summary
|
||||
* @copyright 2019 Michael Hawkins <michaelh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace forumreport_summary\form;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot.'/lib/formslib.php');
|
||||
|
||||
/**
|
||||
* The mform class for creating the forum summary report dates filter.
|
||||
*
|
||||
* @copyright 2019 Michael Hawkins <michaelh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dates_filter_form extends \moodleform {
|
||||
/**
|
||||
* The form definition.
|
||||
*
|
||||
*/
|
||||
public function definition() {
|
||||
$attributes = [
|
||||
'class' => 'align-items-center',
|
||||
];
|
||||
|
||||
// From date field.
|
||||
$this->_form->addElement('date_selector', 'filterdatefrompopover', get_string('from'), ['optional' => true], $attributes);
|
||||
|
||||
// To date field.
|
||||
$this->_form->addElement('date_selector', 'filterdatetopopover', get_string('to'), ['optional' => true], $attributes);
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ use renderable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use templatable;
|
||||
use forumreport_summary;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@ -69,6 +70,20 @@ class filters implements renderable, templatable {
|
||||
*/
|
||||
protected $groupsselected = [];
|
||||
|
||||
/**
|
||||
* HTML for dates filter.
|
||||
*
|
||||
* @var array $datesdata
|
||||
*/
|
||||
protected $datesdata = [];
|
||||
|
||||
/**
|
||||
* Text to display on the dates filter button.
|
||||
*
|
||||
* @var string $datesbuttontext
|
||||
*/
|
||||
protected $datesbuttontext;
|
||||
|
||||
/**
|
||||
* Builds renderable filter data.
|
||||
*
|
||||
@ -84,6 +99,11 @@ class filters implements renderable, templatable {
|
||||
// Prepare groups filter data.
|
||||
$groupsdata = $filterdata['groups'] ?? [];
|
||||
$this->prepare_groups_data($groupsdata);
|
||||
|
||||
// Prepare dates filter data.
|
||||
$datefromdata = $filterdata['datefrom'] ?? [];
|
||||
$datetodata = $filterdata['dateto'] ?? [];
|
||||
$this->prepare_dates_data($datefromdata, $datetodata);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,6 +149,78 @@ class filters implements renderable, templatable {
|
||||
$this->groupsselected = $groupsselected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares from date, to date and button text.
|
||||
* Empty data will default to a disabled filter with today's date.
|
||||
*
|
||||
* @param array $datefromdata From date selected for filtering, and whether the filter is enabled.
|
||||
* @param array $datetodata To date selected for filtering, and whether the filter is enabled.
|
||||
* @return void.
|
||||
*/
|
||||
private function prepare_dates_data(array $datefromdata, array $datetodata): void {
|
||||
$timezone = \core_date::get_user_timezone_object();
|
||||
$calendartype = \core_calendar\type_factory::get_calendar_instance();
|
||||
$timestamptoday = time();
|
||||
$datetoday = $calendartype->timestamp_to_date_array($timestamptoday, $timezone);
|
||||
|
||||
// Prepare date/enabled data.
|
||||
if (empty($datefromdata['enabled'])) {
|
||||
$fromdate = $datetoday;
|
||||
$fromtimestamp = $timestamptoday;
|
||||
$fromenabled = false;
|
||||
} else {
|
||||
$fromdate = $calendartype->timestamp_to_date_array($datefromdata['timestamp'], $timezone);
|
||||
$fromtimestamp = $datefromdata['timestamp'];
|
||||
$fromenabled = true;
|
||||
}
|
||||
|
||||
if (empty($datetodata['enabled'])) {
|
||||
$todate = $datetoday;
|
||||
$totimestamp = $timestamptoday;
|
||||
$toenabled = false;
|
||||
} else {
|
||||
$todate = $calendartype->timestamp_to_date_array($datetodata['timestamp'], $timezone);
|
||||
$totimestamp = $datetodata['timestamp'];
|
||||
$toenabled = true;
|
||||
}
|
||||
|
||||
$this->datesdata = [
|
||||
'from' => [
|
||||
'day' => $fromdate['mday'],
|
||||
'month' => $fromdate['mon'],
|
||||
'year' => $fromdate['year'],
|
||||
'timestamp' => $fromtimestamp,
|
||||
'enabled' => $fromenabled,
|
||||
],
|
||||
'to' => [
|
||||
'day' => $todate['mday'],
|
||||
'month' => $todate['mon'],
|
||||
'year' => $todate['year'],
|
||||
'timestamp' => $totimestamp,
|
||||
'enabled' => $toenabled,
|
||||
],
|
||||
];
|
||||
|
||||
// Prepare button string data.
|
||||
$displayformat = get_string('strftimedatemonthabbr', 'langconfig');
|
||||
$fromdatestring = $calendartype->timestamp_to_date_string($fromtimestamp, $displayformat, $timezone, true, true);
|
||||
$todatestring = $calendartype->timestamp_to_date_string($totimestamp, $displayformat, $timezone, true, true);
|
||||
|
||||
if ($fromenabled && $toenabled) {
|
||||
$datestrings = [
|
||||
'datefrom' => $fromdatestring,
|
||||
'dateto' => $todatestring,
|
||||
];
|
||||
$this->datesbuttontext = get_string('filter:datesfromto', 'forumreport_summary', $datestrings);
|
||||
} else if ($fromenabled) {
|
||||
$this->datesbuttontext = get_string('filter:datesfrom', 'forumreport_summary', $fromdatestring);
|
||||
} else if ($toenabled) {
|
||||
$this->datesbuttontext = get_string('filter:datesto', 'forumreport_summary', $todatestring);
|
||||
} else {
|
||||
$this->datesbuttontext = get_string('filter:datesname', 'forumreport_summary');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export data for use as the context of a mustache template.
|
||||
*
|
||||
@ -171,6 +263,33 @@ class filters implements renderable, templatable {
|
||||
$output->hasgroups = false;
|
||||
}
|
||||
|
||||
// Set date button and generate dates popover mform.
|
||||
$datesformdata = [];
|
||||
|
||||
if ($this->datesdata['from']['enabled']) {
|
||||
$datesformdata['filterdatefrompopover'] = $this->datesdata['from'];
|
||||
}
|
||||
|
||||
if ($this->datesdata['to']['enabled']) {
|
||||
$datesformdata['filterdatetopopover'] = $this->datesdata['to'];
|
||||
}
|
||||
|
||||
$output->filterdatesname = $this->datesbuttontext;
|
||||
$datesform = new forumreport_summary\form\dates_filter_form();
|
||||
$datesform->set_data($datesformdata);
|
||||
$output->filterdatesform = $datesform->render();
|
||||
|
||||
// Set dates filter data within filters form.
|
||||
$disableddate = [
|
||||
'day' => '',
|
||||
'month' => '',
|
||||
'year' => '',
|
||||
'enabled' => '0',
|
||||
];
|
||||
$datefromdata = ['type' => 'from'] + ($this->datesdata['from']['enabled'] ? $this->datesdata['from'] : $disableddate);
|
||||
$datetodata = ['type' => 'to'] + ($this->datesdata['to']['enabled'] ? $this->datesdata['to'] : $disableddate);
|
||||
$output->filterdatesdata = [$datefromdata, $datetodata];
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ class summary_table extends table_sql {
|
||||
/** Groups filter type */
|
||||
const FILTER_GROUPS = 2;
|
||||
|
||||
/** Dates filter type */
|
||||
const FILTER_DATES = 3;
|
||||
|
||||
/** Table to store summary data extracted from the log table */
|
||||
const LOG_SUMMARY_TEMP_TABLE = 'forum_report_summary_counts';
|
||||
|
||||
@ -146,23 +149,26 @@ class summary_table extends table_sql {
|
||||
// Define configs.
|
||||
$this->define_table_configs();
|
||||
|
||||
// Apply relevant filters.
|
||||
$this->define_base_filter_sql();
|
||||
$this->apply_filters($filters);
|
||||
|
||||
// Define the basic SQL data and object format.
|
||||
$this->define_base_sql();
|
||||
|
||||
// Apply relevant filters.
|
||||
$this->apply_filters($filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the string name of each filter type.
|
||||
* Provides the string name of each filter type, to be used by errors.
|
||||
* Note: This does not use language strings as the value is injected into error strings.
|
||||
*
|
||||
* @param int $filtertype Type of filter
|
||||
* @return string Name of the filter
|
||||
*/
|
||||
public function get_filter_name(int $filtertype): string {
|
||||
protected function get_filter_name(int $filtertype): string {
|
||||
$filternames = [
|
||||
self::FILTER_FORUM => 'Forum',
|
||||
self::FILTER_GROUPS => 'Groups',
|
||||
self::FILTER_DATES => 'Dates',
|
||||
];
|
||||
|
||||
return $filternames[$filtertype];
|
||||
@ -362,6 +368,38 @@ class summary_table extends table_sql {
|
||||
|
||||
break;
|
||||
|
||||
case self::FILTER_DATES:
|
||||
if (!isset($values['from']['enabled']) || !isset($values['to']['enabled']) ||
|
||||
($values['from']['enabled'] && !isset($values['from']['timestamp'])) ||
|
||||
($values['to']['enabled'] && !isset($values['to']['timestamp']))) {
|
||||
$paramcounterror = true;
|
||||
} else {
|
||||
$this->sql->filterbase['dates'] = '';
|
||||
$this->sql->filterbase['dateslog'] = '';
|
||||
$this->sql->filterbase['dateslogparams'] = [];
|
||||
|
||||
// From date.
|
||||
if ($values['from']['enabled']) {
|
||||
// If the filter was enabled, include the date restriction.
|
||||
// Needs to form part of the base join to posts, so will be injected by define_base_sql().
|
||||
$this->sql->filterbase['dates'] .= " AND p.created >= :fromdate";
|
||||
$this->sql->params['fromdate'] = $values['from']['timestamp'];
|
||||
$this->sql->filterbase['dateslog'] .= ' AND timecreated >= :fromdate';
|
||||
$this->sql->filterbase['dateslogparams']['fromdate'] = $values['from']['timestamp'];
|
||||
}
|
||||
|
||||
// To date.
|
||||
if ($values['to']['enabled']) {
|
||||
// If the filter was enabled, include the date restriction.
|
||||
// Needs to form part of the base join to posts, so will be injected by define_base_sql().
|
||||
$this->sql->filterbase['dates'] .= " AND p.created <= :todate";
|
||||
$this->sql->params['todate'] = $values['to']['timestamp'];
|
||||
$this->sql->filterbase['dateslog'] .= ' AND timecreated <= :todate';
|
||||
$this->sql->filterbase['dateslogparams']['todate'] = $values['to']['timestamp'];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new coding_exception("Report filter type '{$filtertype}' not found.");
|
||||
break;
|
||||
@ -385,6 +423,8 @@ class summary_table extends table_sql {
|
||||
$this->is_downloadable(true);
|
||||
$this->no_sorting('select');
|
||||
$this->set_attribute('id', 'forumreport_summary_table');
|
||||
$this->sql = new \stdClass();
|
||||
$this->sql->params = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,8 +435,6 @@ class summary_table extends table_sql {
|
||||
protected function define_base_sql(): void {
|
||||
global $USER;
|
||||
|
||||
$this->sql = new \stdClass();
|
||||
|
||||
$userfields = get_extra_user_fields($this->context);
|
||||
$userfieldssql = \user_picture::fields('u', $userfields);
|
||||
|
||||
@ -429,7 +467,8 @@ class summary_table extends table_sql {
|
||||
JOIN {forum_discussions} d ON d.forum = f.id
|
||||
LEFT JOIN {forum_posts} p ON p.discussion = d.id
|
||||
AND p.userid = ue.userid
|
||||
' . $privaterepliessql . '
|
||||
' . $privaterepliessql
|
||||
. $this->sql->filterbase['dates'] . '
|
||||
LEFT JOIN (
|
||||
SELECT COUNT(fi.id) AS attcount, fi.itemid AS postid, fi.userid
|
||||
FROM {files} fi
|
||||
@ -457,7 +496,7 @@ class summary_table extends table_sql {
|
||||
$this->sql->basefields .= ', SUM(CASE WHEN p.charcount IS NOT NULL THEN p.charcount ELSE 0 END) AS charcount';
|
||||
}
|
||||
|
||||
$this->sql->params = [
|
||||
$this->sql->params += [
|
||||
'component' => 'mod_forum',
|
||||
'courseid' => $this->cm->course,
|
||||
] + $privaterepliesparams;
|
||||
@ -467,7 +506,14 @@ class summary_table extends table_sql {
|
||||
$this->sql->basewhere .= ' AND ue.userid = :userid';
|
||||
$this->sql->params['userid'] = $this->userid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the properties to store filter values.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
protected function define_base_filter_sql(): void {
|
||||
// Filter values will be populated separately where required.
|
||||
$this->sql->filterfields = '';
|
||||
$this->sql->filterfromjoins = '';
|
||||
@ -533,6 +579,13 @@ class summary_table extends table_sql {
|
||||
|
||||
// Apply groups filter.
|
||||
$this->add_filter(self::FILTER_GROUPS, $filters['groups']);
|
||||
|
||||
// Apply dates filter.
|
||||
$datevalues = [
|
||||
'from' => $filters['datefrom'],
|
||||
'to' => $filters['dateto'],
|
||||
];
|
||||
$this->add_filter(self::FILTER_DATES, $datevalues);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -614,11 +667,17 @@ class summary_table extends table_sql {
|
||||
$logtable = $this->logreader->get_internal_log_table_name();
|
||||
$nonanonymous = 'AND anonymous = 0';
|
||||
}
|
||||
$params = ['contextid' => $contextid];
|
||||
|
||||
// Apply dates filter if applied.
|
||||
$datewhere = $this->sql->filterbase['dateslog'] ?? '';
|
||||
$dateparams = $this->sql->filterbase['dateslogparams'] ?? [];
|
||||
|
||||
$params = ['contextid' => $contextid] + $dateparams;
|
||||
$sql = "INSERT INTO {" . self::LOG_SUMMARY_TEMP_TABLE . "} (userid, viewcount)
|
||||
SELECT userid, COUNT(*) AS viewcount
|
||||
FROM {" . $logtable . "}
|
||||
WHERE contextid = :contextid
|
||||
$datewhere
|
||||
$nonanonymous
|
||||
GROUP BY userid";
|
||||
$DB->execute($sql, $params);
|
||||
|
@ -36,6 +36,8 @@ $filters = [];
|
||||
// Establish filter values.
|
||||
$filters['forums'] = [$forumid];
|
||||
$filters['groups'] = optional_param_array('filtergroups', [], PARAM_INT);
|
||||
$filters['datefrom'] = optional_param_array('datefrom', ['enabled' => 0], PARAM_INT);
|
||||
$filters['dateto'] = optional_param_array('dateto', ['enabled' => 0], PARAM_INT);
|
||||
|
||||
$download = optional_param('download', '', PARAM_ALPHA);
|
||||
|
||||
|
@ -26,6 +26,12 @@ $string['attachmentcount'] = 'Number of attachments';
|
||||
$string['charcount'] = 'Character count';
|
||||
$string['viewcount'] = 'Number of views';
|
||||
$string['earliestpost'] = 'Earliest post';
|
||||
$string['filter:datesbuttonlabel'] = 'Open the dates filter';
|
||||
$string['filter:datesname'] = 'Dates';
|
||||
$string['filter:datesfrom'] = 'From {$a}';
|
||||
$string['filter:datesfromto'] = '{$a->datefrom} - {$a->dateto}';
|
||||
$string['filter:datesorderwarning'] = 'Please ensure the "From" date selected is earlier than the "To" date selected.';
|
||||
$string['filter:datesto'] = 'To {$a}';
|
||||
$string['filter:groupsbuttonlabel'] = 'Open the groups filter';
|
||||
$string['filter:groupsname'] = 'Groups';
|
||||
$string['filter:groupscountall'] = 'Groups (all)';
|
||||
|
50
mod/forum/report/summary/templates/filter_dates.mustache
Normal file
50
mod/forum/report/summary/templates/filter_dates.mustache
Normal file
@ -0,0 +1,50 @@
|
||||
{{!
|
||||
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 forumreport_summary/filter_dates
|
||||
|
||||
Summary report dates filter.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"filterdatesname": "Dates",
|
||||
"filterdatesdata": [
|
||||
{
|
||||
"type": "from",
|
||||
"timestamp": "1571377510",
|
||||
"enabled": "1"
|
||||
},
|
||||
{
|
||||
"type": "to",
|
||||
"timestamp": "1571377510",
|
||||
"enabled": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
|
||||
|
||||
<button type="button" id="filter-dates-button" class="btn btn-primary rounded p-1" aria-expanded="false"
|
||||
aria-haspopup="true" aria-label="{{# str}} filter:datesbuttonlabel, forumreport_summary {{/ str}}">
|
||||
{{filterdatesname}}
|
||||
</button>
|
||||
|
||||
{{! Hidden dates fields to populate from visible mform in popover. }}
|
||||
{{#filterdatesdata}}
|
||||
<input type="hidden" name="date{{type}}[timestamp]" value="{{timestamp}}">
|
||||
<input type="hidden" name="date{{type}}[enabled]" value="{{enabled}}">
|
||||
{{/filterdatesdata}}
|
@ -0,0 +1,40 @@
|
||||
{{!
|
||||
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 forumreport_summary/filter_dates
|
||||
|
||||
Summary report dates filter.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"filterdatesform": "<div>HTML for date filters</div>"
|
||||
}
|
||||
}}
|
||||
|
||||
<div id="filter-dates-popover" class="popover filter-dates-popover mt-3 hidden">
|
||||
<h3 class="popover-header">{{# str}} filter:datesname, forumreport_summary {{/ str}}</h3>
|
||||
<div class="popover-body" data-region="filter-dates">
|
||||
{{{filterdatesform}}}
|
||||
<div id="dates-filter-warning" class="form-control-feedback text-danger hidden float-right">
|
||||
{{# str}} filter:datesorderwarning, forumreport_summary {{/ str}}
|
||||
</div>
|
||||
<br>
|
||||
<button type="button" class="filter-save float-right btn btn-link p-0" aria-label="{{# str}} save {{/ str}}">
|
||||
<strong>{{# str}} save {{/ str}}</strong>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
70
mod/forum/report/summary/templates/filter_groups.mustache
Normal file
70
mod/forum/report/summary/templates/filter_groups.mustache
Normal file
@ -0,0 +1,70 @@
|
||||
{{!
|
||||
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 forumreport_summary/filter_groups
|
||||
|
||||
Summary report groups filter.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"hasgroups": true,
|
||||
"filtergroupsname" : "Groups (all)",
|
||||
"filtergroups": [
|
||||
{
|
||||
"groupid": "1",
|
||||
"groupname": "Group A",
|
||||
"checked": true
|
||||
},
|
||||
{
|
||||
"groupid": "3",
|
||||
"groupname": "Group C",
|
||||
"checked": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
|
||||
{{#hasgroups}}
|
||||
<button type="button" id="filter-groups-button" class="btn btn-primary rounded p-1 ml-2" aria-expanded="false"
|
||||
aria-haspopup="true" aria-label="{{# str}} filter:groupsbuttonlabel, forumreport_summary {{/ str}}">
|
||||
{{filtergroupsname}}
|
||||
</button>
|
||||
|
||||
{{! Groups filter popover }}
|
||||
<div id="filter-groups-popover" class="popover m-t-1 hidden">
|
||||
<h3 class="popover-header">{{# str}} filter:groupsname, forumreport_summary {{/ str}}</h3>
|
||||
<div class="popover-body" data-region="filter-groups">
|
||||
<div class="form-check filter-scrollable">
|
||||
{{#filtergroups}}
|
||||
<input id="filtergroups{{groupid}}" class="form-check-input" type="checkbox" name="filtergroups[]"
|
||||
value="{{groupid}}" {{#checked}} checked="checked" {{/checked}}>
|
||||
<label class="form-check-label pt-1" for="filtergroups{{groupid}}">{{groupname}}</label>
|
||||
<br>
|
||||
{{/filtergroups}}
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<button type="button" class="select-all btn btn-link p-0 pr-1" aria-label="{{# str}} selectall {{/ str}}">{{# str}} selectall {{/ str}}</button>
|
||||
<div class="float-right">
|
||||
<button type="button" class="filter-clear btn btn-link p-0 px-1" aria-label="{{# str}} clear {{/ str}}">{{# str}} clear {{/ str}}</button>
|
||||
<button type="button" class="filter-save btn btn-link p-0" aria-label="{{# str}} save {{/ str}}">
|
||||
<strong>{{# str}} save {{/ str}}</strong>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/hasgroups}}
|
@ -35,47 +35,36 @@
|
||||
"groupname": "Group C",
|
||||
"checked": false
|
||||
}
|
||||
],
|
||||
"filterdatesname": "Dates",
|
||||
"filterdatesform": "<div>HTML for date filters</div>",
|
||||
"filterdatesdata": [
|
||||
{
|
||||
"type": "from",
|
||||
"timestamp": "510969600",
|
||||
"enabled": "1"
|
||||
},
|
||||
{
|
||||
"type": "to",
|
||||
"timestamp": "725673600",
|
||||
"enabled": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
|
||||
<div class="p-b-3" data-report-id="{{uniqid}}">
|
||||
<div class="pb-4" data-report-id="{{uniqid}}">
|
||||
<form id="filtersform" name="filtersform" method="post" action="{{actionurl}}">
|
||||
<input type="hidden" name="submitted" value="true">
|
||||
<div id="filtersbuttons">
|
||||
{{#hasgroups}}
|
||||
<button type="button" id="filter-groups-button" class="btn btn-primary rounded p-1" aria-expanded="false"
|
||||
aria-haspopup="true" aria-label="{{# str}} filter:groupsbuttonlabel, forumreport_summary {{/ str}}">
|
||||
{{filtergroupsname}}
|
||||
</button>
|
||||
|
||||
{{! Start groups filter popover}}
|
||||
<div id="filter-groups-popover" class="popover m-t-1 hidden">
|
||||
<h3 class="popover-header">{{# str}} filter:groupsname, forumreport_summary {{/ str}}</h3>
|
||||
<div class="popover-body" data-region="filter-groups">
|
||||
<div class="form-check filter-scrollable">
|
||||
{{#filtergroups}}
|
||||
<input id="filtergroups{{groupid}}" class="form-check-input" type="checkbox" name="filtergroups[]"
|
||||
value="{{groupid}}" {{#checked}} checked="checked" {{/checked}}>
|
||||
<label class="form-check-label pt-1" for="filtergroups{{groupid}}">{{groupname}}</label>
|
||||
<br>
|
||||
{{/filtergroups}}
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<button type="button" class="select-all btn btn-link p-0 pr-1" aria-label="{{# str}} selectall {{/ str}}">{{# str}} selectall {{/ str}}</button>
|
||||
<div class="float-right">
|
||||
<button type="button" class="filter-clear btn btn-link p-0 px-1" aria-label="{{# str}} clear {{/ str}}">{{# str}} clear {{/ str}}</button>
|
||||
<button type="button" class="filter-save btn btn-link p-0" aria-label="{{# str}} save {{/ str}}">
|
||||
<strong>{{# str}} save {{/ str}}</strong>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{! End groups filter popover}}
|
||||
{{/hasgroups}}
|
||||
<div id="filtersbuttons">
|
||||
{{> forumreport_summary/filter_dates}}
|
||||
{{> forumreport_summary/filter_groups}}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{! Dates filter popover - mform must exist outside of the filtersform }}
|
||||
{{> forumreport_summary/filter_dates_popover}}
|
||||
</div>
|
||||
|
||||
{{#js}}
|
||||
|
@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2019090200;
|
||||
$plugin->version = 2019101800;
|
||||
$plugin->requires = 2019071900;
|
||||
$plugin->component = 'forumreport_summary';
|
||||
|
@ -416,6 +416,16 @@ $author-image-margin-sm: 8px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
// Required to fit a date mform into a filter popover.
|
||||
.filter-dates-popover {
|
||||
width: 100%;
|
||||
max-width: 41.5em;
|
||||
|
||||
.mform {
|
||||
margin-left: -3em;
|
||||
}
|
||||
}
|
||||
|
||||
// End styling for mod_forum.
|
||||
|
||||
.maincalendar .calendarmonth td,
|
||||
|
@ -16561,6 +16561,12 @@ select {
|
||||
max-height: 25em;
|
||||
margin-bottom: 1em; }
|
||||
|
||||
.filter-dates-popover {
|
||||
width: 100%;
|
||||
max-width: 41.5em; }
|
||||
.filter-dates-popover .mform {
|
||||
margin-left: -3em; }
|
||||
|
||||
.maincalendar .calendarmonth td,
|
||||
.maincalendar .calendarmonth th {
|
||||
border: 1px dotted #dee2e6; }
|
||||
|
@ -16833,6 +16833,12 @@ select {
|
||||
max-height: 25em;
|
||||
margin-bottom: 1em; }
|
||||
|
||||
.filter-dates-popover {
|
||||
width: 100%;
|
||||
max-width: 41.5em; }
|
||||
.filter-dates-popover .mform {
|
||||
margin-left: -3em; }
|
||||
|
||||
.maincalendar .calendarmonth td,
|
||||
.maincalendar .calendarmonth th {
|
||||
border: 1px dotted #dee2e6; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user