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);
// 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();
});
// Submit report via filter
- var submitWithFilter = (containerelement) => {
+ const submitWithFilter = (containerelement) => {
// Close the container (eg popover).
$(containerelement).addClass('hidden');
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.
});
// 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'});
// 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);
+ });
};
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',
}
}
};
--- /dev/null
+<?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);
+ }
+}
use renderer_base;
use stdClass;
use templatable;
+use forumreport_summary;
defined('MOODLE_INTERNAL') || die();
*/
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.
*
// 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);
}
/**
$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.
*
$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;
}
}
/** 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';
// Define configs.
$this->define_table_configs();
- // Define the basic SQL data and object format.
- $this->define_base_sql();
-
// Apply relevant filters.
+ $this->define_base_filter_sql();
$this->apply_filters($filters);
+
+ // Define the basic SQL data and object format.
+ $this->define_base_sql();
}
/**
- * 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];
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;
$this->is_downloadable(true);
$this->no_sorting('select');
$this->set_attribute('id', 'forumreport_summary_table');
+ $this->sql = new \stdClass();
+ $this->sql->params = [];
}
/**
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);
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
$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;
$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 = '';
// 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);
}
/**
$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);
// 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);
$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)';
--- /dev/null
+{{!
+ 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}}
--- /dev/null
+{{!
+ 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>
--- /dev/null
+{{!
+ 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}}
"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}}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2019090200;
+$plugin->version = 2019101800;
$plugin->requires = 2019071900;
$plugin->component = 'forumreport_summary';
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,
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; }
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; }