Commit d7f69613 by Tyler Hallada Committed by Dennis Jen

Refactored filter.js for generic-list.

parent 25821f65
...@@ -20,7 +20,7 @@ define(function(require) { ...@@ -20,7 +20,7 @@ define(function(require) {
}, },
initialize: function(options) { initialize: function(options) {
this.options = options || {}; this.options = options || {};
this.listenTo(this.options.collection, 'sync', this.onCourseListCollectionUpdated); this.listenTo(this.options.collection, 'backgrid:refresh', this.onCourseListCollectionUpdated);
}, },
onBeforeShow: function() { onBeforeShow: function() {
this.onCourseListCollectionUpdated(this.options.collection); this.onCourseListCollectionUpdated(this.options.collection);
......
...@@ -17,10 +17,8 @@ ...@@ -17,10 +17,8 @@
<% if (filterKey === 'ignore_segments') { %> <% if (filterKey === 'ignore_segments') { %>
<div id="<%- filterId %>"> <div id="<%- filterId %>">
<% _.each(filterValues, function (filterValue) { %> <% _.each(filterValues, function (filterValue) { %>
<% if (filterValue.name === 'inactive') { %> <input id="<%- filterValue.name %>" type="checkbox" value="<%- filterValue.name %>" <% if (filterValue.selected) { %> checked <% } %>>
<input id="<%- filterValue.name %>" type="checkbox" value="<%- filterValue.name %>" <% if (hideInactive) { %> checked <% } %>> <label for="<%- filterValue.name %>"> <%- selectDisplayName %> </label><br>
<label for="<%- filterValue.name %>"> <%- selectDisplayName %> </label><br>
<% } %>
<% }); %> <% }); %>
</div> </div>
<% } %> <% } %>
......
...@@ -27,10 +27,10 @@ define(function(require) { ...@@ -27,10 +27,10 @@ define(function(require) {
// It is assumed that there can never be a filter with an empty // It is assumed that there can never be a filter with an empty
// name, therefore it's safe to use the empty string as a // name, therefore it's safe to use the empty string as a
// property in this object. The API interprets this as "all // property in this object. The API interprets this as "all
// learners, unfiltered". // items, unfiltered".
catchAllFilterValue: '', catchAllFilterValue: '',
className: 'learners-filter', className: 'list-filter',
template: _.template(filterTemplate), template: _.template(filterTemplate),
...@@ -39,13 +39,11 @@ define(function(require) { ...@@ -39,13 +39,11 @@ define(function(require) {
* *
* @param options an options object which must include the following * @param options an options object which must include the following
* key/values: * key/values:
* - collection (LearnersCollection): the learners collection to * - collection: the collection to filter.
* filter. * - filterKey (string): the field to be filtered by on the collection.
* - filterKey (string): the field to be filtered by on the learner
* collection.
* - filterValues (Object): the set of valid values that the * - filterValues (Object): the set of valid values that the
* filterKey can take on, represented as a mapping from * filterKey can take on, represented as a mapping from
* filter values to the number of learners matching the applied * filter values to the number of items matching the applied
* filter. * filter.
* - selectDisplayName (string): a *translated* string that will * - selectDisplayName (string): a *translated* string that will
* appear as the label for this filter. * appear as the label for this filter.
...@@ -65,36 +63,37 @@ define(function(require) { ...@@ -65,36 +63,37 @@ define(function(require) {
// 'displayName' is the user-facing representation of the filter // 'displayName' is the user-facing representation of the filter
// which combines the filter with the number of users belonging to // which combines the filter with the number of users belonging to
// it. // it.
var hideInactive = false, var filterValues,
filterValues,
selectedFilterValue; selectedFilterValue;
filterValues = _.chain(this.options.filterValues) filterValues = _.chain(this.options.filterValues)
.pairs() .pairs()
.map(function(filterPair) { .map(function(filterPair) {
var name = filterPair[0], var name = filterPair[0],
numLearners = filterPair[1]; numResults = filterPair[1];
return { return {
name: name, name: name,
displayName: _.template( displayName: _.template(
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
// Translators: 'name' here refers to the name of the filter, while 'numLearners' refers to the number of learners belonging to that filter. // Translators: 'name' here refers to the name of the filter, while 'numResults' refers to the number of items belonging to that filter.
gettext('<%= name %> (<%= numLearners %>)') gettext('<%= name %> (<%= numResults %>)')
)({ )({
name: name, name: name,
numLearners: Utils.localizeNumber(numLearners, 0) numLearners: Utils.localizeNumber(numResults, 0)
}) })
}; };
}) })
.sortBy('name') .sortBy('name')
.value(); .value();
if (filterValues.length) { if (filterValues.length && this.options.filterInput === 'select') {
filterValues.unshift({ filterValues.unshift({
name: this.catchAllFilterValue, name: this.catchAllFilterValue,
// Translators: "All" refers to viewing all the learners in a course. // Translators: "All" refers to viewing all the learners in a course.
displayName: gettext('All') displayName: gettext('All')
}); });
// FIXME: The following code isn't working correctly. getActiveFilterFields seems to return an object,
// not an array.
// Assumes that you can only filter by one filterKey at a time. // Assumes that you can only filter by one filterKey at a time.
selectedFilterValue = _.chain(filterValues) selectedFilterValue = _.chain(filterValues)
.pluck('name') .pluck('name')
...@@ -103,31 +102,31 @@ define(function(require) { ...@@ -103,31 +102,31 @@ define(function(require) {
.value() || this.catchAllFilterValue; .value() || this.catchAllFilterValue;
_.findWhere(filterValues, {name: selectedFilterValue}).selected = true; _.findWhere(filterValues, {name: selectedFilterValue}).selected = true;
} }
if (this.options.filterKey === 'ignore_segments') {
// Translators: inactive meaning that these learners have not interacted with the course recently.
this.options.selectDisplayName = gettext('Hide Inactive Learners');
}
if ('ignore_segments' in this.options.collection.getActiveFilterFields()) {
hideInactive = true;
}
return { return {
filterKey: this.options.filterKey, filterKey: this.options.filterKey,
filterValues: filterValues, filterValues: filterValues,
hideInactive: hideInactive,
selectDisplayName: this.options.selectDisplayName selectDisplayName: this.options.selectDisplayName
}; };
}, },
onCheckboxFilter: function(event) { onCheckboxFilter: function(event) {
if ($(event.currentTarget).find('input:checkbox:checked').length) { var $inputs = $(event.currentTarget).find('input:checkbox:checked'),
this.collection.setFilterField('ignore_segments', 'inactive'); filterKey = $(event.currentTarget).attr('id').slice(7), // chop off "filter-" prefix
appliedFilters = [],
filterValue = '';
if ($inputs.length) {
_.each($inputs, _.bind(function(input) {
appliedFilters.push($(input).attr('id'));
}, this));
filterValue = appliedFilters.join(',');
this.collection.setFilterField(filterKey, filterValue);
} else { } else {
this.collection.unsetFilterField('ignore_segments'); this.collection.unsetFilterField(filterKey);
} }
this.collection.refresh(); this.collection.refresh();
$('#app-focusable').focus(); $('#app-focusable').focus();
this.options.trackingModel.trigger('segment:track', 'edx.bi.roster.filtered', { this.options.trackingModel.trigger('segment:track', 'edx.bi.list.filtered', {
category: 'inactive' category: filterValue
}); });
}, },
......
/**
* Displays either a paginated table of learners or a message that there are
* no learners to display.
*/
define(function(require) {
'use strict';
var _ = require('underscore'),
Marionette = require('marionette'),
AlertView = require('generic-view/common/views/alert-view'),
LearnerTableView = require('learners/roster/views/table'),
LearnerResultsView;
LearnerResultsView = Marionette.LayoutView.extend({
template: _.template('<div class="roster-main"></div>'),
regions: {
main: '.roster-main'
},
initialize: function(options) {
this.options = options || {};
this.listenTo(this.options.collection, 'sync', this.onLearnerCollectionUpdated);
},
onBeforeShow: function() {
this.onLearnerCollectionUpdated(this.options.collection);
},
onLearnerCollectionUpdated: function(collection) {
if (collection.length && this.options.hasData) {
// Don't re-render the learner table view if one already exists.
if (!(this.getRegion('main').currentView instanceof LearnerTableView)) {
this.showChildView('main', new LearnerTableView({
collection: collection,
courseMetadata: this.options.courseMetadata,
trackingModel: this.options.trackingModel
}));
}
} else {
this.showChildView('main', this.createAlertView(collection));
}
},
createAlertView: function(collection) {
var hasSearch = collection.hasActiveSearch(),
hasActiveFilter = !_.isEmpty(collection.getActiveFilterFields()),
suggestions = [],
noLearnersMessage,
detailedMessage;
if (hasSearch || hasActiveFilter) {
noLearnersMessage = gettext('No learners matched your criteria.');
if (hasSearch) {
suggestions.push(gettext('Try a different search.'));
}
if (hasActiveFilter) {
suggestions.push(gettext('Try clearing the filters.'));
}
} else {
noLearnersMessage = gettext('No learner data is currently available for your course.');
// eslint-disable-next-line max-len
detailedMessage = gettext('No learners are enrolled, or course activity data has not yet been processed. Data is updated every day, so check back regularly for up-to-date metrics.');
}
return new AlertView({
alertType: 'info',
title: noLearnersMessage,
body: detailedMessage,
suggestions: suggestions
});
}
});
return LearnerResultsView;
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment