Skip to content

Commit

Permalink
Make course module folding optional and implement automatic scrolling
Browse files Browse the repository at this point in the history
The automatic folding and hiding of expired course modules on the user
results page was suboptimal and annoying for some students/teachers.

Old course modules are no longer hidden behind a button and folding
is made optional with the use of a new "Expand all modules" button.
Automatic scrolling takes the user to the first open module, unless
the page contains previously unseen course news. Automatic scrolling
behavior can be selected using a new button.

Fixes #1125
  • Loading branch information
ihalaij1 committed Jun 30, 2023
1 parent c76e3fb commit bceab6e
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 49 deletions.
102 changes: 102 additions & 0 deletions exercise/static/exercise/user_results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
function startListen() {
if ($(".module-to-collapse").length > 0) {
// Show the "Expand all modules" button if some modules are collapsed
$("#toggle-expand-all-modules").show();
// Check local storage and expand all modules if the variable "expandAllModules" is set to true
const expandAllModules = localStorage.getItem("expandAllModules") === "true";
if (expandAllModules) {
$(".module-panel > div").addClass("in").collapse("show"); // addClass("in") skips the expand animation
$("#toggle-expand-all-modules").find("span").removeClass("glyphicon-unchecked").addClass("glyphicon-check");
}

// Register an event handler to the "Expand all modules" button
$("#toggle-expand-all-modules").on("click", function(event) {
const button = $(this);
const expandAllModules = localStorage.getItem("expandAllModules") === "true";
if (expandAllModules) {
$(".module-panel, .module-to-collapse > div").collapse("hide");
button.find("span").removeClass("glyphicon-check").addClass("glyphicon-unchecked");
localStorage.setItem("expandAllModules", false);
} else {
$(".module-panel > div").collapse("show");
button.find("span").removeClass("glyphicon-unchecked").addClass("glyphicon-check");
localStorage.setItem("expandAllModules", true);
}
});
}

// Check automatic scrolling behavior and show appropriate button
const autoScrollBehavior = localStorage.getItem("autoScrollBehavior");
if (autoScrollBehavior === "instant") {
$("#auto-scroll-behavior-instant").show();
} else if (autoScrollBehavior === "off") {
$("#auto-scroll-behavior-off").show();
} else {
$("#auto-scroll-behavior-smooth").show();
localStorage.setItem("autoScrollBehavior", "smooth"); // Scroll smoothly by default
}

// Register event handlers to all three scroll behavior buttons
$("#cycle-auto-scroll-behavior button").on("click", function(event) {
$(this).hide();
const autoScrollBehavior = localStorage.getItem("autoScrollBehavior");
if (autoScrollBehavior === "instant") {
$("#auto-scroll-behavior-off").show();
localStorage.setItem("autoScrollBehavior", "off");
} else if (autoScrollBehavior === "off") {
$("#auto-scroll-behavior-smooth").show();
localStorage.setItem("autoScrollBehavior", "smooth");
} else {
$("#auto-scroll-behavior-instant").show();
localStorage.setItem("autoScrollBehavior", "instant");
}
});

$('.filter-categories button').on("click", function(event) {
var button = $(this);
var id = button.attr("data-category");
if (button.hasClass("active")) {
button.removeClass("active").find("span").removeClass("glyphicon-unchecked").addClass("glyphicon-check");
$('.module-panel tr[data-category="' + id + '"]').removeClass("hide");
} else {
button.addClass("active").find("span").removeClass("glyphicon-check").addClass("glyphicon-unchecked");
$('.module-panel tr[data-category="' + id + '"]').addClass("hide");
}
$('.module-panel').each(function(index, panel) {
var mod = $(panel);
if (mod.find("tr:not(.hide)").length > 0) {
mod.removeClass("hide");
} else {
mod.addClass("hide");
}
});
});

// Get current course news from the document and previously shown course news from local storage
const news = [];
$(".news-panel > .list-group > .list-group-item > .list-group-item-text").each(function() {
news.push($(this)[0].innerText);
});
const course = "{{course|safe}}";
const allPreviousNews = JSON.parse(localStorage.getItem("courseNews")) || {};
const previousNews = course in allPreviousNews ? allPreviousNews[course] : [];
const currentNews = news.length > 0 ? news : previousNews;
if (news.length > 0) {
const allCurrentNews = { ...allPreviousNews, [course]: currentNews };
localStorage.setItem("courseNews", JSON.stringify(allCurrentNews));
}

function autoScroll() {
const autoScrollBehavior = localStorage.getItem("autoScrollBehavior");
if (autoScrollBehavior !== "off") {
// Scroll to the first open module if there are no new news items
const openModules = $(".module-panel:not(.module-to-collapse)");
if (openModules.length > 0 && JSON.stringify(currentNews) === JSON.stringify(previousNews)) {
const firstHeadingId = openModules[0].querySelector(".panel-heading").id;
document.getElementById(firstHeadingId).scrollIntoView({ behavior: autoScrollBehavior });
}
}
}

setTimeout(autoScroll, 10); // Instant automatic scrolling does not work without a small delay
}
69 changes: 26 additions & 43 deletions exercise/templates/exercise/_user_results.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{% load i18n %}
{% load static %}
{% load course %}
{% load exercise %}

