diff --git a/lms/static/coffee/src/instructor_dashboard/analytics.coffee b/lms/static/coffee/src/instructor_dashboard/analytics.coffee index 3229f51899..4656ea528a 100644 --- a/lms/static/coffee/src/instructor_dashboard/analytics.coffee +++ b/lms/static/coffee/src/instructor_dashboard/analytics.coffee @@ -8,10 +8,10 @@ std_ajax_err = -> window.InstructorDashboard.util.std_ajax_err.apply this, argum class ProfileDistributionWidget - constructor: ({@$container, @feature, title, @endpoint}) -> + constructor: ({@$container, @feature, @title, @endpoint}) -> # render template template_params = - title: title + title: @title feature: @feature endpoint: @endpoint template_html = $("#profile-distribution-widget-template").html() diff --git a/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee b/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee index 5bc312a529..5ac99b69b6 100644 --- a/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee +++ b/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee @@ -33,10 +33,13 @@ CSS_INSTRUCTOR_NAV = 'instructor-nav' # prefix for deep-linking HASH_LINK_PREFIX = '#view-' +$active_section = null # helper class for queueing and fault isolation. # Will execute functions marked by waiter.after only after all functions marked by # waiter.waitFor have been called. +# To guarantee this functionality, waitFor and after must be called +# before the functions passed to waitFor are called. class SafeWaiter constructor: -> @after_handlers = [] @@ -87,8 +90,9 @@ setup_instructor_dashboard = (idash_content) => # clickable section titles $links = idash_content.find(".#{CSS_INSTRUCTOR_NAV}").find('a') - for link in ($ link for link in $links) - link.click (e) -> + # attach link click handlers + $links.each (i, link) -> + $(link).click (e) -> e.preventDefault() # deactivate all link & section styles @@ -97,11 +101,11 @@ setup_instructor_dashboard = (idash_content) => # discover section paired to link section_name = $(this).data 'section' - section = idash_content.find "##{section_name}" + $section = idash_content.find "##{section_name}" # activate link & section styling $(this).addClass CSS_ACTIVE_SECTION - section.addClass CSS_ACTIVE_SECTION + $section.addClass CSS_ACTIVE_SECTION # tracking analytics.pageview "instructor_section:#{section_name}" @@ -111,7 +115,12 @@ setup_instructor_dashboard = (idash_content) => location.hash = "#{HASH_LINK_PREFIX}#{section_name}" sections_have_loaded.after -> - section.data('wrapper')?.onClickTitle?() + $section.data('wrapper')?.onClickTitle?() + + # call onExit handler if exiting a section to a different section. + unless $section.is $active_section + $active_section?.data('wrapper')?.onExit?() + $active_section = $section # TODO enable onExit handler @@ -137,15 +146,25 @@ setup_instructor_dashboard = (idash_content) => # enable sections setup_instructor_dashboard_sections = (idash_content) -> - # see fault isolation NOTE at top of file. - # If an error thrown in one section, it will not stop other sections from exectuing. - plantTimeout 0, sections_have_loaded.waitFor -> - new window.InstructorDashboard.sections.CourseInfo idash_content.find ".#{CSS_IDASH_SECTION}#course_info" - plantTimeout 0, sections_have_loaded.waitFor -> - new window.InstructorDashboard.sections.DataDownload idash_content.find ".#{CSS_IDASH_SECTION}#data_download" - plantTimeout 0, sections_have_loaded.waitFor -> - new window.InstructorDashboard.sections.Membership idash_content.find ".#{CSS_IDASH_SECTION}#membership" - plantTimeout 0, sections_have_loaded.waitFor -> - new window.InstructorDashboard.sections.StudentAdmin idash_content.find ".#{CSS_IDASH_SECTION}#student_admin" - plantTimeout 0, sections_have_loaded.waitFor -> - new window.InstructorDashboard.sections.Analytics idash_content.find ".#{CSS_IDASH_SECTION}#analytics" + sections_to_initialize = [ + constructor: window.InstructorDashboard.sections.CourseInfo + $element: idash_content.find ".#{CSS_IDASH_SECTION}#course_info" + , + constructor: window.InstructorDashboard.sections.DataDownload + $element: idash_content.find ".#{CSS_IDASH_SECTION}#data_download" + , + constructor: window.InstructorDashboard.sections.Membership + $element: idash_content.find ".#{CSS_IDASH_SECTION}#membership" + , + constructor: window.InstructorDashboard.sections.StudentAdmin + $element: idash_content.find ".#{CSS_IDASH_SECTION}#student_admin" + , + constructor: window.InstructorDashboard.sections.Analytics + $element: idash_content.find ".#{CSS_IDASH_SECTION}#analytics" + ] + + sections_to_initialize.map ({constructor, $element}) -> + # See fault isolation NOTE at top of file. + # If an error is thrown in one section, it will not stop other sections from exectuing. + plantTimeout 0, sections_have_loaded.waitFor -> + new constructor $element diff --git a/lms/static/coffee/src/instructor_dashboard/student_admin.coffee b/lms/static/coffee/src/instructor_dashboard/student_admin.coffee index 5db030ffa0..7e40eb98d4 100644 --- a/lms/static/coffee/src/instructor_dashboard/student_admin.coffee +++ b/lms/static/coffee/src/instructor_dashboard/student_admin.coffee @@ -6,6 +6,8 @@ plantTimeout = -> window.InstructorDashboard.util.plantTimeout.apply this, arguments plantInterval = -> window.InstructorDashboard.util.plantInterval.apply this, arguments std_ajax_err = -> window.InstructorDashboard.util.std_ajax_err.apply this, arguments +load_IntervalManager = -> window.InstructorDashboard.util.IntervalManager + # wrap window.confirm # display `msg` @@ -102,8 +104,13 @@ class StudentAdmin @$request_response_error_all = @$section.find ".course-specific-container .request-response-error" # start polling for task list + # if the list is in the DOM if @$table_running_tasks.length > 0 - @start_refresh_running_task_poll_loop() + # reload every 20 seconds. + TASK_LIST_POLL_INTERVAL = 20000 + @reload_running_tasks_list() + @task_poller = new (load_IntervalManager()) TASK_LIST_POLL_INTERVAL, => + @reload_running_tasks_list() # attach click handlers @@ -255,7 +262,6 @@ class StudentAdmin create_task_list_table @$table_task_history_all, data.tasks error: std_ajax_err => @$request_response_error_all.text "Error listing task history for this student and problem." - reload_running_tasks_list: => list_endpoint = @$table_running_tasks.data 'endpoint' $.ajax @@ -264,12 +270,6 @@ class StudentAdmin success: (data) => create_task_list_table @$table_running_tasks, data.tasks error: std_ajax_err => console.warn "error listing all instructor tasks" - start_refresh_running_task_poll_loop: -> - @reload_running_tasks_list() - if @$section.hasClass 'active-section' - # poll every 20 seconds - plantTimeout 20000, => @start_refresh_running_task_poll_loop() - # wraps a function, but first clear the error displays clear_errors_then: (cb) -> @$request_response_error_single.empty() @@ -278,14 +278,10 @@ class StudentAdmin cb?.apply this, arguments # handler for when the section title is clicked. - onClickTitle: -> - if @$table_running_tasks.length > 0 - @start_refresh_running_task_poll_loop() + onClickTitle: -> @task_poller?.start() # handler for when the section is closed - # not working yet. - # onExit: -> - # clearInterval @reload_running_task_list_slot + onExit: -> @task_poller?.stop() # export for use diff --git a/lms/static/coffee/src/instructor_dashboard/util.coffee b/lms/static/coffee/src/instructor_dashboard/util.coffee index b22410e8aa..9217da5064 100644 --- a/lms/static/coffee/src/instructor_dashboard/util.coffee +++ b/lms/static/coffee/src/instructor_dashboard/util.coffee @@ -5,6 +5,7 @@ plantTimeout = (ms, cb) -> setTimeout cb, ms plantInterval = (ms, cb) -> setInterval cb, ms + # standard ajax error wrapper # # wraps a `handler` function so that first @@ -16,6 +17,26 @@ std_ajax_err = (handler) -> (jqXHR, textStatus, errorThrown) -> handler.apply this, arguments +# Helper class for managing the execution of interval tasks. +# Handles pausing and restarting. +class IntervalManager + # Create a manager which will call `fn` + # after a call to .start every `ms` milliseconds. + constructor: (@ms, @fn) -> + @intervalID = null + + # Start or restart firing every `ms` milliseconds. + # Soes not fire immediately. + start: -> + if @intervalID is null + @intervalID = setInterval @fn, @ms + + # Pause firing. + stop: -> + clearInterval @intervalID + @intervalID = null + + # export for use # create parent namespaces if they do not already exist. # abort if underscore can not be found. @@ -25,3 +46,4 @@ if _? plantTimeout: plantTimeout plantInterval: plantInterval std_ajax_err: std_ajax_err + IntervalManager: IntervalManager