AnsweredAssumed Answered

jQuery Modal Dialog Box Not Rendering Consistently

Question asked by Daniel Murphy on Feb 3, 2020
Latest reply on Feb 4, 2020 by Daniel Murphy

I have created a modal dialog box for the [institution's Canvas domain]/accounts/ page that provides a UI for selecting reporting options for Canvas API calls. My script can pull and process the data with no problem, but the dialog box does not render consistently on the page. Sometimes it works flawlessly with a gray overlay div behind the dialog. Sometimes the overlay div shows behind some of the page elements without the dialog box. Sometimes the overlay covers the dialog.

 

The user should be able to click the "Canvas API Reports" link that the script inserts below the Settings link. The reports link should open the dialog.

 

The script was written to run in Tampermonkey so the dialog and its form elements are dynamically added to the DOM.

 

The dialog rendered consistently until January of this year.

 

The portion of my code that applies to the dialog is inserted below.

 

 

/ ==UserScript==
// @name         Canvas API Reports UI Test
// @namespace    https://github.com/djm60546/canvas-api-reports
// @version      1.1
// @description  Script for extracting student and instructor performance data using the Canvas API. Generates a .CSV download containing the data. Based on the Access Report Data script by James Jones.
// @author       Dan Murphy, Northwestern University School of Professional Studies (dmurphy@northwestern.edu)
// @match        https://northwestern.test.instructure.com/accounts/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.js
// @require      https://code.jquery.com/jquery-3.4.1.js
// @require      https://code.jquery.com/ui/1.12.1/jquery-ui.js
// @grant        none

// ==/UserScript==

(function() {

    'use strict';

 

    function errorHandler(e) {
        console.log(e.name + ': ' + e.message + 'at ' + e.stack);
        alert('An error occured. See browser console for details.');
        //wrapup();
    }

   
    function dateOptionsDlgResult(result) {
        var dS, hS, dE, hE;
        if (result) {
            controls.rptDateStartTxt = $("#dm_start_date_txt").val();
            controls.rptDateEndTxt = $("#dm_end_date_txt").val();
            dS = Date.parse($("#dm_start_date_txt").val());
            hS = dS.setHours(0,0,0,0);
            controls.rptDateStart = hS;
            dE = Date.parse($("#dm_end_date_txt").val());
            hE = dE.setHours(24,0,0,0);
            controls.rptDateEnd = hE;
            $('#dm_date_range_p').html(controls.rptDateStartTxt + " - " + controls.rptDateEndTxt);
        } else {
            controls.rptDateStart = 0;
            controls.rptDateEnd = 0;
            controls.rptDateStartTxt = '';
            controls.rptDateEndTxt = '';
            $("#dm_rprt_prd_chbx").prop("checked",false);
            $('#dm_date_range_p').html('');
        }
    }

    function showDateOptionsDlg() {
        try {
            if ($('#dm_prtcptn_dts_dialog').length === 0) {
                $('body').append('<div id="dm_prtcptn_dts_dialog"></div>');
                $('#dm_prtcptn_dts_dialog').append('<p style="font-size: 1em">Select range of dates for zero participation.</p>');
                $('#dm_prtcptn_dts_dialog').append('<form id="dm_prtcptn_dts_frm"></div>');
                $('#dm_prtcptn_dts_frm').append('<fieldset id="dm_prtcptn_dts_fldst"></fieldset>');
                $('#dm_prtcptn_dts_fldst').append('<label for="dm_start_date_txt">Start Date:</label>');
                $('#dm_prtcptn_dts_fldst').append('<input type="text" id="dm_start_date_txt" name="dm_start_date_txt">');
                $('#dm_prtcptn_dts_fldst').append('<label for="dm_end_date_txt">End Date:</label>');
                $('#dm_prtcptn_dts_fldst').append('<input type="text" id="dm_end_date_txt" name="dm_end_date_txt">');
                var enableDataPicker = $( function() {
                    $( "#dm_start_date_txt" ).datepicker();
                    $( "#dm_end_date_txt" ).datepicker();
                } );
                $('#dm_prtcptn_dts_dialog').dialog ({
                    'title' : 'Specify Reporting Period',
                    'autoOpen' : false,
                    buttons : {
                        "OK": function () {
                            var dS = Date.parse($("#dm_start_date_txt").val());
                            var dE = Date.parse($( "#dm_end_date_txt").val());
                            if (!(dS instanceof Date) || !(dE instanceof Date)) {
                                alert('Enter valid start and end dates for the reporting period')
                                return false;
                            } else if (dE < dS) {
                                alert('The end date must occur after the start date.');
                                return false;
                            } else {
                                $(this).dialog("close");
                                dateOptionsDlgResult(true);
                            }
                        },
                        "Cancel": function () {
                            $(this).dialog("close");
                            dateOptionsDlgResult(false);
                        }
                    }});
            }
            $('#dm_prtcptn_dts_dialog').dialog('open');
        } catch (e) {
            return false;
            errorHandler(e);
        }
    }

    function enableReportOptionsDlgOK() {
        if (($("#dm_term_slct").val() != 0 || $("#dm_srch_inpt").val() != '') && $("#dm_report_slct").val() != 0) {
            $('#dm_term_slct').closest(".ui-dialog").find("button:contains('OK')").removeAttr('disabled').removeClass( 'ui-state-disabled' );;
        } else {
             $('#dm_term_slct').closest(".ui-dialog").find("button:contains('OK')").prop("disabled", true).addClass("ui-state-disabled");
        }
    }

    function reportOptionsDlg() {
        try {
            if ($('#dm_options_frm').length === 0) {
                // Update this array with new Canvas term IDs and labels as quarters/terms are added
                // Populates the term select menu in the "Select Report Options" dialog box
                var terms = {data:[
                    {val : 0, txt: 'Select a term'},
                    {val : 166, txt: '2020 Summer'},
                    {val : 165, txt: '2020 Spring'},
                    {val : 164, txt: '2020 Winter'},
                    {val : 163, txt: '2019 Fall'},
                    {val : 129, txt: '2019-2020 Academic Year'},
                    {val : 131, txt: '2019-2020 Academic Year'},
                    {val : 128, txt: '2019 Summer'},
                    {val : 127, txt: '2019 Spring'},
                    {val : 124, txt: '2019 Winter'},
                    {val : 126, txt: '2018 Fall'},
                    {val : 125, txt: '2018-2019 Med Academic Year'},
                    {val : 130, txt: '2018-2019 Academic Year'},
                    {val : 123, txt: '2018 Summer'},
                    {val : 122, txt: '2018 Spring'},
                    {val : 121, txt: '2018 Winter'},
                    {val : 120, txt: '2017 Fall'},
                    {val : 118, txt: '2017-2018 Academic Year'},
                    {val : 119, txt: '2017 Summer'},
                    {val : 113, txt: '2017 Spring'},
                    {val : 112, txt: '2017 Winter'},
                    {val : 111, txt: '2016 Fall'},
                    {val : 109, txt: '2016-2017 Academic Year'},
                    {val : 110, txt: '2016 Summer'},
                    {val : 107, txt: '2016 Spring'},
                    {val : 106, txt: '2016 Winter'},
                    {val : 105, txt: '2015 Fall'},
                    {val : 108, txt: '2015-2016 Academic Year'},
                    {val : 103, txt: '2015 Summer'},
                    {val : 93, txt: '2015 Spring'},
                    {val : 96, txt: '2015 Winter'},
                    {val : 92, txt: '2014 Fall'},
                    {val : 104, txt: '2014-2015 Academic Year'},
                    {val : 115, txt: 'Advising Term'},
                    {val : 1, txt: 'Default Term'},
                    {val : 116, txt: 'Demo Term'},
                    {val : 114, txt: 'Prep Site Term'},
                    {val : 117, txt: 'Program Term'}
                ]};
                // Populates the reports select menu in the "Select Report Options" dialog box
                var reports = {data:[
                    {val : '0', txt: 'Select a report type'},
                    {val : 'at-risk', txt: 'At-risk Students'},
                    {val : 'access', txt: 'Course Resource Access'},
                    {val : 'instructor', txt: 'Instructor Presence'},
                    {val : 'participation', txt: 'Zero Participation'},
                ]};
                // Define "Select Report Options" dialog box
                $('body').append('<div id="dm_options_dialog"></div>');
                $('#dm_options_dialog').append('<form id="dm_options_frm"></div>');
                $('#dm_options_frm').append('<fieldset id="dm_options_fldst"></fieldset>');
                $('#dm_options_fldst').append('<select id="dm_term_slct">');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<input type="radio" name="dm_srch_rdo" id="coursename" value="true" checked="checked">');
                $('#dm_options_fldst').append('<label for="coursename"> Course Name</label>');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<input type="radio" name="dm_srch_rdo" id="instructorname" value="false">');
                $('#dm_options_fldst').append('<label for="instructorname"> Instructor Name</label>');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<label for="dm_srch_inpt">Search text:</label>');
                $('#dm_options_fldst').append('<input type="text" id="dm_srch_inpt" name="dm_srch_inpt">');
                $('#dm_options_fldst').append('<hr/>');
                $('#dm_options_fldst').append('<select id="dm_report_slct">');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<input type="radio" name="dm_report_opts" id="single" value="true" checked="checked">');
                $('#dm_options_fldst').append('<label for="single"> Single report (all selected courses)</label>');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<input type="radio" name="dm_report_opts" id="multiple" value="false">');
                $('#dm_options_fldst').append('<label for="multiple"> Multiple reports (individual courses)</label>');
                $('#dm_options_fldst').append('<hr/>');
                $('#dm_options_fldst').append('<input type="checkbox" id="dm_dl_crs_chbx" name="dm_dl_crs_chbx" value="true" checked>');
                $('#dm_options_fldst').append('<label for="dm_dl_crs_chbx"> Online courses only</label>');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<input type="checkbox" id="dm_anon_stdnt_chbx" name="dm_anon_stdnt_chbx" value="true" checked>');
                $('#dm_options_fldst').append('<label for="dm_anon_stdnt_chbx"> Anonymize students</label>');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<input type="checkbox" id="dm_rprt_prd_chbx" name="dm_rprt_prd_chbx" value="true">');
                $('#dm_options_fldst').append('<label for="dm_rprt_prd_chbx"> Specify reporting period</label>');
                $('#dm_options_fldst').append('<br/>');
                $('#dm_options_fldst').append('<span id="dm_date_range_p" style="font-size: 1em; margin-left: 1.75em"></span>');
                $("#dm_term_slct").change(function() {
                    enableReportOptionsDlgOK();
                });
                $("#dm_srch_inpt").change(function() {
                    enableReportOptionsDlgOK();
                });
                $("#dm_report_slct").change(function() {
                    if ($(this).children("option:selected").val() == 'participation')
                    {
                        $("#dm_anon_stdnt_chbx").prop("checked",false);
                        $("#dm_anon_stdnt_chbx").prop("disabled",true);
                        $("#dm_rprt_prd_chbx").prop("checked",true);
                        $("#dm_rprt_prd_chbx").prop("disabled",true);
                        showDateOptionsDlg();
                    }
                    else if ($(this).children("option:selected").val() == 'at-risk' || $(this).children("option:selected").val() == 'instructor')
                    {
                        $("#dm_anon_stdnt_chbx").prop("checked",false);
                        $("#dm_anon_stdnt_chbx").prop("disabled",true);
                         $("#dm_rprt_prd_chbx").prop("disabled",false);
                    }
                    else {
                        controls.rptDateStart = null;
                        controls.rptDateEnd = null;
                        $("#dm_anon_stdnt_chbx").prop("disabled",false);
                        $("#dm_rprt_prd_chbx").prop("disabled",false);
                        $("#dm_rprt_prd_chbx").prop("checked",false);
                        $('#dm_date_range_p').html('');
                    }
                    enableReportOptionsDlgOK();
                });
                $("#dm_rprt_prd_chbx").change(function() {
                    controls.rptDateStart = 0;
                    controls.rptDateEnd = 0;
                    if($(this).is(":checked"))
                    {
                        showDateOptionsDlg();
                    } else {
                        $('#dm_date_range_p').html('');
                    }
                });
                $('#dm_options_dialog').dialog ({
                    'title' : 'Select Report Options',
                    'autoOpen' : false,
                    'modal' : true,
                    'buttons' : {
                        "OK": function () {
                            $(this).dialog("close");
                            var enrllTrmSelct = $("#dm_term_slct option:selected").val();
                            var srchByChecked = $("input[name='dm_srch_rdo']:checked").val();
                            var srchTermsStr = $("#dm_srch_inpt").val();
                            controls.rptType = $('#dm_report_slct').children("option:selected").val();
                            controls.combinedRpt = $("input[name='dm_report_opts']:checked").val()
                            controls.dlCrsOnly = $('#dm_dl_crs_chbx').prop('checked');
                            controls.anonStdnts = $('#dm_anon_stdnt_chbx').prop('checked');
                            setupReports(enrllTrmSelct, srchByChecked, srchTermsStr);
                        },
                        "Cancel": function () {
                            $(this).dialog('close');
                            $('#jj_access_report').one('click', reportOptionsDlg);
                        }
                    }});
                $('.ui-dialog-titlebar-close').remove(); // Remove titlebar close button forcing users to form buttons
                $('#dm_term_slct').closest(".ui-dialog").find("button:contains('OK')").prop("disabled", true).addClass("ui-state-disabled");
                if ($('#dm_term_slct').children('option').length === 0) { // add terms to terms select element
                    $.each(terms.data, function (key, value) {
                        $("#dm_term_slct").append($('<option>', {
                            value: value.val,
                            text: value.txt,
                            'data-mark': value.id
                        }));
                    });
                }
                if ($('#dm_report_slct').children('option').length === 0) { // add report types to reports select element
                    $.each(reports.data, function (key, value) {
                        $("#dm_report_slct").append($('<option>', {
                            value: value.val,
                            text: value.txt,
                            'data-mark': value.id
                        }));
                    });
                }
            }
            //$('#dm_options_dialog').css('z-index', '9000');
            $('#dm_options_dialog').dialog('open');
        } catch (e) {
            errorHandler(e);
        }
    }

    // Add "Canvas API Reports" link below navigation
    function addReportsLink() {
        if ($('#jj_access_report').length === 0) {
            $('#left-side').append('<div class="rs-margin-bottom"><a id="jj_access_report"><span aria-hidden="true" style="color:#f92626; cursor: pointer; display: block; font-size: 1rem; line-height: 20px; margin: 5px auto; padding: 8px 0px 8px 6px;">Custom API Reports</span><span class="screenreader-only">Custom API Reports</span></a></div>');
            $('#jj_access_report').one('click', reportOptionsDlg);
        }
        return;
    }

    $( document ).ready(function() {
        addReportsLink(); // Add reports link to page
    });

}());

Any insights or solutions will be appreciated.

 

Thanks,

 

Dan Murphy

Outcomes