<script src="{% static 'exercise/user_results.js' %}"></script>

{% if categories|len_listed > 1 %}
<p class="filter-categories">
<small>{% translate "FILTER_VIEW" %}:</small>
Expand All @@ -16,22 +19,37 @@
</p>
{% endif %}

<p id="toggle-expired" class="hide">
<button class="aplus-button--secondary aplus-button--xs">
<span class="glyphicon glyphicon-time" aria-hidden="true"></span>
{% translate "SHOW_OLDER_ASSIGNMENTS" %}
<p>
<button id="toggle-expand-all-modules" class="aplus-button--secondary aplus-button--xs" style="display:none">
<span class="glyphicon glyphicon-unchecked" aria-hidden="true"></span>
{% translate "EXPAND_ALL_MODULES" %}
</button>
<span id="cycle-auto-scroll-behavior">
<button id="auto-scroll-behavior-smooth" class="aplus-button--secondary aplus-button--xs" style="display:none">
<span class="glyphicon glyphicon-check" aria-hidden="true"></span>
{% translate "AUTO_SCROLL_BEHAVIOR_SMOOTH" %}
</button>
<button id="auto-scroll-behavior-instant" class="aplus-button--secondary aplus-button--xs" style="display:none">
<span class="glyphicon glyphicon-flash" aria-hidden="true"></span>
{% translate "AUTO_SCROLL_BEHAVIOR_INSTANT" %}
</button>
<button id="auto-scroll-behavior-off" class="aplus-button--secondary aplus-button--xs" style="display:none">
<span class="glyphicon glyphicon-unchecked" aria-hidden="true"></span>
{% translate "AUTO_SCROLL_BEHAVIOR_OFF" %}
</button>
</span>
</p>

{% for module in modules %}
{% if module|is_visible or is_teacher %}
{% with open=module|exercises_open:now after_open=module|has_opened:now %}
{% module_accessible module as accessible %}
{% exercise_accessible module as exercise_accessible %}
<div class="panel panel-primary module-panel{% if not open and after_open %} module-expired{% endif %}">
<div class="panel panel-primary module-panel{% if not accessible or not open and after_open %} module-to-collapse{% endif %}">
<a class="panel-heading{% if not accessible or not open and after_open %} collapsed{% endif %}"
role="button" href="#module{{ module.id }}" data-toggle="collapse"
aria-expanded="{% if accessible and not after_open or open %}true{% else %}false{% endif %}" aria-controls="#module{{ module.id }}">
aria-expanded="{% if accessible and not after_open or open %}true{% else %}false{% endif %}" aria-controls="#module{{ module.id }}"
id="module{{ module.id }}-heading">
<h3 class="panel-title">
{% points_badge module "pull-right" %}
{% if not accessible %}
Expand Down Expand Up @@ -221,41 +239,6 @@ <h3 class="panel-title">
{% endfor %}

<script>
var aplusPointsTotal = {{ total_json|safe }};

