/**
 * Fetch the form for showing actions at the bottom of the page for the QuestionPool.
 */
function WPCW_showPage_QuestionPool_actionForm()
{
    // Start wrapper for bulk actions
    $formWrapper_end = '<div id="wpcw_tbl_question_pool_bulk_actions">';
    // Error messages - if no questions or tags have been selected.
    $formWrapper_end .= sprintf('<div id="wpcw_bulk_action_message_no_questions" class="wpcw_msg_error">%s</div>', __('Please select <b>at least 1 question</b> before continuing...', 'wp_courseware'));
    $formWrapper_end .= sprintf('<div id="wpcw_bulk_action_message_no_tag_first" class="wpcw_msg_error">%s</div>', __('Please select the <b>first tag</b> before continuing...', 'wp_courseware'));
    $formWrapper_end .= sprintf('<div id="wpcw_bulk_action_message_no_tag_second" class="wpcw_msg_error">%s</div>', __('Please select the <b>second tag</b> before continuing...', 'wp_courseware'));
    // Label - saying these are actions
    $formWrapper_end .= sprintf('<label>%s</label>', __('Action for selected questions?', 'wp_courseware'));
    // Dropdown of actions
    $formWrapper_end .= sprintf(WPCW_forms_createDropdown('wpcw_bulk_action_actions', array('' => __('--- Select action ---', 'wp_courseware'), 'add_tag' => __('Add tag to selected questions', 'wp_courseware'), 'remove_tag' => __('Remove tag from selected questions', 'wp_courseware'), 'replace_tag' => __('Replace all instances of tag', 'wp_courseware')), false, 'wpcw_tbl_question_pool_bulk_actions_chooser', false));
    // #### The starting labels for all 3 actions.
    $formWrapper_end .= sprintf('<label class="wpcw_bulk_action_label wpcw_bulk_action_add_tag">%s:</label>', __('Add Tag', 'wp_courseware'));
    $formWrapper_end .= sprintf('<label class="wpcw_bulk_action_label wpcw_bulk_action_remove_tag">%s:</label>', __('Remove Tag', 'wp_courseware'));
    $formWrapper_end .= sprintf('<label class="wpcw_bulk_action_label wpcw_bulk_action_replace_tag">%s:</label>', __('Replace Tag', 'wp_courseware'));
    // #### All 3 - Selector for Add/Remove/Replace tag - first box
    $formWrapper_end .= WPCW_questions_tags_getTagDropdown(__('Select a tag', 'wp_courseware'), 'wpcw_bulk_action_select_tag_a', WPCW_arrays_getValue($_POST, 'wpcw_bulk_action_select_tag_a'), 'wpcw_bulk_action_select_tag_a wpcw_bulk_action_select_tag wpcw_bulk_action_add_tag wpcw_bulk_action_remove_tag wpcw_bulk_action_replace_tag');
    // ### Just 'Replace Tag' - the second label
    $formWrapper_end .= sprintf('<label class="wpcw_bulk_action_label wpcw_bulk_action_replace_tag">%s:</label>', __('With', 'wp_courseware'));
    // Just 'Replace Tag' - the second dropdown
    $formWrapper_end .= WPCW_questions_tags_getTagDropdown(__('Select a tag', 'wp_courseware'), 'wpcw_bulk_action_select_tag_b', WPCW_arrays_getValue($_POST, 'wpcw_bulk_action_select_tag_b'), 'wpcw_bulk_action_select_tag_b wpcw_bulk_action_select_tag wpcw_bulk_action_replace_tag');
    // Button - submit
    $formWrapper_end .= sprintf('<input type="submit" class="button-primary" value="%s">', __('Update Questions', 'wp_courseware'));
    // End wrapper for bulk actions
    $formWrapper_end .= '</div>';
    return $formWrapper_end;
}
Example #2
0
/**
 * Constructs the inner form to allow the user to choose a template for a
 * unit.
 */
