johnfhict / AssignmentStatusChanger

// ==UserScript==
// @name     AssignmentStatusChanger
// @include     https://*.instructure.com/courses/*/modules
// @include     https://*.instructure.com/courses/*/assignments/*
// @include     https://*.instructure.com/courses/*/assignments
// @version  1.4.2
// @license GPL-3.0-or-later
// @copyright 2020, Ioannis Kyrousis (https://openuserjs.org/users/johnfhict) and Nearchos Katsanikakis
// @grant    none
// ==/UserScript==

var icons = new RegExp(/🔵⚪️|✅🔵|✅🔴|🔴|🔵|⚪️|✅|🏁|🚷/);

var iconsObj = {
    '🔵': "Waiting for feedback",
    '⚪️': "Can be graded",
    '🔴': "Reviewed",
    '✅': "Graded",
    '🏁': "Graded and processed",
    "🔵⚪️": "Needs feedback and grade",
    "✅🔵": "Graded but needs feedback",
    "✅🔴": "Graded and reviewed",
    '🚷': "Obsolete"
};

var registeredListeners;

/**
This method changes the value of an element by prepending the iconArg (defaults to 🔵if no arg was passed) and replacing with any possible existing icons.
**/
function changeAssignmentStatus(element, iconArg) {
    var icon = iconArg || "🔵";

    element.value = icon + element.value.replace(icons, "");
}

/**
Returns a select HTML element with the different assignment states as options. 
Registers to a param named element to update the name as the selected values change.
**/
function getSelect(element) {
    var selectEl = document.createElement("SELECT");

    selectEl.id = "assignment-status-select";

    var option = document.createElement("option");

    var keys = Object.keys(iconsObj);

    for (var i = 0; i < keys.length; i++) {
        var option = document.createElement("option");
        option.text = [keys[i]] + " " + iconsObj[[keys[i]]];
        option.value = [keys[i]];

        selectEl.add(option);
    }

    selectEl.addEventListener('change', (event) => { changeAssignmentStatus(element, event.target.value); });

    selectEl.addEventListener('click', (event) => { changeAssignmentStatus(element, event.target.value); });

    return selectEl;
}

/**
 This is the initial code run in our plugin. We try to figure out which page we are on by querying for the elements available. If we are on the assignment edit or modules page, we proceed to query for the assignment name input element and attach the assignment changer below.

The assignments page requires a different approach, where we register click handlers for all the edit assignment buttons on the view more on the right of each assignment. When the user clicks and the edit assignment popup window is show, we proceed to run the code again and find the input field to attach the status changer.
**/
function addInitializeSelect() {

    var element = document.getElementById("assignment_name");

    if (!element) {
        element = document.getElementById("content_tag_title");
    }

    if (!element && document.querySelectorAll(".edit_assignment") != null) {
        element = document.querySelectorAll(".ui-dialog input[name=name]");
        if (!registeredListeners) {
            registerListener(".edit_assignment");
            registeredListeners = true;
        }
    }

    if (!element) {
        console.log("Didn't find any element")
        return;
    }

    if (document.querySelectorAll(".edit_item_link") != null && !registeredListeners) {
        registerListener(".edit_item_link");
        registeredListeners = true;
    }

    console.log("element", element)

    if (element.length > 1) {

        for (var i = 0; i < element.length; i++) {
            appendStatusChangerToParent(element[i]);
        }
    } else if (element.length !== 0) {
        appendStatusChangerToParent(element.length === undefined ? element : element[0]);
    }

}

/** Creates a div element with a text and the select of assignment status changer 
And appends it to the element passed in as a parameter.
**/
function appendStatusChangerToParent(element) {
    var span = document.createElement("span");

    span.style.marginRight = "8px";

    span.innerHTML = "Assignment status";

    var div = document.createElement("div");

    div.className = "assignment-status-changer";

    div.style.marginTop = "20px";

    div.appendChild(span);

    div.appendChild(getSelect(element));

    if (!element.parentNode.querySelector(".assignment-status-changer")) {
        element.parentNode.appendChild(div);
    }
}

/** Registers a click listener for all the edit assignment buttons  in the assignments page. 
This happens because the modal window for editing the assignment has not been created when the page loads yet in order for us to attach the assignment changer element. 
**/
function registerListener(selector) {
    var elements = document.querySelectorAll(selector);

    for (var i = 0; i < elements.length; i++) {

        console.log('adding click to', elements[i]);
        elements[i].addEventListener('click', (event) => {

            console.log('click', event.target);

            addInitializeSelect();
        }
        );
    }
}

setTimeout(addInitializeSelect, 2000);