$(function() {
var limit = 2;
var expired = $(".module-expired");
if (expired.length > limit) {
expired.slice(0, expired.length - limit).hide();
$("#toggle-expired").removeClass("hide")
.find("button").on("click", function(event) {
event.preventDefault();
$(".module-expired:hidden").show();
$(this).parent().hide();
});
}

$('.filter-categories button').on("click", function(event) {
var button = $(this);
var id = button.attr("data-category");
if (button.hasClass("active")) {
button.removeClass("active")
.find("span").removeClass("glyphicon-unchecked").addClass("glyphicon-check");
$('.module-panel tr[data-category="' + id + '"]').removeClass("hide");
} else {
button.addClass("active")
.find("span").removeClass("glyphicon-check").addClass("glyphicon-unchecked");
$('.module-panel tr[data-category="' + id + '"]').addClass("hide");
}
$('.module-panel').each(function(index, panel) {
var mod = $(panel);
if (mod.find("tr:not(.hide)").length > 0) {
mod.removeClass("hide");
} else {
mod.addClass("hide");
}
});
});
});
var aplusPointsTotal = {{ total_json|safe }};
window.addEventListener("load", startListen, false);
</script>
18 changes: 15 additions & 3 deletions locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-14 14:12+0300\n"
"POT-Creation-Date: 2023-06-30 14:22+0300\n"
"PO-Revision-Date: 2021-05-27 14:47+0300\n"
"Last-Translator: Jimmy Ihalainen <jimmy.ihalainen@aalto.fi>\n"
"Language-Team: English<>\n"
Expand Down Expand Up @@ -4010,8 +4010,20 @@ msgid "FILTER_VIEW"
msgstr "Show"

#: exercise/templates/exercise/_user_results.html
msgid "SHOW_OLDER_ASSIGNMENTS"
msgstr "Show older assignments"
msgid "EXPAND_ALL_MODULES"
msgstr "Expand all modules"

#: exercise/templates/exercise/_user_results.html
msgid "AUTO_SCROLL_BEHAVIOR_SMOOTH"
msgstr "Automatic scrolling: Smooth"

#: exercise/templates/exercise/_user_results.html
msgid "AUTO_SCROLL_BEHAVIOR_INSTANT"
msgstr "Automatic scrolling: Instant"

#: exercise/templates/exercise/_user_results.html
msgid "AUTO_SCROLL_BEHAVIOR_OFF"
msgstr "Automatic scrolling: Off"

#: exercise/templates/exercise/_user_results.html
msgid "OPENS ON"
Expand Down
18 changes: 15 additions & 3 deletions locale/fi/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-14 14:12+0300\n"
"POT-Creation-Date: 2023-06-30 14:22+0300\n"
"PO-Revision-Date: 2019-08-14 12:16+0200\n"
"Last-Translator: Jimmy Ihalainen <jimmy.ihalainen@aalto.fi>\n"
"Language-Team: Finnish <>\n"
Expand Down Expand Up @@ -4020,8 +4020,20 @@ msgid "FILTER_VIEW"
msgstr "Näytä"

#: exercise/templates/exercise/_user_results.html
msgid "SHOW_OLDER_ASSIGNMENTS"
msgstr "Näytä vanhemmat tehtävät"
msgid "EXPAND_ALL_MODULES"
msgstr "Laajenna kaikki moduulit"

#: exercise/templates/exercise/_user_results.html
msgid "AUTO_SCROLL_BEHAVIOR_SMOOTH"
msgstr "Automaattinen vieritys: Pehmeä"

#: exercise/templates/exercise/_user_results.html
msgid "AUTO_SCROLL_BEHAVIOR_INSTANT"
msgstr "Automaattinen vieritys: Nopea"

#: exercise/templates/exercise/_user_results.html
msgid "AUTO_SCROLL_BEHAVIOR_OFF"
msgstr "Automaattinen vieritys: Pois päältä"

#: exercise/templates/exercise/_user_results.html
msgid "OPENS ON"
Expand Down

0 comments on commit bceab6e

Please sign in to comment.