diff --git a/bases/rsptx/assignment_server_api/routers/student.py b/bases/rsptx/assignment_server_api/routers/student.py index b4160dbbd..76c45c217 100644 --- a/bases/rsptx/assignment_server_api/routers/student.py +++ b/bases/rsptx/assignment_server_api/routers/student.py @@ -201,6 +201,7 @@ def sort_key(assignment): lti1p1=is_lti1p1_course, now=now, visibility_map=visibility_map, + term_start_date=course.term_start_date, settings=settings, base_url=construct_course_url(course), activity_info="{}", @@ -1020,6 +1021,7 @@ async def doAssignment( questions_score=questions_score, readings_score=readings_score, user=user, + term_start_date=course.term_start_date, user_id=user.username, # _base.html for ptx student pages needs user_id base_course=course.base_course, # gradeRecordingUrl=URL('assignments', 'record_grade'), diff --git a/bases/rsptx/interactives/ptxrs-bootstrap.less b/bases/rsptx/interactives/ptxrs-bootstrap.less index b16bbb3b4..34667c40f 100644 --- a/bases/rsptx/interactives/ptxrs-bootstrap.less +++ b/bases/rsptx/interactives/ptxrs-bootstrap.less @@ -23,6 +23,7 @@ border-radius: 5px; height: 20px; position: relative; + margin: 10px auto; } diff --git a/bases/rsptx/interactives/public/index.html b/bases/rsptx/interactives/public/index.html index 8cd23507d..01ddd23c3 100644 --- a/bases/rsptx/interactives/public/index.html +++ b/bases/rsptx/interactives/public/index.html @@ -235,9 +235,11 @@

- You have attempted of - activities on this page -
+
+ You have attempted of + activities on this page. +
+
diff --git a/bases/rsptx/interactives/runestone/common/css/runestone.css b/bases/rsptx/interactives/runestone/common/css/runestone.css index 6f2615d68..f70b55e7b 100644 --- a/bases/rsptx/interactives/runestone/common/css/runestone.css +++ b/bases/rsptx/interactives/runestone/common/css/runestone.css @@ -1432,4 +1432,11 @@ legend { .autopermalink { display: none; +} + + +.course-not-started-warning { + margin-bottom: 20px; + margin-top: 20px; + padding: 15px; } \ No newline at end of file diff --git a/bases/rsptx/interactives/runestone/common/js/bookfuncs.js b/bases/rsptx/interactives/runestone/common/js/bookfuncs.js index fe0c8cf43..9addd2753 100644 --- a/bases/rsptx/interactives/runestone/common/js/bookfuncs.js +++ b/bases/rsptx/interactives/runestone/common/js/bookfuncs.js @@ -348,6 +348,25 @@ export const NON_CONTENT_PAGES = [ "search.html", ]; +export function isCourseStarted() { + let startDate = eBookConfig.termStartDate; // format is "2026-09-22" + if (!startDate) { + return false; + } + let today = new Date(); + let start = new Date(startDate); + return today >= start; +} + +function courseNotStartedMessage() { + const formattedDate = new Date(eBookConfig.termStartDate).toLocaleDateString(undefined, { + year: 'numeric', + month: 'long', + day: 'numeric' + }); + return ("Course has not started yet. Progress will be tracked starting on " + formattedDate); +} + /** True when pathname names one of the NON_CONTENT_PAGES. */ export function isNonContentPage(pathname = window.location.pathname) { let page = pathname.split("/").pop().toLowerCase(); @@ -440,6 +459,11 @@ export class PageProgressBar { } catch (e) { value = 0; } + let progressText = document.getElementById("scprogress-activity-count"); + // Warn if course not started + if(progressText && !isCourseStarted()) { + progressText.appendChild(document.createTextNode(courseNotStartedMessage())); + } // Replace #subchapterprogress div with a native element if not already done let subchapterprogress = document.getElementById("subchapterprogress"); if (subchapterprogress && subchapterprogress.tagName !== "PROGRESS") { @@ -1080,6 +1104,22 @@ async function handlePageSetup() { } } } + + // PTX generated pages may have stale HTML. Forcibly re-render the content + // of the progress container. Any logic that modifies the progress container + // should be done after this point, or it will be overwritten. + const scprogresscontainer = document.getElementById( + "scprogresscontainer", + ); + if (scprogresscontainer) + scprogresscontainer.innerHTML = ` +
+ You have attempted of + activities on this page. +
+
+ `; + console.log(`This page served by ${eBookConfig.served_by}`); if (eBookConfig.isLoggedIn) { mess = `username: ${eBookConfig.username}`; @@ -1094,7 +1134,23 @@ async function handlePageSetup() { } } document.dispatchEvent(new Event("runestone:login")); + addReadingList(); + + // Warn if the course has not started yet + if (!isCourseStarted()) { + const ptxContent = document.getElementById("ptx-content"); + if (ptxContent) { + const warningContainer = document.createElement("div"); + warningContainer.className = "ptx-runestone-container"; + const warningDiv = document.createElement("div"); + warningDiv.className = "course-not-started-warning alert alert-danger"; + warningDiv.textContent = courseNotStartedMessage(); + warningContainer.appendChild(warningDiv); + ptxContent.insertBefore(warningContainer, ptxContent.firstChild); + } + } + // Only show the StudyClues widget for certain base courses and when the path includes "/ns/books/". // This is a temporary measure to limit the widget to courses that are known to work well with it and to avoid showing it on non-book pages where it may not be as useful. if (shouldShowStudyCluesWidget()) { diff --git a/bases/rsptx/interactives/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html b/bases/rsptx/interactives/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html index 3a95ea707..359e153e5 100644 --- a/bases/rsptx/interactives/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html +++ b/bases/rsptx/interactives/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html @@ -400,7 +400,11 @@

Before you keep reading...

{% endif %}
- You have attempted of activities on this page
+
+ You have attempted of + activities on this page. +
+
{% include "subchapter.html" %} diff --git a/bases/rsptx/interactives/runestone/common/test/bookfuncs_progress.test.js b/bases/rsptx/interactives/runestone/common/test/bookfuncs_progress.test.js index 3c0eff6e8..eeb15e0d9 100644 --- a/bases/rsptx/interactives/runestone/common/test/bookfuncs_progress.test.js +++ b/bases/rsptx/interactives/runestone/common/test/bookfuncs_progress.test.js @@ -22,9 +22,11 @@ import { /** The markup a book emits for the progress bar. */ function progressMarkup() { return ` -
You have attempted - of -activities on this page. +
+
+ You have attempted of + activities on this page. +
`; } diff --git a/components/rsptx/templates/admin/instructor/course_settings.html b/components/rsptx/templates/admin/instructor/course_settings.html index db3d5e2c2..bc0c46c05 100644 --- a/components/rsptx/templates/admin/instructor/course_settings.html +++ b/components/rsptx/templates/admin/instructor/course_settings.html @@ -24,7 +24,7 @@

{{ course.course_name }}

-
Set the start date for your course term
+
Set this to the first day students will be able to do work in the course. Student work before this date will not be counted.
diff --git a/components/rsptx/templates/admin/instructor/create_course.html b/components/rsptx/templates/admin/instructor/create_course.html index a6b98d260..868c82ee2 100644 --- a/components/rsptx/templates/admin/instructor/create_course.html +++ b/components/rsptx/templates/admin/instructor/create_course.html @@ -147,7 +147,8 @@

{{ section }}



- + + Set this to the first day students will be able to do work in the course. Student work before this date will not be counted.
Step 6: (Optional !!): Support Runestone Academy
diff --git a/components/rsptx/templates/assignment/student/chooseAssignment.html b/components/rsptx/templates/assignment/student/chooseAssignment.html index d0077c158..574e09016 100644 --- a/components/rsptx/templates/assignment/student/chooseAssignment.html +++ b/components/rsptx/templates/assignment/student/chooseAssignment.html @@ -16,6 +16,11 @@ {% endblock %} {% block content %} + +{% if using_ptx_base != "true" %} + {% include 'common/ebook_config.html' %} +{% endif %} +

Choose Assignment

diff --git a/components/rsptx/templates/common/ebook_config.html b/components/rsptx/templates/common/ebook_config.html index 99cdd9b73..0dc4b5eeb 100644 --- a/components/rsptx/templates/common/ebook_config.html +++ b/components/rsptx/templates/common/ebook_config.html @@ -32,4 +32,5 @@ eBookConfig.authorServerUrl = "{{settings.author_server_url}}"; eBookConfig.websocketUrl = "{{settings.websocket_url}}" eBookConfig.enableDebug = true ? "{{settings.debug}}" == "True" : false; + eBookConfig.termStartDate = "{{ course.term_start_date | default('', true) }}";