Commit 60855242 by Will Daly

Refactored capa module HTML rendering, isolating logic for

determining which buttons to show
parent 42043d2c
......@@ -136,7 +136,7 @@ class CapaModule(XModule):
self.close_date = self.display_due_date
max_attempts = self.metadata.get('attempts', None)
if max_attempts:
if max_attempts is not None:
self.max_attempts = int(max_attempts)
else:
self.max_attempts = None
......@@ -247,6 +247,78 @@ class CapaModule(XModule):
'progress': Progress.to_js_status_str(self.get_progress())
})
def check_button_name(self):
"""
Determine the name for the "check" button.
Usually it is just "Check", but if this is the student's
final attempt, change the name to "Final Check"
"""
if self.max_attempts is not None:
final_check = (self.attempts >= self.max_attempts - 1)
else:
final_check = False
return "Final Check" if final_check else "Check"
def should_show_check_button(self):
"""
Return True/False to indicate whether to show the "Check" button.
"""
submitted_without_reset = (self.is_completed() and self.rerandomize == "always")
# If the problem is closed (past due / too many attempts)
# then we do NOT show the "check" button
# Also, do not show the "check" button if we're waiting
# for the user to reset a randomized problem
if self.closed() or submitted_without_reset:
return False
else:
return True
def should_show_reset_button(self):
"""
Return True/False to indicate whether to show the "Reset" button.
"""
survey_question = (self.max_attempts == 0)
if self.rerandomize in ["always", "onreset"]:
# If the problem is closed (and not a survey question with max_attempts==0),
# then do NOT show the reset button.
# If the problem hasn't been submitted yet, then do NOT show
# the reset button.
if (self.closed() and not survey_question) or not self.is_completed():
return False
else:
return True
# Only randomized problems need a "reset" button
else:
return False
def should_show_save_button(self):
"""
Return True/False to indicate whether to show the "Save" button.
"""
# If the user has forced the save button to display,
# then show it as long as the problem is not closed
# (past due / too many attempts)
if self.force_save_button == "true":
return not self.closed()
else:
survey_question = (self.max_attempts == 0)
needs_reset = self.is_completed() and self.rerandomize == "always"
# If the problem is closed (and not a survey question with max_attempts==0),
# then do NOT show the reset button
# If we're waiting for the user to reset a randomized problem
# then do NOT show the reset button
if (self.closed() and not survey_question) or needs_reset:
return False
else:
return True
def get_problem_html(self, encapsulate=True):
'''Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.'''
......@@ -313,57 +385,14 @@ class CapaModule(XModule):
'weight': self.descriptor.weight,
}
# We using strings as truthy values, because the terminology of the
# check button is context-specific.
# Put a "Check" button if unlimited attempts or still some left
if self.max_attempts is None or self.attempts < self.max_attempts - 1:
check_button = "Check"
else:
# Will be final check so let user know that
check_button = "Final Check"
reset_button = True
save_button = True
# If we're after deadline, or user has exhausted attempts,
# question is read-only.
if self.closed():
check_button = False
reset_button = False
save_button = False
# If attempts=0 then show just check and reset buttons; this is for survey questions using capa
if self.max_attempts==0:
check_button = False
reset_button = True
save_button = True
# User submitted a problem, and hasn't reset. We don't want
# more submissions.
if self.lcp.done and self.rerandomize == "always":
check_button = False
save_button = False
# Only show the reset button if pressing it will show different values
if self.rerandomize not in ["always", "onreset"]:
reset_button = False
# User hasn't submitted an answer yet -- we don't want resets
if not self.lcp.done:
reset_button = False
# We may not need a "save" button if infinite number of attempts and
# non-randomized. The problem author can force it. It's a bit weird for
# randomization to control this; should perhaps be cleaned up.
if (self.force_save_button == "false") and (self.max_attempts is None and self.rerandomize != "always"):
save_button = False
context = {'problem': content,
'id': self.id,
'check_button': check_button,
'reset_button': reset_button,
'save_button': save_button,
# Pass in the name of the check button or False
# if we do not need a check button
'check_button': self.check_button_name() if self.should_show_check_button() else False,
'reset_button': self.should_show_reset_button(),
'save_button': self.should_show_save_button(),
'answer_available': self.answer_available(),
'ajax_url': self.system.ajax_url,
'attempts_used': self.attempts,
......@@ -731,6 +760,7 @@ class CapaModule(XModule):
# reset random number generator seed (note the self.lcp.get_state()
# in next line)
self.lcp.seed = None
self.lcp = LoncapaProblem(self.definition['data'],
self.location.html_id(), self.lcp.get_state(),
......
......@@ -3,6 +3,7 @@ import json
from mock import Mock, MagicMock, patch
from pprint import pprint
import unittest
import random
import xmodule
import capa
......@@ -618,3 +619,164 @@ class CapaModuleTest(unittest.TestCase):
# Expect that we succeed
self.assertTrue('success' in result and result['success'])
def test_check_button_name(self):
# If last attempt, button name changes to "Final Check"
# Just in case, we also check what happens if we have
# more attempts than allowed.
attempts = random.randint(1, 10)
module = CapaFactory.create(attempts=attempts-1, max_attempts=attempts)
self.assertEqual(module.check_button_name(), "Final Check")
module = CapaFactory.create(attempts=attempts, max_attempts=attempts)
self.assertEqual(module.check_button_name(), "Final Check")
module = CapaFactory.create(attempts=attempts + 1, max_attempts=attempts)
self.assertEqual(module.check_button_name(), "Final Check")
# Otherwise, button name is "Check"
module = CapaFactory.create(attempts=attempts-2, max_attempts=attempts)
self.assertEqual(module.check_button_name(), "Check")
module = CapaFactory.create(attempts=attempts-3, max_attempts=attempts)
self.assertEqual(module.check_button_name(), "Check")
# If no limit on attempts, then always show "Check"
module = CapaFactory.create(attempts=attempts-3)
self.assertEqual(module.check_button_name(), "Check")
module = CapaFactory.create(attempts=0)
self.assertEqual(module.check_button_name(), "Check")
def test_should_show_check_button(self):
attempts = random.randint(1,10)
# If we're after the deadline, do NOT show check button
module = CapaFactory.create(due=self.yesterday_str)
self.assertFalse(module.should_show_check_button())
# If user is out of attempts, do NOT show the check button
module = CapaFactory.create(attempts=attempts, max_attempts=attempts)
self.assertFalse(module.should_show_check_button())
# If survey question (max_attempts = 0), do NOT show the check button
module = CapaFactory.create(max_attempts=0)
self.assertFalse(module.should_show_check_button())
# If user submitted a problem but hasn't reset,
# do NOT show the check button
# Note: we can only reset when rerandomize="always"
module = CapaFactory.create(rerandomize="always")
module.lcp.done = True
self.assertFalse(module.should_show_check_button())
# Otherwise, DO show the check button
module = CapaFactory.create()
self.assertTrue(module.should_show_check_button())
# If the user has submitted the problem
# and we do NOT have a reset button, then we can show the check button
# Setting rerandomize to "never" ensures that the reset button
# is not shown
module = CapaFactory.create(rerandomize="never")
module.lcp.done = True
self.assertTrue(module.should_show_check_button())
def test_should_show_reset_button(self):
attempts = random.randint(1,10)
# If we're after the deadline, do NOT show the reset button
module = CapaFactory.create(due=self.yesterday_str)
module.lcp.done = True
self.assertFalse(module.should_show_reset_button())
# If the user is out of attempts, do NOT show the reset button
module = CapaFactory.create(attempts=attempts, max_attempts=attempts)
module.lcp.done = True
self.assertFalse(module.should_show_reset_button())
# If we're NOT randomizing, then do NOT show the reset button
module = CapaFactory.create(rerandomize="never")
module.lcp.done = True
self.assertFalse(module.should_show_reset_button())
# If the user hasn't submitted an answer yet,
# then do NOT show the reset button
module = CapaFactory.create()
module.lcp.done = False
self.assertFalse(module.should_show_reset_button())
# Otherwise, DO show the reset button
module = CapaFactory.create()
module.lcp.done = True
self.assertTrue(module.should_show_reset_button())
# If survey question for capa (max_attempts = 0),
# DO show the reset button
module = CapaFactory.create(max_attempts=0)
module.lcp.done = True
self.assertTrue(module.should_show_reset_button())
def test_should_show_save_button(self):
attempts = random.randint(1,10)
# If we're after the deadline, do NOT show the save button
module = CapaFactory.create(due=self.yesterday_str)
module.lcp.done = True
self.assertFalse(module.should_show_save_button())
# If the user is out of attempts, do NOT show the save button
module = CapaFactory.create(attempts=attempts, max_attempts=attempts)
module.lcp.done = True
self.assertFalse(module.should_show_save_button())
# If user submitted a problem but hasn't reset, do NOT show the save button
module = CapaFactory.create(rerandomize="always")
module.lcp.done = True
self.assertFalse(module.should_show_save_button())
# Otherwise, DO show the save button
module = CapaFactory.create()
module.lcp.done = False
self.assertTrue(module.should_show_save_button())
# If we're not randomizing, then we can re-save
module = CapaFactory.create(rerandomize="never")
module.lcp.done = True
self.assertTrue(module.should_show_save_button())
# If survey question for capa (max_attempts = 0),
# DO show the save button
module = CapaFactory.create(max_attempts=0)
module.lcp.done = False
self.assertTrue(module.should_show_save_button())
def test_should_show_save_button_force_save_button(self):
# If we're after the deadline, do NOT show the save button
# even though we're forcing a save
module = CapaFactory.create(due=self.yesterday_str,
force_save_button="true")
module.lcp.done = True
self.assertFalse(module.should_show_save_button())
# If the user is out of attempts, do NOT show the save button
attempts = random.randint(1,10)
module = CapaFactory.create(attempts=attempts,
max_attempts=attempts,
force_save_button="true")
module.lcp.done = True
self.assertFalse(module.should_show_save_button())
# Otherwise, if we force the save button,
# then show it even if we would ordinarily
# require a reset first
module = CapaFactory.create(force_save_button="true",
rerandomize="always")
module.lcp.done = True
self.assertTrue(module.should_show_save_button())
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