<commit_before><div class="content">

    <script>
        green = getComputedStyle(document.documentElement).getPropertyValue('--date-picker-green');
        yellow = getComputedStyle(document.documentElement).getPropertyValue('--date-picker-yellow');
        red = getComputedStyle(document.documentElement).getPropertyValue('--date-picker-red');
    </script>

    {% if user_group == 1 %}
        <div class="action-buttons" style="float: right; margin-bottom: 20px;">
            {# button to open all of the subfolders and cookie it#}
            <a onclick='setCookie("foldersOpen",openAllDivForCourseMaterials());' class="btn btn-primary key_to_click" tabindex="0">Open/Close All Folders</a>
            {# button to set the release dates of all files in the page/course materials #}
            <a
                    onclick='openSetAllRelease()'
                    class="btn btn-primary key_to_click {% if not materials_exist %}disabled{% endif %}"
                    tabindex="0">Set All Release Dates</a>
            <a onclick="newUploadCourseMaterialsForm()" class="btn btn-primary key_to_click" tabindex="0">Upload Course Materials</a>
        </div>
    {% endif %}
    <h1>Course Materials</h1>
    {% if user_group==1 %}
        <ul style="justify-self: center" id="details-legend" class="table-bordered">
            <li>
                <i class="fas fa-circle grader-NULL"></i>
                Null date
            </li>
            <li>
                <i class="fas fa-circle grader-invalid"></i>
                Never release for at LEAST 10 years
            </li>
            <li>
                <i class="fas fa-circle grader-3"></i>
                Imminent release in at MOST 10 years
            </li>
            <li>
                <i class="fas fa-circle grader-1"></i>
                Released
            </li>
        </ul>
    {% endif %}
    <div class="inner-container" id="file-container">
        {{ _self.display_files(course_materials, links, user_group, user_section, "s", 0, display_file_url, base_course_material_path, directory_priorities, material_list, date_format, folder_ids, seen) }}

    </div>
</div>

{% macro display_files(course_materials, links, user_group, user_section, id, indent, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) %}
    {% for name, course_material in course_materials %}
        {% if course_material is iterable %}
            {{ _self.display_folder(name, course_material, links, user_group, user_section, id ~ "d" ~ loop.index, indent, display_file_url, folder_path ~ "/" ~ name, directory_priorities, material_list, date_format, folder_ids, seen) }}
        {% else %}
            {{ _self.display_file(name, course_material, links, user_group, user_section, id ~ "f" ~ loop.index, indent, display_file_url, date_format, folder_ids, seen) }}
        {% endif %}
    {% endfor %}
{% endmacro %}

{% macro display_file(name, course_material, links, user_group, user_section, id, indent, display_file_url, date_format, folder_ids, seen) %}
    {% if user_group < 4 or ( not course_material.isHiddenFromStudents and (course_material.isSectionAllowed(user_section)) ) %}
        <div class="file-container">
            <div class="file-viewer">
                {% if course_material.isLink %}
                    <i class="fas fa-link" style="vertical-align: text-bottom;"></i>
                    <a href="{{ course_material.getUrl }}" onclick="markViewed([{{ course_material.getId }}])" onauxclick="markViewed([{{ course_material.getId }}])">{{ course_material.getUrlTitle }}</a>
                {% else %}
                    <i class="fas fa-file" style="vertical-align: text-bottom;"></i>
                    {% set extension = name|split('.')|last|lower %}
                    {% if '.' ~ extension in ['.pdf', '.jpg', '.jpeg', '.c', '.cpp', '.s', '.twig', '.py', '.java', '.png', '.txt', '.h', '.html', '.php', '.js', '.sql', '.sh', '.md', '.csv', '.salsa', '.erl', '.oz', '.pl', '.hs', '.gif'] %}
                        <a class="popout-item" target="_blank" href="{{ links[course_material.getId] }}" aria-label="Pop up {{ name }} in a new window" tabindex="0" style="text-decoration: none;">{{ name }} <i class="fas fa-window-restore" title="Pop up the file in a new window"></i></a>
                    {% else %}
                        {{ name }}
                    {% endif %}
                    <a class="key_to_click" onclick='downloadCourseMaterial("{{ course_material.getId }}")' aria-label="Download {{ name }}" tabindex="0"><i class="fas fa-download" title="Download the file"></i></a>
                {% endif %}
                {% if user_group == 1 %}
                    {% if course_material.isLink %}
                        {% set url_title = course_material.getUrlTitle %}
                        {% set url_url = course_material.getUrl %}
                    {% else %}
                        {% set url_title = "" %}
                        {% set url_url = "" %}
                    {% endif %}
                    <a
                        class="key_to_click"
                        tabindex="0"
                        onclick='newEditCourseMaterialsForm(this)'
                        data-id="{{ course_material.getId }}"
                        data-priority="{{ course_material.getPriority }}"
                        data-sections={{course_material.getSections|map(s => s.getSectionId)|json_encode|raw}}
                        data-hidden-state="{{course_material.isHiddenFromStudents}}"
                        data-release-time="{{ course_material.getReleaseDate|date(date_format) }}"
                        data-is-link="{{ course_material.isLink }}" data-link-title="{{ url_title }}"
                        data-link-url="{{ url_url }}"
                    >
                        <i class="fas fa-pencil-alt black-btn" aria-hidden="true" style="font-size: 16px; margin: 5px;"></i>
                    </a>
                    <a class="key_to_click" tabindex="0" onclick='newDeleteCourseMaterialForm("{{ course_material.getId }}", "{{ name }}");' aria-label="Delete {{ name }}"> <i class="fas fa-trash" title="Delete the file" style="font-size: 16px; margin: 5px;"></i></a>
                    <label for="date_to_release_{{ id }}">Share to student on</label>
                    <input name="release_date" id="date_to_release_{{ id }}" class="date_picker" type="text" size="26"  value="{{ course_material.getReleaseDate|date(date_format) }}"/>
                {% if not course_material.getSections|length == 0 %}
                {% if course_material.isHiddenFromStudents %}
                    <span>Sections (Hidden):
                        {{course_material.getSections|sort|map(s => s.getSectionId)|join(',')}}
                        </span>
                {% else %}
                    <span>Sections:
                        {{course_material.getSections|sort|map(s => s.getSectionId)|join(',')}}
                        </span>
                {% endif %}

                {% endif %}

                    <script>
                        function determineRelease(inputID){
                            const now = new Date();

                            function pad(str){
                                return ('0'+str).slice(-2);
                            }

                            const date = now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate());
                            const time = pad(now.getHours())+":"+pad(now.getMinutes())+":"+pad(now.getSeconds());
                            let currentDT = date+' '+time;
                            let neverDT = (now.getFullYear()+10)+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate())+' '+time;

                            //get the value in each file so the color can be assigned
                            //based on the time chosen
                            const inputDT = document.getElementById(inputID);
                            let fileDT = inputDT.value;

                            fileDT = fileDT.replace(/\s/, 'T');
                            currentDT = currentDT.replace(/\s/, 'T');
                            neverDT = neverDT.replace(/\s/, 'T');

                            //also custom colors for this page for readability
                            if(new Date(fileDT).getTime() <= new Date(currentDT).getTime()){
                                return green;
                            } else if(new Date(fileDT).getTime() >= new Date(neverDT).getTime()){
                                return red;
                            } else {
                                return yellow;
                            }
                        }
                        document.getElementById('date_to_release_{{ id }}').style.backgroundColor= determineRelease('date_to_release_{{ id }}');
                    </script>
                {% endif %}
                {% if not seen[course_material.getPath] %}
                    <span class="badge course-material-badge" >NEW</span>
                {% endif %}
            </div>
            <div class="file-viewer-data" id="file_viewer_{{ id }}" style="margin-left:{{ indent * -15 }}px" data-file_name="{{ name }}" data-file_url="{{ course_material.getPath }}"></div>
        </div>
    {% endif %}
{% endmacro %}

