burningpony/phd_checker

View on GitHub
app/assets/javascripts/phd.js

Summary

Maintainability
F
3 days
Test Coverage
const PHASE_ONE_ID = 1;
const PHASE_TWO_ID = 2;
var TIME_LIMIT_IN_MINUTES = 7;
var INTERVAL_IN_SECONDS_OF_HOW_OFTEN_TO_SHOW_OTHER_STUDENT_ACTIONS = 60; // one minute
var TIMEOUT_FOR_OTHER_PARTICIPANTS = 15 * 1000;
var PHASE_ONE_ROUNDS = 1;
var PHASE_TWO_ROUNDS = 4;
var NUMBER_OF_ROUNDS = PHASE_TWO_ROUNDS;
var PHASE_ID = PHASE_TWO_ID;
var PHASE = App.determinePhase();
if (PHASE === 'phase_one') {
    NUMBER_OF_ROUNDS = PHASE_ONE_ROUNDS;
    PHASE_ID         = PHASE_ONE_ID;
}
window.elapsed_time_in_seconds = 0;
window.participant_id = undefined;
window.group_id = undefined;
window.round_number = 1;
window.total_errors_shown = 0;
window.total_corrections_avaliable = 0;
window.completed_in_time = true;
jQuery(function() {
    if ($(".participant").length > 0) {
        // Setup the back button warning:
        $(window).on("beforeunload", function() {
            return "Hitting the back button will break this experiment, and is disabled, hit cancel";
        });

        $(window).unload(function() {
            $.ajax({
                type: "POST",
                url: "rounds.json",
                data: {
                    user_id: window.user.id,
                    round_number: window.round_number,
                    early_exit: true,
                    controller: window.path_to_controller
                },
                async: false
            });
        });

        console.log("preparing exam");
        // 1) Collect Group and Participant ID
        $(".participant").modal({
            close: false,
            overlayId: "simplemodal-overlay",
            containerId: "simplemodal-container",
            onShow: function(dialog) {
                var modal = this;
                $(".participant").show();
                //accept enter
                $(".participant input").keyup(function(event) {
                    if (event.keyCode == "13") {
                        $(".participant .button").click();
                    }
                });
                // if the user clicks "yes"
                $(".participant input[type=button]").click(function() {
                    // clear error message
                    $(".participant .error").html("");
                    // close the dialog
                    window.participant_id = $(
                        ".participant #participant_id"
                    ).val();
                    window.group_id = $(".participant #group_id").val();
                    if (
                        window.participant_id &&
                        window.group_id &&
                        window.group_id.match(/^\d\d*$/) &&
                        window.participant_id.match(/^\d\d*$/)
                    ) {
                        modal.close();

                        //create user
                        create_user(
                            window.participant_id,
                            window.group_id,
                            window.available_payments,
                            window.job
                        ).success(function() {
                            window.show_instructions();
                        });
                    } else {
                        var error =
                            "You must enter a valid group id and participant id";
                        $(".participant .error").html(error);
                        if (window.console) {
                            window.console.error(error);
                        }
                    }
                });
            }
        });
        window.reset_essay_links = function() {
            $(".essay_link").addClass("hide");
            $(
                '.essay_link[data-round="' + window.round_number + '"]'
            ).removeClass("hide");
        };
        window.get_first_essay = function() {
            $(
                '.essay_link[data-round="' +
                    window.round_number +
                    '"]:first-child'
            ).click();
        };
        // Add instructions
        window.show_instructions = function() {
            var timer_started = false;
            $(".round").html("Round " + window.round_number);
            reset_essay_links();
            $(".round").html("Round " + window.round_number);
            $(".instructions").modal({
                escClose: false,
                close: false,
                overlayClose: false,
                overlayId: "instructions-overlay",
                containerId: "instructions-container",
                onClose: function() {
                    window.start_round(
                        window.round_number,
                        window.user.id,
                        window.option,
                        window.path_to_controller
                    );

                    if (!timer_started) {
                        window.start_timer();
                        timer_started = true;
                        $(".content").show();
                        // click on first essay
                        window.get_first_essay();
                    }
                    this.close();
                },
                onShow: function() {
                    var modal = this;
                    $(".simplemodal-close").click(function() {
                        if (!timer_started) {
                            window.start_timer();
                            timer_started = true;
                            $(".content").show();
                            // click on first essay
                            window.get_first_essay();
                        }
                        modal.close();
                        closed = true;
                    });
                }
            });
        };
        $(".quit").click(function(event) {
            event.stopPropagation();
            $(".confirm_quit").modal({
                close: true,
                overlayClose: true,
                overlayId: "quit-overlay",
                containerId: "quit-container",
                onShow: function() {
                    var modal = this;
                    $(".confirm_quit .quit_button").click(function() {
                        window.stop_timer();
                        modal.close();
                        // let it close the modal, and open a new one
                        setTimeout(function() {
                            window.quit();
                        }, 10);
                    });
                    $(".confirm_quit .cancel_button").click(function() {
                        modal.close();
                    });
                }
            });
            return false;
        });
        window.quit = function(kwargs) {
            // make sure whatever is open is now closed
            $.modal.close();
            if (kwargs && kwargs.timeout) {
                //MAKE IT SO WHEN IT TIMES OUT IT CHECKS WHAT ROUND IT IS ON AND DOES THE RIghT ThinG
                if (window.round_number < NUMBER_OF_ROUNDS) {
                    window.completed_in_time = false;
                    window.stop_timer();
                    var msg = "";
                    msg =
                        "This round has timed out, your next round starts now!";
                    $(".score_card .msg").html(msg);
                    window.score_card_modal();
                } else {
                    window.completed_in_time = false;
                    window.stop_timer();
                    var msg = "";
                    msg = "You ran out of time, but at least it's over :-)";
                    $(".finished .msg").html(msg);
                    // remove unload handler so we can reset things easily
                    window.onbeforeunload = undefined;
                    window.finished_modal();
                }
            } else if (window.round_number < NUMBER_OF_ROUNDS) {
                window.completed_in_time = true;
                window.score_card_modal();
            } else {
                // remove unload handler so we can reset things easily
                window.completed_in_time = true;
                window.onbeforeunload = undefined;
                window.finished_modal();
            }
        };
        window.finished_modal = function finished_modal() {
            // basically 'callLater' something about these dialogs
            setTimeout(function() {
                $(".finished").modal({
                    close: false,
                    overlayClose: false,
                    minHeight: 620,
                    overlayId: "quit-overlay",
                    containerId: "quit-container",
                    onShow: function() {
                        time = window.elapsed_time_in_seconds;
                        $.get(
                            window.path_to_controller + "/score_card",
                            {
                                user_id: window.user.id,
                                round_number: window.round_number,
                                round_time: window.elapsed_time_in_seconds,
                                completed_in_time: window.completed_in_time,
                                round_id: window.round.id,
                                option: window.option
                            },
                            function(data) {
                                $(".finished .body").html(data);
                                time = window.elapsed_time_in_seconds;
                                $.ajax({
                                    type: "POST",
                                    url: "users/complete",
                                    data: {
                                        user_id: window.user.id,
                                        group: window.group_id,
                                        time_to_complete: time
                                    }
                                });
                            }
                        );
                    }
                });
            }, 10);
        };
        window.score_card_modal = function score_card_modal() {
            // basically 'callLater' something about these dialogs
            setTimeout(function() {
                $(".score_card").modal({
                    close: false,
                    overlayClose: false,
                    overlayId: "quit-overlay",
                    containerId: "quit-container",
                    onShow: function() {
                        // Hack to steal the time from the timer.
                        var modal = this;
                        // TODO: k you may need to change the url to the score_card
                        time = window.elapsed_time_in_seconds;
                        $.get(
                            window.path_to_controller + "/score_card",
                            {
                                user_id: window.user.id,
                                round_number: window.round_number,
                                round_time: window.elapsed_time_in_seconds,
                                completed_in_time: window.completed_in_time,
                                round_id: window.round.id,
                                option: window.option
                            },
                            function(data) {
                                $(".score_card .body").html(data);
                            }
                        );
                        $(".done .done_button").click(function() {
                            update_round();
                            modal.close();
                        });
                    }
                });
            }, 10);
        };
        window.show_other_student_actions = function() {
            // stops the timer and shows what other students are up to
            // basically overlays a model dialog and we work from there
            window.stop_timer();
            // make sure whatever is open is now closed
            $.modal.close();
            var closed = false;
            $(".other_participants").modal({
                close: true,
                overlayClose: true,
                overlayId: "quit-overlay",
                containerId: "quit-container",
                onShow: function() {
                    var modal = this;
                    // TODO: Russell you may need to change the url to the stats
                    // Do an ajax request to get the body we are looking for
                    $.get("/users/stats?group=" + window.group_id, function(
                        data
                    ) {
                        $(".other_participants .body").html(data);
                    });
                    $(".other_participants .button").click(function() {
                        modal.close();
                        closed = true;
                        window.start_timer();
                    });
                    setTimeout(function() {
                        if (!closed) {
                            modal.close();
                        }
                    }, TIMEOUT_FOR_OTHER_PARTICIPANTS);
                },
                onClose: function() {
                    this.close();
                    window.start_timer();
                }
            });
        };
        // TODO: don't start the timer until they have finished the practice test
        //TODO: have a way to do the handler
        // add click handlers for all the individual essays
        var cached_essays = {};
        window.essay_loading = false;
        $(".essay_link").click(function(event) {
            event.stopPropagation();
            if (window.essay_loading == false) {
                window.essay_loading = true;
                var essay_number = $(this).attr("data-essay");
                window.problem_set_type = $(this).attr("data-type");
                var essay_round_id =
                    $(this).attr("data-round") +
                    "_" +
                    $(this).attr("data-essay");
                var essay_id = "#o" + window.option + "_e" + essay_round_id;
                $(".essay_link").each(function() {
                    $(this).parents("li").removeClass("active");
                });
                // when clicked give it state of active
                $(this).parents("li").addClass("active");
                // hide all content
                $(".content").hide();
                $(".essay_content").hide();
                if (cached_essays[essay_id]) {
                    $(essay_id).show();
                    $(".content").show();
                    window.essay_id = essay_id;
                    window.essay_loading = false;
                } else {
                    $.ajax({
                        type: "GET",
                        url: "/essay_base/show/" + essay_round_id,
                        data: { option: window.option, phase: PHASE }
                    }).success(function(data) {
                        $(".content").append(data);
                        cached_essays[essay_id] = true;
                        // process the div
                        attach_event_handlers_to_essay(essay_id, essay_number);
                        window.essay_id = essay_id;
                        $(essay_id).show();
                        $(".content").show();
                        window.essay_loading = false;
                    });
                }
            }
        });

        function generate_box(span) {
            var is_quota = span.className.match(/quota/i) != null
                ? true
                : false;
            if (is_quota && window.__show_quota_items) {
                span.className = "correctme unmodified_quota";
            } else {
                span.className = "correctme unmodified";
            }
            var original_text = $(span).html();
            //clear it
            $(span).html("");
            var input = document.createElement("input");
            input.type = "text";
            input.value = original_text;
            input.size = (input.value.length || 1) * 1.2;
            var correct_answer = span.getAttribute("rel");
            input.state = function() {
                /*
                Given a span like:
                <span class='correctme' rel='correct string'>original string</span>

                Tells us whether the string modified by the user is
                - correct
                - modified, but reverted to the original
                - no change (un touched at all by the user)
                - modifies, and returns difference
            */
                var current_value = input.value;
                if (input.modified) {
                    if (current_value == correct_answer) {
                        return {
                            status: "correct",
                            msg: correct_answer,
                            style_class: "state_correct"
                        };
                    } else if (current_value == original_text) {
                        return {
                            status: "incorrect - reverted to original",
                            msg: "modified but returned to normal",
                            style_class: "state_reverted"
                        };
                    } else {
                        // find the differnce between original and difference
                        // using the diffString Algorithm
                        var difference = diffString(
                            original_text,
                            current_value
                        );
                        // modified, return difference
                        return {
                            status: "incorrect - modified",
                            msg: difference,
                            style_class: "state_modified"
                        };
                    }
                } else {
                    return {
                        status: "incorrect - no change",
                        msg: current_value,
                        style_class: "state_no_change"
                    };
                }
            };
            var change_function = function() {
                // remember that the field was modified
                input.modified = true;
                // timeout 10ms so we can read the input value for changes
                setTimeout(function() {
                    if (is_quota && window.__show_quota_items) {
                        span.className = "correctme modified_quota";
                    } else {
                        span.className = "correctme modified";
                    }
                    if (input.value == original_text) {
                        if (is_quota && window.__show_quota_items) {
                            span.className = "correctme unmodified_quota";
                        } else {
                            span.className = "correctme unmodified";
                        }
                    }
                }, 10);
            };
            // handle change events
            input.onkeyup = change_function;
            input.onchange = change_function;
            // Save changes with  window.send_correction
            $(input).change(function() {
                var field_id = span.id;
                var current_value = input.value;
                // correct_answer
                var original_value = original_text;
                var essay = window.essay_id;
                //is_quota
                var round_number = window.round_number;
                window.send_correction(
                    window.group_id,
                    window.participant_id,
                    essay,
                    field_id,
                    original_value,
                    current_value,
                    correct_answer,
                    is_quota,
                    round_number,
                    PHASE_ID
                );
            });
            span.appendChild(input);
        }
        // given an essay ID attach all the correct event handlers

        function attach_event_handlers_to_essay(essay_id, essay_number) {
            errors = 0;
            // generate boxes
            $(essay_id + " span.correctme").each(function() {
                if ($(this).attr("rel") != $(this).text()) {
                    errors++;
                }
                generate_box(this);
            });
            window.total_corrections_avaliable += $(
                essay_id + " span.correctme"
            ).length;
            window.total_errors_shown += errors;
            $(essay_id + " h2").html(
                window.problem_set_type + " " + essay_number
            );
        }
        // timer related functions and variables
        var timer = null;
        var seconds = 0;
        window.start_timer = function() {
            window.stop_timer();
            timer = setInterval(function() {
                var minutes_to_render =
                    TIME_LIMIT_IN_MINUTES - parseInt(seconds / 60) - 1;
                var seconds_to_render = 59 - parseInt(seconds % 60);
                var spacer = "0";
                if (seconds_to_render > 9) {
                    spacer = "";
                }
                // render the seconds
                $(".timer").html(
                    minutes_to_render + ":" + spacer + seconds_to_render
                );
                seconds += 1;
                window.elapsed_time_in_seconds = seconds;
                // show other student scores
                if (
                    seconds %
                        INTERVAL_IN_SECONDS_OF_HOW_OFTEN_TO_SHOW_OTHER_STUDENT_ACTIONS ==
                        0 &&
                    window.__show_other_student_actions
                ) {
                    window.stop_timer();
                    window.show_other_student_actions();
                }
                if (seconds == TIME_LIMIT_IN_MINUTES * 60) {
                    window.stop_timer();
                    window.quit({
                        timeout: true
                    });
                }
            }, 1000);
        };
        window.stop_timer = function() {
            if (timer) {
                clearInterval(timer);
            }
        };
        window.update_round = function update_round() {
            //update round number
            //Send the time to the backend

            window.round_number++;
            window.total_corrections_avaliable = 0;
            window.total_errors_shown = 0;
            $(".round").html("Round " + window.round_number);
            //clear cache
            cached_essays = {};
            $(".content").html("");
            reset_essay_links();
            console.log("Reseting Essays", cached_essays);
            get_first_essay();
            seconds = 0;
            window.elapsed_time_in_seconds = seconds;
            window
                .start_round(
                    window.round_number,
                    window.user.id,
                    window.option,
                    window.path_to_controller
                )
                .success(function() {
                    window.start_timer();
                });
        };
    }
    // Handler for .ready() called.
});