function WPCW_metabox_showTemplateSelectionTool()
{
    printf('<p>%s</p>', __('Here you can choose which template to use for this unit.', 'wp_courseware'));
    // Get a list of all templates
    $theme = wp_get_theme();
    // N.B. No caching, even though core Page Templates has that.
    // Nacin advises:
    // "ultimately, "caching" for page templates is not very helpful"
    // "by default, the themes bucket is non-persistent. also, calling
    //  get_page_templates() no longer requires us to load up all theme
    //  data for all themes so overall, it's much quicker already."
    $postTemplates = array('' => '--- ' . __('Use default template', 'wp_courseware') . ' ---');
    // Get a list of all PHP files in the theme, so that we can check for theme headers.
    // Allow the search to go into 1 level of folders.
    $fileList = (array) $theme->get_files('php', 2);
    foreach ($fileList as $fileName => $fullFilePath) {
        // Progressively check the headers for each file. The header is called 'Unit Template Name'.
        // e.g.
        //
        // Unit Template Name: Your Custom Template
        //
        $headers = get_file_data($fullFilePath, array('unit_template_name' => 'Unit Template Name'));
        // No header found
        if (empty($headers['unit_template_name'])) {
            continue;
        }
        // We got one!
        $postTemplates[$fileName] = $headers['unit_template_name'];
    }
    // Show form with selected template that the user can choose from.
    global $post;
    $selectedTemplate = get_post_meta($post->ID, WPCW_TEMPLATE_META_ID, true);
    echo WPCW_forms_createDropdown('wpcw_units_choose_template_list', $postTemplates, $selectedTemplate);
}
/**
 * Shows a detailed summary of the user's quiz or survey answers.
 */