{% macro display_folder(name, course_materials, links, user_group, user_section, id, indent, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) %}
    {% if indent == -1 %}
        {{ _self.display_files(course_materials, links, user_group, user_section, id, indent + 1, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) }}
    {% else %}
        <div class="folder-container">
            <div class="div-viewer">
                <a class="openAllDiv key_to_click openAllDivsubmissions openable-element-submissions" id="{{ name }}" onclick="setCookie('{{ folder_path }}',openDivForCourseMaterials('{{ id }}')+'{{ id }}')" tabindex="0">
                    <span  class="fas fa-folder open-all-folder" style="vertical-align: text-top; font-size: 20px"></span>
                    {{ name }}
                </a>
                <a onclick="downloadCourseMaterialZip('{{ folder_ids[folder_path] }}')" aria-label="Download the folder: {{ name }}" class="key_to_click" tabindex="0"><i class="fas fa-download" title="Download the folder"></i></a>
                {% if user_group == 1 %}
                    <a class="key_to_click" tabindex="0" onclick='newEditCourseMaterialsFolderForm(this)' data-id="{{ folder_ids[folder_path] }}" data-priority="{{ directory_priorities[folder_path] }}"> <i class="fas fa-pencil-alt black-btn" aria-hidden="true" style="font-size: 16px; margin: 5px;"></i></a>
                    <a class="key_to_click" tabindex="0" onclick='newDeleteCourseMaterialForm("{{ folder_ids[folder_path]  }}", "{{ name }}");'> <i class="fas fa-trash" aria-hidden="true" style="font-size: 16px; margin: 5px;"></i></a>
                    <a onclick='setFolderRelease("{{ folder_path }}","","{{ id }}","{{ folder_ids[folder_path] }}")' class="btn btn-primary key_to_click" tabindex="0">Set Folder Release Date</a>
                {% endif %}
                {% if not seen[folder_path] %}
                    <span class="badge course-material-badge" >NEW</span>
                {% endif %}
            </div>
            <div id="div_viewer_{{ id }}" style="margin-left: 15px; display: none" data-file_name="{{ name }}">
                {{ _self.display_files(course_materials, links, user_group, user_section, id, indent + 1, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) }}
            </div>
        </div>
    {% endif %}
{% endmacro %}

<script>
    //set cookie for open adapted from w3schools
    function setCookie(cName,cVal){
        document.cookie = cName+'='+cVal;
    }
    //get the value for the cookie with this name
    function getCookie(cName) {
        var name = cName+'=';
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for(var i = 0; i <ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }

    {% if user_group == 1 %}

        function handleHideMaterialsCheckboxChange(clicked) {
            const warningIds = {"hide-materials-checkbox": "upload-form", "hide-materials-checkbox-edit": "edit-form", "hide-folder-materials-checkbox-edit": "edit-folder-form"};
            var callerId = clicked.target ? clicked.target.id : clicked; //can be an event or id itself
            var caller = $('#'+callerId);
            var warningMessage = $('#'+callerId+' ~ #'+warningIds[callerId]+'-hide-warning');
            if (caller.hasClass('partial-checkbox')) {
                caller.removeClass('partial-checkbox');
                caller.siblings()[0].remove();
                if (caller.attr('class') === '') {
                    caller.removeAttr('class');
                }
                caller.prop('checked', true);
            }
            if(caller.is(':checked') && warningMessage.length === 0) {
                var callerParent = caller.parent().get(0);
                callerParent.insertAdjacentHTML(
                    'beforeend',
                    '<span id="'+warningIds[callerId]+`-hide-warning" class="red-message full-width">\nWarning:
                    Students can view the hidden course material by guessing the corresponding
                    course material ID (a simple number). It is recommended to instead use the release date feature
                    if it is necessary to prevent students from accessing course materials.\n</span>`
                );
            }
            else if(caller.is(':not(:checked)')) {
                warningMessage.remove();
            }
        }

    {% endif %}

    window.onload = function () {
        //determine if folders have been left open or closed
        var folderCookie = getCookie('foldersOpen');
        //if the cookie says it is open
        if(folderCookie == "open"){
            //open all the folders
            openAllDivForCourseMaterials();
            //
            {% for file in material_list %}
            //if one of the subdirs, check if it is closed post opening all
            var subFolderCookie = getCookie("{{ file.getPath }}".substr(0,'{{ file.getPath }}'.lastIndexOf("/")));
            if(subFolderCookie.indexOf("closed")==0){
                //if closed. close it after it has been opened by the override above
                closeDivForCourseMaterials(subFolderCookie.substr(6,subFolderCookie.length));
            }
            {% endfor %}
        }
        else{
            //makes sure that opened folders don't get opened multiple times
            let trackOpens = new Map();
            //goes through all possible directories
            {% for file in material_list %}
            //get the cookie for each dir
            var subFolderCookie = getCookie("{{ file.getPath }}".substr(0,'{{ file.getPath }}'.lastIndexOf("/")));
            //if the folder is open
            if(subFolderCookie.indexOf("open")==0){
                //check if the folder has been opened already (do it it again will close it)
                if(trackOpens.get(subFolderCookie.substr(4,subFolderCookie.length)) === undefined){
                    //undefined means it has not been opened
                    //set the value as open so it will not be reopened
                    trackOpens.set(subFolderCookie.substr(4,subFolderCookie.length),"released");
                    //open the folder
                    openDivForCourseMaterials(subFolderCookie.substr(4,subFolderCookie.length));
                }
            }
            else{
                if(subFolderCookie.indexOf("closed")==0){
                    //if the folder should be closed, close it
                    closeDivForCourseMaterials(subFolderCookie.substr(6,subFolderCookie.length));
                    //there's no way to open it in that function
                }
            }
            {% endfor %}
        }
        // loop thru each div_viewer_xxx
        var jumpToScrollPosition = document.cookie.replace(/(?:(?:^|.*;\s*)jumpToScrollPosition\s*\=\s*([^;]*).*$)|^.*$/, "$1");
        {% if user_group == 1 %}
            var topFolderMatcher = new RegExp('^div_viewer_sd[0-9]{0,}$');
            const partiallyHidden = 2;

            // accepts an element (editButton) having required data attributes; other parameters represent the properties known to be common until now
            // returns an updated set of common props by comparing with the props of the given element
            function folderCommonProps(editButton, commonSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch) {
                let residualSections = [];
                if (first) {
                    commonSections = editButton.data('sections');
                    releaseTime = editButton.data('release-time');
                    hiddenState = editButton.data('hidden-state');
                    first = false;
                }
                else {
                    let combinedSections = [...(new Set([...commonSections, ...editButton.data('sections')]))];
                    commonSections = commonSections.filter(x => {return editButton.data('sections').includes(x);});
                    residualSections = combinedSections.filter(x => {return !commonSections.includes(x);});
                    if (!releaseTimeMismatch) {
                        if (editButton.data('release-time') !== releaseTime) {
                            releaseTimeMismatch = true;
                            releaseTime = '';
                        }
                    }
                    if (!hiddenStateMismatch) {
                        if (editButton.data('hidden-state') !== hiddenState) {
                            hiddenStateMismatch = true;
                            hiddenState = '';
                        }
                    }
                }
                return [commonSections, residualSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch];
            }

            // sets the common properties of a given folder
            function folderSetter(elem) {
                let insideFileMatcher = new RegExp(`^${elem.attr("id").replace("div", "file")}f[0-9]{0,}$`);
                let insideFolderMatcher = new RegExp(`^${elem.attr("id")}d[0-9]{0,}$`);
                let first = true;
                let commonSections = [];
                let residualSections = [];
                let partialSections = [];
                let releaseTime = "";
                let hiddenState = '';
                let hiddenStateMismatch = false;
                let releaseTimeMismatch = false;
                $(`.folder-container > [id^=${elem.attr("id")}d]`, elem).each(function() {
                    if (insideFolderMatcher.test($(this).attr('id'))) {
                        folderSetter($(this));
                        let fEditButton = $(this).siblings('.div-viewer').children('a[onclick^=newEditCourseMaterialsFolderForm]');
                        partialSections.push(...fEditButton.data('partial-sections'));
                        [commonSections, residualSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch] = folderCommonProps(fEditButton, commonSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch);
                        partialSections.push(...residualSections);
                    }
                });
                $(`.file-container > .file-viewer > a[onclick^=newEditCourseMaterialsForm]`, elem).each(function() {
                    if (insideFileMatcher.test($(this).parent('.file-viewer').siblings('.file-viewer-data').attr('id'))) {
                        [commonSections, residualSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch] = folderCommonProps($(this), commonSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch);
                        partialSections.push(...residualSections);
                    }
                });
                let editButton = $(elem.siblings('.div-viewer').children('a[onclick^=newEditCourseMaterialsFolderForm]'));
                editButton.attr('data-sections', JSON.stringify(commonSections));
                editButton.attr('data-partial-sections', JSON.stringify(partialSections));
                editButton.attr('data-release-time', releaseTime);
                if (hiddenStateMismatch) {
                    hiddenState = partiallyHidden;
                }
                editButton.attr('data-hidden-state', hiddenState);
            }

            function callFolderSetter(elem) {
                if (topFolderMatcher.test(elem.id)) {
                    folderSetter($(elem));
                }
            }
        {% endif %}
        if (jumpToScrollPosition.length > 0 && jumpToScrollPosition != '-1') {

            $('[id^=div_viewer_]').each(function() {
                {% if user_group == 1 %}
                    callFolderSetter(this);
                {% endif %}
                var number = this.id.replace('div_viewer_', '').trim();
                var keyValuePairs = document.cookie.split(';');

                for(var i = 0; i < keyValuePairs.length; i++) {
                    var name = keyValuePairs[i].substring(0, keyValuePairs[i].indexOf('=')).trim();
                    var value = keyValuePairs[i].substring(keyValuePairs[i].indexOf('=')+1);
                    if (name === 'cm_'+number && value === '1') {
                        openDivForCourseMaterials(number);
                        document.cookie = 'cm_' + number + '='; // clean up cookie since we don't need this anymore
                    }
                }
            });
            // jump to last location if scroll is enabled.
            window.scrollTo(0, jumpToScrollPosition);
            document.cookie = 'jumpToScrollPosition=-1';

        }
        else {
            // clean up all cookies which are stated with "cm_";
            $('[id^=div_viewer_]').each(function() {
                {% if user_group == 1 %}
                    callFolderSetter(this);
                {% endif %}
                var number = this.id.replace('div_viewer_', '').trim();
                var keyValuePairs = document.cookie.split(';');

                for(var i = 0; i < keyValuePairs.length; i++) {
                    var name = keyValuePairs[i].substring(0, keyValuePairs[i].indexOf('=')).trim();
                    if (name === 'cm_'+number) {
                        document.cookie = 'cm_' + number + '=';
                    }
                }
            });
        }
        {% if user_group == 1 %}

            $('#hide-materials-checkbox').on('change', handleHideMaterialsCheckboxChange);
            $('#hide-materials-checkbox-edit').on('change', handleHideMaterialsCheckboxChange);
            $('[id^="section-folder-edit"]').on('change', function() {
                if ($(this).hasClass('partial-checkbox')) {
                    $(this).removeClass('partial-checkbox');
                    if ($(this).attr('class') === '') {
                        $(this).removeAttr('class');
                    }
                    $(this).prop('checked', true);
                }
            })

        {% endif %}
    };

</script>


{% include('course/SetFolderReleaseForm.twig') %}
{% include 'course/UploadCourseMaterialsForm.twig' with {reg_sections: reg_sections} %}
{% include 'course/EditCourseMaterialsForm.twig' %}
{% include 'course/EditCourseMaterialsFolderForm.twig' %}
{% include('course/DeleteCourseMaterialForm.twig') %}
{% include('course/SetAllReleaseForm.twig') %}
<commit_msg>[Bugfix:CourseMaterials] Open/Close All Folders for Students (#8425)<commit_after><div class="content">

    <script>
        green = getComputedStyle(document.documentElement).getPropertyValue('--date-picker-green');
        yellow = getComputedStyle(document.documentElement).getPropertyValue('--date-picker-yellow');
        red = getComputedStyle(document.documentElement).getPropertyValue('--date-picker-red');
    </script>

    <div class="action-buttons" style="float: right; margin-bottom: 20px;">
        {# button to open all of the subfolders and cookie it#}            
        <a onclick='setCookie("foldersOpen",openAllDivForCourseMaterials());' class="btn btn-primary key_to_click" tabindex="0">Open/Close All Folders</a>
        {% if user_group == 1 %}
            {# button to set the release dates of all files in the page/course materials #}
            <a
                    onclick='openSetAllRelease()'
                    class="btn btn-primary key_to_click {% if not materials_exist %}disabled{% endif %}"
                    tabindex="0">Set All Release Dates</a>
            <a onclick="newUploadCourseMaterialsForm()" class="btn btn-primary key_to_click" tabindex="0">Upload Course Materials</a>
        {% endif %}
    </div>
    <h1>Course Materials</h1>
    {% if user_group==1 %}
        <ul style="justify-self: center" id="details-legend" class="table-bordered">
            <li>
                <i class="fas fa-circle grader-NULL"></i>
                Null date
            </li>
            <li>
                <i class="fas fa-circle grader-invalid"></i>
                Never release for at LEAST 10 years
            </li>
            <li>
                <i class="fas fa-circle grader-3"></i>
                Imminent release in at MOST 10 years
            </li>
            <li>
                <i class="fas fa-circle grader-1"></i>
                Released
            </li>
        </ul>
    {% endif %}
    <div class="inner-container" id="file-container">
        {{ _self.display_files(course_materials, links, user_group, user_section, "s", 0, display_file_url, base_course_material_path, directory_priorities, material_list, date_format, folder_ids, seen) }}

    </div>
</div>

{% macro display_files(course_materials, links, user_group, user_section, id, indent, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) %}
    {% for name, course_material in course_materials %}
        {% if course_material is iterable %}
            {{ _self.display_folder(name, course_material, links, user_group, user_section, id ~ "d" ~ loop.index, indent, display_file_url, folder_path ~ "/" ~ name, directory_priorities, material_list, date_format, folder_ids, seen) }}
        {% else %}
            {{ _self.display_file(name, course_material, links, user_group, user_section, id ~ "f" ~ loop.index, indent, display_file_url, date_format, folder_ids, seen) }}
        {% endif %}
    {% endfor %}
{% endmacro %}

{% macro display_file(name, course_material, links, user_group, user_section, id, indent, display_file_url, date_format, folder_ids, seen) %}
    {% if user_group < 4 or ( not course_material.isHiddenFromStudents and (course_material.isSectionAllowed(user_section)) ) %}
        <div class="file-container">
            <div class="file-viewer">
                {% if course_material.isLink %}
                    <i class="fas fa-link" style="vertical-align: text-bottom;"></i>
                    <a href="{{ course_material.getUrl }}" onclick="markViewed([{{ course_material.getId }}])" onauxclick="markViewed([{{ course_material.getId }}])">{{ course_material.getUrlTitle }}</a>
                {% else %}
                    <i class="fas fa-file" style="vertical-align: text-bottom;"></i>
                    {% set extension = name|split('.')|last|lower %}
                    {% if '.' ~ extension in ['.pdf', '.jpg', '.jpeg', '.c', '.cpp', '.s', '.twig', '.py', '.java', '.png', '.txt', '.h', '.html', '.php', '.js', '.sql', '.sh', '.md', '.csv', '.salsa', '.erl', '.oz', '.pl', '.hs', '.gif'] %}
                        <a class="popout-item" target="_blank" href="{{ links[course_material.getId] }}" aria-label="Pop up {{ name }} in a new window" tabindex="0" style="text-decoration: none;">{{ name }} <i class="fas fa-window-restore" title="Pop up the file in a new window"></i></a>
                    {% else %}
                        {{ name }}
                    {% endif %}
                    <a class="key_to_click" onclick='downloadCourseMaterial("{{ course_material.getId }}")' aria-label="Download {{ name }}" tabindex="0"><i class="fas fa-download" title="Download the file"></i></a>
                {% endif %}
                {% if user_group == 1 %}
                    {% if course_material.isLink %}
                        {% set url_title = course_material.getUrlTitle %}
                        {% set url_url = course_material.getUrl %}
                    {% else %}
                        {% set url_title = "" %}
                        {% set url_url = "" %}
                    {% endif %}
                    <a
                        class="key_to_click"
                        tabindex="0"
                        onclick='newEditCourseMaterialsForm(this)'
                        data-id="{{ course_material.getId }}"
                        data-priority="{{ course_material.getPriority }}"
                        data-sections={{course_material.getSections|map(s => s.getSectionId)|json_encode|raw}}
                        data-hidden-state="{{course_material.isHiddenFromStudents}}"
                        data-release-time="{{ course_material.getReleaseDate|date(date_format) }}"
                        data-is-link="{{ course_material.isLink }}" data-link-title="{{ url_title }}"
                        data-link-url="{{ url_url }}"
                    >
                        <i class="fas fa-pencil-alt black-btn" aria-hidden="true" style="font-size: 16px; margin: 5px;"></i>
                    </a>
                    <a class="key_to_click" tabindex="0" onclick='newDeleteCourseMaterialForm("{{ course_material.getId }}", "{{ name }}");' aria-label="Delete {{ name }}"> <i class="fas fa-trash" title="Delete the file" style="font-size: 16px; margin: 5px;"></i></a>
                    <label for="date_to_release_{{ id }}">Share to student on</label>
                    <input name="release_date" id="date_to_release_{{ id }}" class="date_picker" type="text" size="26"  value="{{ course_material.getReleaseDate|date(date_format) }}"/>
                {% if not course_material.getSections|length == 0 %}
                {% if course_material.isHiddenFromStudents %}
                    <span>Sections (Hidden):
                        {{course_material.getSections|sort|map(s => s.getSectionId)|join(',')}}
                        </span>
                {% else %}
                    <span>Sections:
                        {{course_material.getSections|sort|map(s => s.getSectionId)|join(',')}}
                        </span>
                {% endif %}

                {% endif %}

                    <script>
                        function determineRelease(inputID){
                            const now = new Date();

                            function pad(str){
                                return ('0'+str).slice(-2);
                            }

                            const date = now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate());
                            const time = pad(now.getHours())+":"+pad(now.getMinutes())+":"+pad(now.getSeconds());
                            let currentDT = date+' '+time;
                            let neverDT = (now.getFullYear()+10)+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate())+' '+time;

                            //get the value in each file so the color can be assigned
                            //based on the time chosen
                            const inputDT = document.getElementById(inputID);
                            let fileDT = inputDT.value;

                            fileDT = fileDT.replace(/\s/, 'T');
                            currentDT = currentDT.replace(/\s/, 'T');
                            neverDT = neverDT.replace(/\s/, 'T');

                            //also custom colors for this page for readability
                            if(new Date(fileDT).getTime() <= new Date(currentDT).getTime()){
                                return green;
                            } else if(new Date(fileDT).getTime() >= new Date(neverDT).getTime()){
                                return red;
                            } else {
                                return yellow;
                            }
                        }
                        document.getElementById('date_to_release_{{ id }}').style.backgroundColor= determineRelease('date_to_release_{{ id }}');
                    </script>
                {% endif %}
                {% if not seen[course_material.getPath] %}
                    <span class="badge course-material-badge" >NEW</span>
                {% endif %}
            </div>
            <div class="file-viewer-data" id="file_viewer_{{ id }}" style="margin-left:{{ indent * -15 }}px" data-file_name="{{ name }}" data-file_url="{{ course_material.getPath }}"></div>
        </div>
    {% endif %}
{% endmacro %}

{% macro display_folder(name, course_materials, links, user_group, user_section, id, indent, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) %}
    {% if indent == -1 %}
        {{ _self.display_files(course_materials, links, user_group, user_section, id, indent + 1, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) }}
    {% else %}
        <div class="folder-container">
            <div class="div-viewer">
                <a class="openAllDiv key_to_click openAllDivsubmissions openable-element-submissions" id="{{ name }}" onclick="setCookie('{{ folder_path }}',openDivForCourseMaterials('{{ id }}')+'{{ id }}')" tabindex="0">
                    <span  class="fas fa-folder open-all-folder" style="vertical-align: text-top; font-size: 20px"></span>
                    {{ name }}
                </a>
                <a onclick="downloadCourseMaterialZip('{{ folder_ids[folder_path] }}')" aria-label="Download the folder: {{ name }}" class="key_to_click" tabindex="0"><i class="fas fa-download" title="Download the folder"></i></a>
                {% if user_group == 1 %}
                    <a class="key_to_click" tabindex="0" onclick='newEditCourseMaterialsFolderForm(this)' data-id="{{ folder_ids[folder_path] }}" data-priority="{{ directory_priorities[folder_path] }}"> <i class="fas fa-pencil-alt black-btn" aria-hidden="true" style="font-size: 16px; margin: 5px;"></i></a>
                    <a class="key_to_click" tabindex="0" onclick='newDeleteCourseMaterialForm("{{ folder_ids[folder_path]  }}", "{{ name }}");'> <i class="fas fa-trash" aria-hidden="true" style="font-size: 16px; margin: 5px;"></i></a>
                    <a onclick='setFolderRelease("{{ folder_path }}","","{{ id }}","{{ folder_ids[folder_path] }}")' class="btn btn-primary key_to_click" tabindex="0">Set Folder Release Date</a>
                {% endif %}
                {% if not seen[folder_path] %}
                    <span class="badge course-material-badge" >NEW</span>
                {% endif %}
            </div>
            <div id="div_viewer_{{ id }}" style="margin-left: 15px; display: none" data-file_name="{{ name }}">
                {{ _self.display_files(course_materials, links, user_group, user_section, id, indent + 1, display_file_url, folder_path, directory_priorities, material_list, date_format, folder_ids, seen) }}
            </div>
        </div>
    {% endif %}
{% endmacro %}

<script>
    //set cookie for open adapted from w3schools
    function setCookie(cName,cVal){
        document.cookie = cName+'='+cVal;
    }
    //get the value for the cookie with this name
    function getCookie(cName) {
        var name = cName+'=';
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for(var i = 0; i <ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }

    {% if user_group == 1 %}

        function handleHideMaterialsCheckboxChange(clicked) {
            const warningIds = {"hide-materials-checkbox": "upload-form", "hide-materials-checkbox-edit": "edit-form", "hide-folder-materials-checkbox-edit": "edit-folder-form"};
            var callerId = clicked.target ? clicked.target.id : clicked; //can be an event or id itself
            var caller = $('#'+callerId);
            var warningMessage = $('#'+callerId+' ~ #'+warningIds[callerId]+'-hide-warning');
            if (caller.hasClass('partial-checkbox')) {
                caller.removeClass('partial-checkbox');
                caller.siblings()[0].remove();
                if (caller.attr('class') === '') {
                    caller.removeAttr('class');
                }
                caller.prop('checked', true);
            }
            if(caller.is(':checked') && warningMessage.length === 0) {
                var callerParent = caller.parent().get(0);
                callerParent.insertAdjacentHTML(
                    'beforeend',
                    '<span id="'+warningIds[callerId]+`-hide-warning" class="red-message full-width">\nWarning:
                    Students can view the hidden course material by guessing the corresponding
                    course material ID (a simple number). It is recommended to instead use the release date feature
                    if it is necessary to prevent students from accessing course materials.\n</span>`
                );
            }
            else if(caller.is(':not(:checked)')) {
                warningMessage.remove();
            }
        }

    {% endif %}

    window.onload = function () {
        //determine if folders have been left open or closed
        var folderCookie = getCookie('foldersOpen');
        //if the cookie says it is open
        if(folderCookie == "open"){
            //open all the folders
            openAllDivForCourseMaterials();
            //
            {% for file in material_list %}
            //if one of the subdirs, check if it is closed post opening all
            var subFolderCookie = getCookie("{{ file.getPath }}".substr(0,'{{ file.getPath }}'.lastIndexOf("/")));
            if(subFolderCookie.indexOf("closed")==0){
                //if closed. close it after it has been opened by the override above
                closeDivForCourseMaterials(subFolderCookie.substr(6,subFolderCookie.length));
            }
            {% endfor %}
        }
        else{
            //makes sure that opened folders don't get opened multiple times
            let trackOpens = new Map();
            //goes through all possible directories
            {% for file in material_list %}
            //get the cookie for each dir
            var subFolderCookie = getCookie("{{ file.getPath }}".substr(0,'{{ file.getPath }}'.lastIndexOf("/")));
            //if the folder is open
            if(subFolderCookie.indexOf("open")==0){
                //check if the folder has been opened already (do it it again will close it)
                if(trackOpens.get(subFolderCookie.substr(4,subFolderCookie.length)) === undefined){
                    //undefined means it has not been opened
                    //set the value as open so it will not be reopened
                    trackOpens.set(subFolderCookie.substr(4,subFolderCookie.length),"released");
                    //open the folder
                    openDivForCourseMaterials(subFolderCookie.substr(4,subFolderCookie.length));
                }
            }
            else{
                if(subFolderCookie.indexOf("closed")==0){
                    //if the folder should be closed, close it
                    closeDivForCourseMaterials(subFolderCookie.substr(6,subFolderCookie.length));
                    //there's no way to open it in that function
                }
            }
            {% endfor %}
        }
        // loop thru each div_viewer_xxx
        var jumpToScrollPosition = document.cookie.replace(/(?:(?:^|.*;\s*)jumpToScrollPosition\s*\=\s*([^;]*).*$)|^.*$/, "$1");
        {% if user_group == 1 %}
            var topFolderMatcher = new RegExp('^div_viewer_sd[0-9]{0,}$');
            const partiallyHidden = 2;

            // accepts an element (editButton) having required data attributes; other parameters represent the properties known to be common until now
            // returns an updated set of common props by comparing with the props of the given element
            function folderCommonProps(editButton, commonSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch) {
                let residualSections = [];
                if (first) {
                    commonSections = editButton.data('sections');
                    releaseTime = editButton.data('release-time');
                    hiddenState = editButton.data('hidden-state');
                    first = false;
                }
                else {
                    let combinedSections = [...(new Set([...commonSections, ...editButton.data('sections')]))];
                    commonSections = commonSections.filter(x => {return editButton.data('sections').includes(x);});
                    residualSections = combinedSections.filter(x => {return !commonSections.includes(x);});
                    if (!releaseTimeMismatch) {
                        if (editButton.data('release-time') !== releaseTime) {
                            releaseTimeMismatch = true;
                            releaseTime = '';
                        }
                    }
                    if (!hiddenStateMismatch) {
                        if (editButton.data('hidden-state') !== hiddenState) {
                            hiddenStateMismatch = true;
                            hiddenState = '';
                        }
                    }
                }
                return [commonSections, residualSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch];
            }

            // sets the common properties of a given folder
            function folderSetter(elem) {
                let insideFileMatcher = new RegExp(`^${elem.attr("id").replace("div", "file")}f[0-9]{0,}$`);
                let insideFolderMatcher = new RegExp(`^${elem.attr("id")}d[0-9]{0,}$`);
                let first = true;
                let commonSections = [];
                let residualSections = [];
                let partialSections = [];
                let releaseTime = "";
                let hiddenState = '';
                let hiddenStateMismatch = false;
                let releaseTimeMismatch = false;
                $(`.folder-container > [id^=${elem.attr("id")}d]`, elem).each(function() {
                    if (insideFolderMatcher.test($(this).attr('id'))) {
                        folderSetter($(this));
                        let fEditButton = $(this).siblings('.div-viewer').children('a[onclick^=newEditCourseMaterialsFolderForm]');
                        partialSections.push(...fEditButton.data('partial-sections'));
                        [commonSections, residualSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch] = folderCommonProps(fEditButton, commonSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch);
                        partialSections.push(...residualSections);
                    }
                });
                $(`.file-container > .file-viewer > a[onclick^=newEditCourseMaterialsForm]`, elem).each(function() {
                    if (insideFileMatcher.test($(this).parent('.file-viewer').siblings('.file-viewer-data').attr('id'))) {
                        [commonSections, residualSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch] = folderCommonProps($(this), commonSections, releaseTime, hiddenState, first, hiddenStateMismatch, releaseTimeMismatch);
                        partialSections.push(...residualSections);
                    }
                });
                let editButton = $(elem.siblings('.div-viewer').children('a[onclick^=newEditCourseMaterialsFolderForm]'));
                editButton.attr('data-sections', JSON.stringify(commonSections));
                editButton.attr('data-partial-sections', JSON.stringify(partialSections));
                editButton.attr('data-release-time', releaseTime);
                if (hiddenStateMismatch) {
                    hiddenState = partiallyHidden;
                }
                editButton.attr('data-hidden-state', hiddenState);
            }

            function callFolderSetter(elem) {
                if (topFolderMatcher.test(elem.id)) {
                    folderSetter($(elem));
                }
            }
        {% endif %}
        if (jumpToScrollPosition.length > 0 && jumpToScrollPosition != '-1') {

            $('[id^=div_viewer_]').each(function() {
                {% if user_group == 1 %}
                    callFolderSetter(this);
                {% endif %}
                var number = this.id.replace('div_viewer_', '').trim();
                var keyValuePairs = document.cookie.split(';');

                for(var i = 0; i < keyValuePairs.length; i++) {
                    var name = keyValuePairs[i].substring(0, keyValuePairs[i].indexOf('=')).trim();
                    var value = keyValuePairs[i].substring(keyValuePairs[i].indexOf('=')+1);
                    if (name === 'cm_'+number && value === '1') {
                        openDivForCourseMaterials(number);
                        document.cookie = 'cm_' + number + '='; // clean up cookie since we don't need this anymore
                    }
                }
            });
            // jump to last location if scroll is enabled.
            window.scrollTo(0, jumpToScrollPosition);
            document.cookie = 'jumpToScrollPosition=-1';

        }
        else {
            // clean up all cookies which are stated with "cm_";
            $('[id^=div_viewer_]').each(function() {
                {% if user_group == 1 %}
                    callFolderSetter(this);
                {% endif %}
                var number = this.id.replace('div_viewer_', '').trim();
                var keyValuePairs = document.cookie.split(';');

                for(var i = 0; i < keyValuePairs.length; i++) {
                    var name = keyValuePairs[i].substring(0, keyValuePairs[i].indexOf('=')).trim();
                    if (name === 'cm_'+number) {
                        document.cookie = 'cm_' + number + '=';
                    }
                }
            });
        }
        {% if user_group == 1 %}

            $('#hide-materials-checkbox').on('change', handleHideMaterialsCheckboxChange);
            $('#hide-materials-checkbox-edit').on('change', handleHideMaterialsCheckboxChange);
            $('[id^="section-folder-edit"]').on('change', function() {
                if ($(this).hasClass('partial-checkbox')) {
                    $(this).removeClass('partial-checkbox');
                    if ($(this).attr('class') === '') {
                        $(this).removeAttr('class');
                    }
                    $(this).prop('checked', true);
                }
            })

        {% endif %}
    };

</script>


{% include('course/SetFolderReleaseForm.twig') %}
{% include 'course/UploadCourseMaterialsForm.twig' with {reg_sections: reg_sections} %}
{% include 'course/EditCourseMaterialsForm.twig' %}
{% include 'course/EditCourseMaterialsFolderForm.twig' %}
{% include('course/DeleteCourseMaterialForm.twig') %}
{% include('course/SetAllReleaseForm.twig') %}

{'fraction_non_alphanumeric': 0.14084419998763983, 'fraction_numerical': 0.004284860845023999, 'mean_word_length': 1.8754886861746238, 'pattern_counts': {'":': 10, '<': 219, '<?xml version=': 0, '>': 229, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2393810', 'n_tokens_mistral': 13523, 'n_tokens_neox': 12491, 'n_words': 2716}