function WPCW_showPage_UserProgess_quizAnswers_load()
{
    global $wpcwdb, $wpdb;
    $wpdb->show_errors();
    $page = new PageBuilder(false);
    $page->showPageHeader(__('Detailed User Quiz/Survey Results', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
    $userID = WPCW_arrays_getValue($_GET, 'user_id') + 0;
    $unitID = WPCW_arrays_getValue($_GET, 'unit_id') + 0;
    $quizID = WPCW_arrays_getValue($_GET, 'quiz_id') + 0;
    // Create a link back to the detailed user progress, and back to all users.
    printf('<div class="wpcw_button_group">');
    // Link back to all user summary
    printf('<a href="%s" class="button-secondary">%s</a>&nbsp;&nbsp;', admin_url('users.php'), __('&laquo; Return to User Summary', 'wp_courseware'));
    if ($userDetails = get_userdata($userID)) {
        // Link back to user's personal summary
        printf('<a href="%s&user_id=%d" class="button-secondary">%s</a>&nbsp;&nbsp;', admin_url('users.php?page=WPCW_showPage_UserProgess'), $userDetails->ID, sprintf(__('&laquo; Return to <b>%s\'s</b> Progress Report', 'wp_courseware'), $userDetails->display_name));
    }
    // Try to get the full detailed results.
    $results = WPCW_quizzes_getUserResultsForQuiz($userID, $unitID, $quizID);
    // No results, so abort.
    if (!$results) {
        // Close the button wrapper for above early
        printf('</div>');
        // .wpcw_button_group
        $page->showMessage(__('Sorry, but no results could be found.', 'wp_courseware'), true);
        $page->showPageFooter();
        return;
    }
    // Could potentially have an issue where the quiz has been deleted
    // but the data exists.. small chance though.
    $quizDetails = WPCW_quizzes_getQuizDetails($quizID, true, true, $userID);
    // Extra button - return to gradebook
    printf('<a href="%s&course_id=%d" class="button-secondary">%s</a>&nbsp;&nbsp;', admin_url('admin.php?page=WPCW_showPage_GradeBook'), $quizDetails->parent_course_id, __("&laquo; Return to Gradebook", 'wp_courseware'));
    printf('</div>');
    // .wpcw_button_group
    // #### 1 - Handle grades being updated
    $results = WPCW_showPage_UserProgess_quizAnswers_handingGrading($quizDetails, $results, $page, $userID, $unitID);
    // #### 2A - Check if next action for user has been triggered by the admin.
    $results = WPCW_showPage_UserProgess_quizAnswers_whatsNext_savePreferences($quizDetails, $results, $page, $userID, $unitID);
    // #### 2B - Handle telling admin what's next
    WPCW_showPage_UserProgess_quizAnswers_whatsNext($quizDetails, $results, $page, $userID, $unitID);
    //Ê#### 3 - Handle sending emails if something has changed.
    if (isset($results->sendOutEmails) && $results->sendOutEmails) {
        $extraDetail = isset($results->extraEmailDetail) ? $results->extraEmailDetail : '';
        // Only called if the quiz was graded.
        if (isset($results->quiz_has_just_been_graded) && $results->quiz_has_just_been_graded) {
            // Need to call the action anyway, but any functions hanging off this
            // should check if the admin wants users to have notifications or not.
            do_action('wpcw_quiz_graded', $userID, $quizDetails, number_format($results->quiz_grade, 1), $extraDetail);
        }
        $courseDetails = WPCW_courses_getCourseDetails($quizDetails->parent_course_id);
        if ($courseDetails->email_quiz_grade_option == 'send_email') {
            // Message is only if quiz has been graded.
            if (isset($results->quiz_has_just_been_graded) && $results->quiz_has_just_been_graded) {
                $page->showMessage(__('The user has been sent an email with their grade for this course.', 'wp_courseware'));
            }
        }
    }
    // #### - Table 1 - Overview
    printf('<h3>%s</h3>', __('Quiz/Survey Overview', 'wp_courseware'));
    $tbl = new TableBuilder();
    $tbl->attributes = array('id' => 'wpcw_tbl_progress_quiz_info', 'class' => 'widefat wpcw_tbl');
    $tblCol = new TableColumn(false, 'quiz_label');
    $tblCol->cellClass = 'wpcw_tbl_label';
    $tbl->addColumn($tblCol);
    $tblCol = new TableColumn(false, 'quiz_detail');
    $tbl->addColumn($tblCol);
    // These are the base details for the quiz to show.
    $summaryData = array(__('Quiz Title', 'wp_courseware') => $quizDetails->quiz_title, __('Quiz Description', 'wp_courseware') => $quizDetails->quiz_desc, __('Quiz Type', 'wp_courseware') => WPCW_quizzes_getQuizTypeName($quizDetails->quiz_type), __('No. of Questions', 'wp_courseware') => $results->quiz_question_total, __('Completed Date', 'wp_courseware') => __('About', 'wp_courseware') . ' ' . human_time_diff($results->quiz_completed_date_ts) . ' ' . __('ago', 'wp_courseware') . '<br/><small>(' . date('D jS M Y \\a\\t H:i:s', $results->quiz_completed_date_ts) . ')</small>', __('Number of Quiz Attempts', 'wp_courseware') => $results->attempt_count, __('Permitted Quiz Attempts', 'wp_courseware') => -1 == $quizDetails->quiz_attempts_allowed ? __('Unlimited', 'wp_courseware') : $quizDetails->quiz_attempts_allowed);
    // Quiz details relating to score, etc.
    if ('survey' != $quizDetails->quiz_type) {
        $summaryData[__('Pass Mark', 'wp_courseware')] = $quizDetails->quiz_pass_mark . '%';
        // Still got items to grade
        if ($results->quiz_needs_marking > 0) {
            $summaryData[__('No. of Questions to Grade', 'wp_courseware')] = '<span class="wpcw_status_info wpcw_icon_pending">' . $results->quiz_needs_marking . '</span>';
            $summaryData[__('Overall Grade', 'wp_courseware')] = '<span class="wpcw_status_info wpcw_icon_pending">' . __('Awaiting Final Grading', 'wp_courseware') . '</span>';
        } else {
            $summaryData[__('No. of Question to Grade', 'wp_courseware')] = '-';
            // Show if PASSED or FAILED with the overall grade.
            $gradeData = false;
            if ($results->quiz_grade >= $quizDetails->quiz_pass_mark) {
                $gradeData = sprintf('<span class="wpcw_tbl_progress_quiz_overall wpcw_question_yesno_status wpcw_question_yes">%s%% %s</span>', number_format($results->quiz_grade, 1), __('Passed', 'wp_courseware'));
            } else {
                $gradeData = sprintf('<span class="wpcw_tbl_progress_quiz_overall wpcw_question_yesno_status wpcw_question_no">%s%% %s</span>', number_format($results->quiz_grade, 1), __('Failed', 'wp_courseware'));
            }
            $summaryData[__('Overall Grade', 'wp_courseware')] = $gradeData;
        }
    }
    foreach ($summaryData as $label => $data) {
        $tbl->addRow(array('quiz_label' => $label . ':', 'quiz_detail' => $data));
    }
    echo $tbl->toString();
    // ### 4 - Form Code - to allow instructor to send data back to
    printf('<form method="POST" id="wpcw_tbl_progress_quiz_grading_form">');
    printf('<input type="hidden" name="grade_answers_submitted" value="true">');
    // ### 5 - Table 2 - Each Specific Quiz
    $questionNumber = 0;
    if ($results->quiz_data && count($results->quiz_data) > 0) {
        foreach ($results->quiz_data as $questionID => $answer) {
            $data = $answer;
            // Get the question type
            if (isset($quizDetails->questions[$questionID])) {
                // Store as object for easy reference.
                $quObj = $quizDetails->questions[$questionID];
                // Render the question as a table.
                printf('<h3>%s #%d - %s</h3>', __('Question', 'wp_courseware'), ++$questionNumber, $quObj->question_question);
                $tbl = new TableBuilder();
                $tbl->attributes = array('id' => 'wpcw_tbl_progress_quiz_info', 'class' => 'widefat wpcw_tbl wpcw_tbl_progress_quiz_answers_' . $quObj->question_type);
                $tblCol = new TableColumn(false, 'quiz_label');
                $tblCol->cellClass = 'wpcw_tbl_label';
                $tbl->addColumn($tblCol);
                $tblCol = new TableColumn(false, 'quiz_detail');
                $tbl->addColumn($tblCol);
                $theirAnswer = false;
                switch ($quObj->question_type) {
                    case 'truefalse':
                    case 'multi':
                        $theirAnswer = $answer['their_answer'];
                        break;
                        // File Upload - create a download link
                    // File Upload - create a download link
                    case 'upload':
                        $theirAnswer = sprintf('<a href="%s%s" target="_blank" class="button-primary">%s .%s %s (%s)</a>', WP_CONTENT_URL, $answer['their_answer'], __('Open', 'wp_courseware'), pathinfo($answer['their_answer'], PATHINFO_EXTENSION), __('File', 'wp_courseware'), WPCW_files_getFileSize_human($answer['their_answer']));
                        break;
                        // Open Ended - Wrap in span tags, to cap the size of the field, and format new lines.
                    // Open Ended - Wrap in span tags, to cap the size of the field, and format new lines.
                    case 'open':
                        $theirAnswer = '<span class="wpcw_q_answer_open_wrap"><textarea readonly>' . $data['their_answer'] . '</textarea></span>';
                        break;
                }
                // end of $theirAnswer check
                $summaryData = array(__('Type', 'wp_courseware') => array('data' => WPCW_quizzes_getQuestionTypeName($quObj->question_type), 'cssclass' => ''), __('Their Answer', 'wp_courseware') => array('data' => $theirAnswer, 'cssclass' => ''));
                // Just for quizzes - show answers/grade
                if ('survey' != $quizDetails->quiz_type) {
                    switch ($quObj->question_type) {
                        case 'truefalse':
                        case 'multi':
                            // The right answer...
                            $summaryData[__('Correct Answer', 'wp_courseware')] = array('data' => $answer['correct'], 'cssclass' => '');
                            // Did they get it right?
                            $getItRight = sprintf('<span class="wpcw_question_yesno_status wpcw_question_%s">%s</span>', $answer['got_right'], 'yes' == $answer['got_right'] ? __('Yes', 'wp_courseware') : __('No', 'wp_courseware'));
                            $summaryData[__('Did they get it right?', 'wp_courseware')] = array('data' => $getItRight, 'cssclass' => '');
                            break;
                        case 'upload':
                        case 'open':
                            $gradeHTML = false;
                            $theirGrade = WPCW_arrays_getValue($answer, 'their_grade');
                            // Not graded - show select box.
                            if ($theirGrade == 0) {
                                $cssClass = 'wpcw_grade_needs_grading';
                            } else {
                                $cssClass = 'wpcw_grade_already_graded';
                                $gradeHTML = sprintf('<span class="wpcw_grade_view">%d%% <a href="#">(%s)</a></span>', $theirGrade, __('Click to edit', 'wp_courseware'));
                            }
                            // Not graded yet, allow admin to grade the quiz, or change
                            // the grading later if they want to.
                            $gradeHTML .= WPCW_forms_createDropdown('grade_quiz_' . $quObj->question_id, WPCW_quizzes_getPercentageList(__('-- Select a grade --', 'wp_courseware')), $theirGrade, false, 'wpcw_tbl_progress_quiz_answers_grade');
                            $summaryData[__('Their Grade', 'wp_courseware')] = array('data' => $gradeHTML, 'cssclass' => $cssClass);
                            break;
                    }
                }
                // Check of showing the right answer.
                foreach ($summaryData as $label => $data) {
                    $tbl->addRow(array('quiz_label' => $label . ':', 'quiz_detail' => $data['data']), $data['cssclass']);
                }
                echo $tbl->toString();
            }
            // end if (isset($quizDetails->questions[$questionID]))
        }
        // foreach ($results->quiz_data as $questionID => $answer)
    }
    printf('</form>');
    // Shows a bar that pops up, allowing the user to easily save all grades that have changed.
    ?>
	<div id="wpcw_sticky_bar" style="display: none">
		<div id="wpcw_sticky_bar_inner">
			<a href="#" id="wpcw_tbl_progress_quiz_grading_updated" class="button-primary"><?php 
    _e('Save Changes to Grades', 'wp_courseware');
    ?>
</a>
			<span id="wpcw_sticky_bar_status" title="<?php 
    _e('Grades have been changed. Ready to save changes?', 'wp_courseware');
    ?>
"></span>
		</div>
	</div>
	<br/><br/><br/><br/>
	<?php 
    $page->showPageFooter();
}
    /**
     * Generates the form where the trainer can edit the details of the custom message.
     */
    function generate_editForm()
    {
        $html = false;
        // Build the root of each field name, then append a suffix for each field.
        $fieldSuffix = '_' . $this->feedbackMsgDetails->qfeedback_id;
        $fieldPrefix = 'wpcw_qcfm_sgl_';
        $html .= sprintf('<div id="%swrapper%s"><table class="wpcw_quiz_custom_feedback_wrap_single" cellspacing="0"><tbody>', $fieldPrefix, $fieldSuffix);
        // ### 1) - Show the feedback message - summary field.
        $html .= sprintf('<tr class="wpcw_quiz_custom_feedback_hdr">');
        // Label
        $html .= sprintf('<th>%s:<span class="wpcw_inner_hint">%s</span></th>', __('Message Description', 'wp_courseware'), __('(Required) A quick summary for this message. This will not be displayed to students.'));
        $html .= '<td>';
        // Entry field for message summary name
        $html .= sprintf('<input name="%s" type="text" value="%s" class="wpcw_qcfm_sgl_summary" placeholder="%s">', $fieldPrefix . 'summary' . $fieldSuffix, $this->feedbackMsgDetails->qfeedback_summary, __('e.g. Low score on MyTag section', 'wp_courseware'));
        // Error message if incomplete
        $html .= sprintf('<span class="wpcw_quiz_custom_feedback_error">%s</span>', __('Please specify a quick summary for this message.', 'wp_courseware'));
        $html .= '</td>';
        // Toggle field
        //$html .= sprintf('<td class="wpcw_quiz_custom_feedback_toggle">[+]</td>');
        $html .= '</tr>';
        // ### 2) - Show tag selection field
        $html .= sprintf('<tr>');
        // Label
        $html .= sprintf('<th>%s:<span class="wpcw_inner_hint">%s</span></th>', __('Select Question Tag', 'wp_courseware'), __('(Required) Select the tag for which you want to provide feedback.'));
        // Tag selection
        $html .= '<td>';
        // Dropdown for the tags
        $html .= WPCW_questions_tags_getTagDropdown(__('-- Please choose a tag ---', 'wp_courseware'), $fieldPrefix . 'tag' . $fieldSuffix, $this->feedbackMsgDetails->qfeedback_tag_id, 'wpcw_qcfm_sgl_tag', false, false);
        // Error message if incomplete
        $html .= sprintf('<span class="wpcw_quiz_custom_feedback_error">%s</span>', __('Please select a tag for this message.', 'wp_courseware'));
        // Shows the count of how many tags are available for this tag
        // This has not been continued for now, as it's an extremely expensive operation due to the random questions.
        /*
        					if ($this->feedbackMsgDetails->qfeedback_tag_id > 0)
        					{
        						$questionCount = 3;//WPCW_quizzes_getQuestionCountForTag($this->quizID, $this->feedbackMsgDetails->qfeedback_tag_id);
        						
        						// Show count based on how many questions found for this tag.
        						$html .= sprintf('<span class="wpcw_quiz_custom_feedback_question_count"><b>%d %s</b> %s</span>', 
        							$questionCount,
        							_n('question', 'questions', $questionCount, 'wp_courseware'),
        							__('found for this tag in this quiz.', 'wp_courseware')
        						);
        					}
        					
        					// No selected tag, so just hide this.
        					else {
        						$html .= '<span class="wpcw_quiz_custom_feedback_question_count" style="display: none;"></span>';
        					}*/
        $html .= '</td>';
        // Empty toggle field.
        //$html .= sprintf('<td></td>');
        $html .= '</tr>';
        // ### 3) - Show the score level selection
        $html .= sprintf('<tr class="alternate">');
        // Label
        $html .= sprintf('<th>%s:<span class="wpcw_inner_hint">%s</span></th>', __('Select Question Tag', 'wp_courseware'), __('(Required) Select the tag for which you want to provide feedback.'));
        $html .= '<td class="wpcw_quiz_custom_feedback_score">';
        $html .= sprintf('<span class="wpcw_quiz_custom_feedback_score_label_first">%s</span>', __('Display this message to students who score:', 'wp_courseware'));
        // Score condition check
        $html .= '<span class="wpcw_quiz_custom_feedback_score_radio_wrap">';
        $html .= sprintf('<label><input type="radio" name="%s" value="above" %s /> %s</label>', $fieldPrefix . 'score_type' . $fieldSuffix, $this->feedbackMsgDetails->qfeedback_score_type == 'above' ? 'checked="checked"' : false, __('above', 'wp_courseware'));
        $html .= sprintf('<label><input type="radio" name="%s" value="below" %s /> %s</label>', $fieldPrefix . 'score_type' . $fieldSuffix, $this->feedbackMsgDetails->qfeedback_score_type == 'below' ? 'checked="checked"' : false, __('at or below', 'wp_courseware'));
        $html .= '</span>';
        // Score selection
        $html .= WPCW_forms_createDropdown($fieldPrefix . 'score_grade' . $fieldSuffix, WPCW_quizzes_getPercentageList(false), $this->feedbackMsgDetails->qfeedback_score_grade);
        $html .= sprintf('<span class="wpcw_quiz_custom_feedback_score_label_second">%s</span>', __('across all questions for the tag selected above', 'wp_courseware'));
        // Error message if incomplete
        $html .= sprintf('<span class="wpcw_quiz_custom_feedback_error">%s</span>', __('Please select a trigger score for this message.', 'wp_courseware'));
        $html .= '</td>';
        $html .= '</tr>';
        // ### 4) - Show the message form
        $html .= sprintf('<tr>');
        // Label
        $html .= sprintf('<th>%s:<span class="wpcw_inner_hint">%s</span></th>', __('Custom Feedback Message', 'wp_courseware'), __('(Required) Enter the message to display to students when conditions above are met.'), 'test');
        $html .= '<td>';
        // Text area for message
        $html .= sprintf('<textarea name="%s" rows="7" class="wpcw_qcfm_sgl_message">%s</textarea>', $fieldPrefix . 'message' . $fieldSuffix, $this->feedbackMsgDetails->qfeedback_message);
        // Error message if incomplete
        $html .= sprintf('<span class="wpcw_quiz_custom_feedback_error">%s</span>', __('Please enter a helpful feedback message for the trainee.', 'wp_courseware'));
        $html .= '</td>';
        $html .= '</tr>';
        // ### 5) Show the footer with the delete icon
        $html .= sprintf('<tr class="wpcw_quiz_row_footer">
				<td colspan="3" class="wpcw_question_actions">
					<a href="#" class="wpcw_delete_icon" rel="%s">Delete</a>
				</td>
			</tr>', __('Are you sure you wish to delete this custom feedback message?', 'wp_courseware'));
        $html .= '</tbody></table></div>';
        return $html;
    }
/**
 * Generate a course list for resetting the progress for a user.
 * 
 * @param $fieldName String The name to use for the name attribute for this dropdown.
 * @param $courseIDList Array If specified, this is a list of IDs to determine which courses to use in the reset box.
 * @param $blankMessage String the message to show if there are no courses.
 * @param $addBlank String Use this string as the first item in the dropdown.
 * @param $cssID String The CSS ID to use for the select box.
 * @param $cssClass String The CSS class to use for the select box.
 *  
 * @return String The course reset dropdown box.
 */
function WPCW_courses_getCourseResetDropdown($fieldName, $courseIDList = false, $blankMessage, $addBlank, $cssID, $cssClass)
{
    $selectDetails = array('' => $addBlank);
    // Need all courses
    $courseList = WPCW_courses_getCourseList();
    if (!empty($courseList)) {
        $blankCount = 2;
        foreach ($courseList as $courseID => $aCourse) {
            // Filter out unwanted courses.
            if (is_array($courseIDList) && !in_array($courseID, $courseIDList)) {
                continue;
            }
            // Have sentinel of course_ to identify a course.
            $selectDetails['course_' . $courseID] = $aCourse;
            // Now we add the modules for this course
            $moduleList = WPCW_courses_getModuleDetailsList($courseID);
            if (!empty($moduleList)) {
                foreach ($moduleList as $moduleID => $moduleDetails) {
                    // Now we add the units for this course
                    $units = WPCW_units_getListOfUnits($moduleID);
                    if (!empty($units)) {
                        // Only add a module if it has units, to make resetting easier.
                        $selectDetails['module_' . $moduleID] = sprintf('&nbsp;&nbsp;- %s %d: %s', __('Module', 'wp_courseware'), $moduleDetails->module_number, $moduleDetails->module_title);
                        foreach ($units as $unitID => $unitDetails) {
                            $selectDetails['unit_' . $unitID] = sprintf('&nbsp;&nbsp;-- %s %d: %s', __('Unit', 'wp_courseware'), $unitDetails->unit_meta->unit_number, $unitDetails->post_title);
                        }
                    }
                    // end of unit list check
                }
                // end of foreach module
            }
            // end of module list check
            // Add a blank sentinel to space out courses.
            $paddingKey = str_pad(false, $blankCount++, ' ');
            $selectDetails[$paddingKey] = '&nbsp';
        }
    }
    // No courses... show meaningful message to the trainer.
    if (count($selectDetails) == 1) {
        $selectDetails[' '] = $blankMessage;
    }
    // Generate the select box. Use the $cssID as the name of the field too.
    return WPCW_forms_createDropdown($fieldName, $selectDetails, false, $cssID, $cssClass);
}