├── .gitattributes ├── .gitignore ├── Canvas Course Event Manager.user.js ├── Canvas Crosslisting.user.js ├── Canvas Remove Student Tool.user.js ├── Instructor Crosslisting and Decrosslisting with Admin Crosslisting.user.js ├── KatyISD Specific Scripts └── KatyISD specific crosslisting with admin crosslisting and decrosslisting tool ├── LICENSE ├── README.md ├── instructor and admin crosslisting tools.user.js └── printCanvasQuizzes.user.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Canvas Course Event Manager.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Canvas Course Event Manager 3 | // @namespace https://github.com/sukotsuchido/CanvasUserScripts 4 | // @version 0.55 5 | // @description A Canvas UserScript to manage course events 6 | // @author Chad Scott (ChadScott@katyisd.org) 7 | // @include https://*.instructure.com/calendar* 8 | // @require https://code.jquery.com/jquery-3.4.1.min.js 9 | // @grant none 10 | // ==/UserScript== 11 | (function() { 12 | 'use strict'; 13 | var assocRegex3 = new RegExp('^/calendar'); 14 | var errors = []; 15 | var courseId = ''; 16 | var termId = ''; 17 | var courses = []; 18 | var allCourses = []; 19 | var wholeName = ''; 20 | var array =[]; 21 | var user = ''; 22 | /* role setup */ 23 | var roles = ENV.current_user_roles; 24 | var buttonRoles = ["admin", "teacher", "root_admin"]; 25 | var test1 = buttonRoles.some(el => roles.includes(el)); 26 | if( (test1 === true) && (assocRegex3.test(window.location.pathname))){ 27 | add_button(); 28 | } 29 | function add_button() { 30 | var parent = document.querySelector('aside#right-side'); 31 | if (parent) { 32 | var el = parent.querySelector('#manage_events'); 33 | if (!el) { 34 | el = document.createElement('button'); 35 | el.classList.add('Button'); 36 | el.type = 'button'; 37 | el.id = 'manage_events'; 38 | var icon = document.createElement('i'); 39 | icon.classList.add('icon-edit'); 40 | el.appendChild(icon); 41 | var txt = document.createTextNode(' Manage Course Events'); 42 | el.appendChild(txt); 43 | el.addEventListener('click', openDialog); 44 | parent.appendChild(el); 45 | } 46 | } 47 | } 48 | function getCourses(){ 49 | // Reset global variable errors 50 | errors= []; 51 | var url = "/api/v1/users/self/courses?include[]=term&per_page=75"; // change self to specific user number for testing 52 | $.ajax({ 53 | 'async': true, 54 | 'type': "GET", 55 | 'global': true, 56 | 'dataType': 'JSON', 57 | 'data': JSON.stringify(courses), 58 | 'contentType': "application/json", 59 | 'url': url, 60 | 'success': function(courses){ 61 | allCourses = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 62 | var toAppend = ''; 63 | var select = document.getElementById('event_course'); 64 | select.options.length = 0; // clear out existing items 65 | $.each(allCourses, function(i, o){ 66 | if(o.name !== undefined){ 67 | toAppend += ''; 68 | } 69 | }); 70 | var blank =''; 71 | blank += ''; 72 | $('#event_course').append(blank); 73 | $('#event_course').append(toAppend); 74 | } 75 | }); 76 | } 77 | function getEvents(){ 78 | // Reset global variable errors 79 | errors= []; 80 | courseId = document.getElementById('event_course').value; 81 | var url = "/api/v1/users/self/calendar_events?per_page=150&all_events=true&context_codes[]=course_"+courseId; 82 | $.ajax({ 83 | 'async': true, 84 | 'type': "GET", 85 | 'global': true, 86 | 'dataType': 'JSON', 87 | 'data': JSON.stringify(courses), 88 | 'contentType': "application/json", 89 | 'url': url, 90 | 'success': function (data, textStatus, request) { 91 | var toAppend; 92 | var clear = document.getElementById('inner_table'); 93 | if (clear.innerHTML !== null){ 94 | clear.innerHTML = ""; 95 | } 96 | $.each(data,function(i,o){ 97 | //start date 98 | var date = new Date(o.start_at); 99 | var day = date.getDate(); 100 | var year = date.getFullYear(); 101 | var month = date.getMonth()+1; 102 | var dateStr = month+"/"+day+"/"+year; 103 | //end date 104 | var date2 = new Date(o.end_at); 105 | var day2 = date2.getDate(); 106 | var year2 = date2.getFullYear(); 107 | var month2 = date2.getMonth()+1; 108 | var dateStr2 = month2+"/"+day2+"/"+year2; 109 | toAppend += ''+o.title+''+dateStr+''+dateStr2+''; 110 | }); 111 | $('#table_header').append(toAppend); 112 | } 113 | }); 114 | } 115 | function deleteEvents(){ 116 | $.each(array, function(index,item){ 117 | var eventId = item; 118 | var url = "/api/v1/calendar_events/"+eventId; 119 | $.ajax({ 120 | 'async': true, 121 | 'type': "DELETE", 122 | 'global': true, 123 | 'dataType': 'JSON', 124 | 'data': JSON.stringify(), 125 | 'contentType': "application/json", 126 | 'url': url, 127 | 'success': open_success_dialog 128 | }); 129 | }); 130 | window.location.reload(true); 131 | } 132 | function removeDates(){ 133 | $.each(array, function(index,item){ 134 | var eventId = item; 135 | var url = "/api/v1/calendar_events/"+eventId+"?calendar_event[start_at]=null&calendar_event[end_at]=null"; 136 | $.ajax({ 137 | 'async': true, 138 | 'type': "PUT", 139 | 'global': true, 140 | 'dataType': 'JSON', 141 | 'data': JSON.stringify(), 142 | 'contentType': "application/json", 143 | 'url': url, 144 | 'success': open_success_dialog 145 | }); 146 | }); 147 | window.location.reload(true); 148 | } 149 | function createDialog() { 150 | var el = document.querySelector('#events_dialog'); 151 | if (!el) { 152 | el = document.createElement('div'); 153 | el.id = 'events_dialog'; 154 | //Parent Course selection 155 | var el2 = document.createElement('div'); 156 | el2.classList.add('ic-Form-control'); 157 | el.appendChild(el2); 158 | var label = document.createElement('label'); 159 | label.htmlFor = 'event_course'; 160 | label.textContent = 'Step 1: Select Course:'; 161 | label.classList.add('ic-Label'); 162 | el2.appendChild(label); 163 | var select = document.createElement('select'); 164 | select.id = 'event_course'; 165 | select.classList.add('ic-Input'); 166 | select.onchange = getEvents; 167 | el2.appendChild(select); 168 | //Events Table 169 | var table = document.createElement('TABLE'); 170 | table.id = 'table_header'; 171 | table.style.width = '100%'; 172 | table.classList.add("ic-Table", "ic-Table--hover-row", "ic-Table--striped"); 173 | el.appendChild(table); 174 | var tr = document.createElement('TR'); 175 | table.appendChild(tr); 176 | var th = document.createElement('TH'); 177 | var input = document.createElement('input'); 178 | input.type = 'checkbox'; 179 | input.name = 'select-all'; 180 | input.id = 'select-all'; 181 | input.onchange = setEvents; 182 | th.appendChild(input); 183 | th.classList.add('ic-Checkbox-group'); 184 | tr.appendChild(th); 185 | th = document.createElement('TH'); 186 | th.textContent = 'Event Title'; 187 | tr.appendChild(th); 188 | th = document.createElement('TH'); 189 | th.textContent = 'Start Date'; 190 | tr.appendChild(th); 191 | th = document.createElement('TH'); 192 | th.textContent = 'End Date'; 193 | tr.appendChild(th); 194 | var tbody = document.createElement('tbody'); 195 | tbody.id = 'inner_table'; 196 | tbody.onchange= setEvents; 197 | table.appendChild(tbody); 198 | var notice = document.createElement('div'); 199 | notice.id = 'app'; 200 | /*notice.id = 'notice'; 201 | notice.style = 'text-align: right'; 202 | notice.style.padding = '5px'; 203 | notice.style.font ='bold 14px arial,serif'; 204 | notice.textContent ='First 100 Events Only'; 205 | */ 206 | el.appendChild(notice); 207 | //HR 208 | var hr = document.createElement('HR'); 209 | el.appendChild(hr); 210 | //selected action list 211 | var el3 = document.createElement('div'); 212 | el3.innerHTML ='
For Selected Events:
'; 213 | el.append(el3); 214 | //message flash 215 | var msg = document.createElement('div'); 216 | msg.id = 'events_msg'; 217 | //msg.classList.add('ic-flash-warning'); 218 | msg.style.display = 'none'; 219 | el.appendChild(msg); 220 | var parent = document.querySelector('body'); 221 | parent.appendChild(el); 222 | } 223 | $('#select-all').click(function(event) { 224 | var state = this.checked; $(':checkbox').each(function() { this.checked = state; }); 225 | }); 226 | } 227 | function setEvents() { 228 | array = $.map($('input[name="events"]:checked'), function(c){return c.value; }); 229 | } 230 | function openDialog() { 231 | try { 232 | createDialog(); 233 | $('#events_dialog').dialog({ 234 | 'title' : 'Manage Course Events', 235 | 'autoOpen' : false, 236 | 'closeOnEscape': false, 237 | 'open': getCourses(), function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 238 | 'buttons' : [ { 239 | 'text' : 'Cancel', 240 | 'click' : function() { 241 | $(this).dialog('destroy').remove(); 242 | errors = []; 243 | updateMsgs(); 244 | } 245 | },{ 246 | 'text' : 'Submit', 247 | 'class': 'Button Button--primary', 248 | 'click' : submitButton 249 | 250 | } ], 251 | 'modal' : true, 252 | 'resizable' : false, 253 | 'height' : '600', 254 | 'width' : '40%', 255 | 'scrollable' : true 256 | }); 257 | if (!$('#events_dialog').dialog('isOpen')) { 258 | $('#events_dialog').dialog('open'); 259 | } 260 | } catch (e) { 261 | console.log(e); 262 | } 263 | } 264 | function submitButton(){ 265 | var action = document.querySelector('input[name="action"]:checked').value; 266 | if(action == "delete_events"){ 267 | deleteEvents(); 268 | }else{ 269 | removeDates(); 270 | } 271 | } 272 | function successDialog(){ 273 | var el = document.querySelector('#success_dialog'); 274 | if (!el) { 275 | el = document.createElement('div'); 276 | el.id = 'success_dialog'; 277 | var div1 = document.createElement('div'); 278 | div1.classList.add('ic-flash-success'); 279 | el.appendChild(div1); 280 | var div2 = document.createElement('div'); 281 | div2.classList.add('ic-flash__icon'); 282 | div2.classList.add('aria-hidden="true"'); 283 | div1.appendChild(div2); 284 | var icon = document.createElement('i'); 285 | icon.classList.add('icon-check'); 286 | div2.appendChild(icon); 287 | var msg = document.createTextNode("The action completed successfully!"); 288 | div1.appendChild(msg); 289 | var button = document.createElement('button'); 290 | button.type = 'button'; 291 | button.classList.add("Button", "Button--icon-action", "close_link"); 292 | el.appendChild(button); 293 | icon = document.createElement('i'); 294 | icon.classList.add('ic-icon-x'); 295 | icon.classList.add('aria-hidden="true"'); 296 | button.appendChild(icon); 297 | var parent = document.querySelector('body'); 298 | parent.appendChild(el); 299 | } 300 | } 301 | function open_success_dialog(){ 302 | try { 303 | successDialog(); 304 | $('#success_dialog').dialog({ 305 | 'autoOpen' : false, 306 | 'closeOnEscape': false, 307 | 'open': function () { $(".ui-dialog-titlebar").hide(); $(".ui-widget-content").css("background", "rgba(255, 255, 255, 0)"); $(".ui-dialog.ui-widget-content").css("box-shadow", "none");}, 308 | 'modal' : true, 309 | 'resizable' : false, 310 | 'height' : 'auto', 311 | 'width' : '40%', 312 | }); 313 | if (!$('#success_dialog').dialog('isOpen')) { 314 | $('#success_dialog').dialog('open'); 315 | } 316 | } catch (e) { 317 | console.log(e); 318 | } 319 | } 320 | function updateMsgs() { 321 | var msg = document.getElementById('events_msg'); 322 | if (!msg) { 323 | return; 324 | } 325 | if (msg.hasChildNodes()) { 326 | msg.removeChild(msg.childNodes[0]); 327 | } 328 | if (typeof errors === 'undefined' || errors.length === 0) { 329 | msg.style.display = 'none'; 330 | } else { 331 | var div1 = document.createElement('div'); 332 | div1.classList.add('ic-flash-error'); 333 | var div2; 334 | div2 = document.createElement('div'); 335 | div2.classList.add('ic-flash__icon'); 336 | div2.classList.add('aria-hidden="true"'); 337 | div1.appendChild(div2); 338 | var icon; 339 | icon = document.createElement('i'); 340 | icon.classList.add('icon-warning'); 341 | div2.appendChild(icon); 342 | var ul = document.createElement('ul'); 343 | for (var i = 0; i < errors.length; i++) { 344 | var li; 345 | li = document.createElement('li'); 346 | li.textContent = errors[i]; 347 | ul.appendChild(li); 348 | } 349 | div1.appendChild(ul); 350 | var button; 351 | button = document.createElement('button'); 352 | button.type = 'button'; 353 | button.classList.add("Button", "Button--icon-action", "close_link"); 354 | div1.appendChild(button); 355 | icon = document.createElement('i'); 356 | icon.classList.add('ic-icon-x'); 357 | icon.classList.add('aria-hidden="true"'); 358 | button.appendChild(icon); 359 | msg.appendChild(div1); 360 | msg.style.display = 'inline-block'; 361 | } 362 | } 363 | })(); 364 | -------------------------------------------------------------------------------- /Canvas Crosslisting.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Canvas Crosslisting 3 | // @namespace http://tampermonkey.net/ 4 | // @version 1.0 5 | // @description try to save our time 6 | // @author Chad Scott 7 | // @include https://*.instructure.com/accounts/* 8 | // @grant none 9 | // ==/UserScript== 10 | (function() { 11 | 'use strict'; 12 | var assocRegex = new RegExp('^/accounts/([0-9]+)$'); 13 | var errors = []; 14 | var childS = []; 15 | var parentC = []; 16 | 17 | if (assocRegex.test(window.location.pathname)) { 18 | add_button(); 19 | } 20 | 21 | function getCsrfToken() { 22 | var csrfRegex = new RegExp('^_csrf_token=(.*)$'); 23 | var csrf; 24 | var cookies = document.cookie.split(';'); 25 | for (var i = 0; i < cookies.length; i++) { 26 | var cookie = cookies[i].trim(); 27 | var match = csrfRegex.exec(cookie); 28 | if (match) { 29 | csrf = decodeURIComponent(match[1]); 30 | break; 31 | } 32 | } 33 | return csrf; 34 | } 35 | 36 | function add_button() { 37 | var parent = document.querySelector('aside#right-side'); 38 | if (parent) { 39 | var el = parent.querySelector('#jj_cross'); 40 | if (!el) { 41 | el = document.createElement('a'); 42 | el.classList.add('btn', 'button-sidebar-wide'); 43 | el.id = 'jj_cross'; 44 | var icon = document.createElement('i'); 45 | icon.classList.add('icon-import'); 46 | el.appendChild(icon); 47 | var txt = document.createTextNode(' Crosslist Courses'); 48 | el.appendChild(txt); 49 | el.addEventListener('click', openDialog); 50 | parent.appendChild(el); 51 | } 52 | } 53 | } 54 | 55 | function createDialog() { 56 | var el = document.querySelector('#jj_cross_dialog'); 57 | if (!el) { 58 | //field1 59 | el = document.createElement('div'); 60 | el.id = 'jj_cross_dialog'; 61 | el.classList.add('ic-Form-control'); 62 | var label = document.createElement('label'); 63 | label.htmlFor = 'jj_cross_title'; 64 | label.textContent = 'Parent Course Number:'; 65 | label.classList.add('ic-Label'); 66 | el.appendChild(label); 67 | var input = document.createElement('input'); 68 | input.id = 'jj_cross_title'; 69 | input.classList.add('ic-Input'); 70 | input.type = 'text'; 71 | input.placeholder = 'Enter Parent (bucket) Course Number:'; 72 | el.appendChild(input); 73 | //field2 74 | label = document.createElement('label'); 75 | label.htmlFor = 'jj_cross_child'; 76 | label.textContent = 'Child Course Number: '; 77 | label.classList.add('ic-Label'); 78 | el.appendChild(label); 79 | input = document.createElement('input'); 80 | input.id = 'jj_cross_child'; 81 | input.classList.add('ic-Input'); 82 | input.type = 'text'; 83 | input.placeholder = 'Enter Child Course Number:'; 84 | el.appendChild(input); 85 | 86 | //message flash 87 | var msg = document.createElement('div'); 88 | msg.id = 'jj_cross_msg'; 89 | msg.classList.add('ic-flash-warning'); 90 | msg.style.display = 'none'; 91 | el.appendChild(msg); 92 | var parent = document.querySelector('body'); 93 | parent.appendChild(el); 94 | } 95 | } 96 | 97 | function openDialog() { 98 | try { 99 | createDialog(); 100 | $('#jj_cross_dialog').dialog({ 101 | 'title' : 'Crosslist Courses', 102 | 'autoOpen' : false, 103 | 'buttons' : [ { 104 | 'text' : 'Crosslist', 105 | 'click' : processDialog 106 | }, { 107 | 'text' : 'Cancel', 108 | 'click' : function() { 109 | $(this).dialog('close'); 110 | errors = []; 111 | updateMsgs(); 112 | } 113 | } ], 114 | 'modal' : true, 115 | 'height' : 'auto', 116 | 'width' : '80%' 117 | }); 118 | if (!$('#jj_cross_dialog').dialog('isOpen')) { 119 | $('#jj_cross_dialog').dialog('open'); 120 | } 121 | } catch (e) { 122 | console.log(e); 123 | } 124 | } 125 | 126 | function processDialog() { 127 | // Reset global variable errors 128 | errors = []; 129 | var parentCourse, childCourse; 130 | var el = document.getElementById('jj_cross_title'); 131 | if (el.value && el.value.trim() !== '') { 132 | parentCourse = el.value; 133 | parentC = parentCourse; 134 | } else { 135 | errors.push('You must provide a parent course.'); 136 | } 137 | el = document.getElementById('jj_cross_child'); 138 | if (el.value && el.value.trim() !== '') { 139 | childCourse = el.value; 140 | var childSection; 141 | var url = "/api/v1/courses/" + childCourse + "/sections?"; 142 | $.ajax({ 143 | 'async': true, 144 | 'type': "GET", 145 | 'global': true, 146 | 'dataType': 'JSON', 147 | 'data': JSON.stringify(childSection), 148 | 'contentType': "application/json", 149 | 'url': url, 150 | 'success': function (data) { 151 | childSection = data[0].id; 152 | childS = childSection; 153 | var url2 = "/api/v1/sections/" + childS + "/crosslist/" + parentC +"?"; 154 | $.ajax({ 155 | 'cache' : false, 156 | 'url' : url2 , 157 | 'type' : 'POST', 158 | }).done(function() { 159 | updateMsgs(); 160 | $('#jj_cross_dialog').dialog('close'); 161 | window.location.reload(true); 162 | }).fail(function() { 163 | errors.push('All the information was supplied correctly, but there was an error crosslisting courses in Canvas.'); 164 | updateMsgs(); 165 | }); 166 | } 167 | }); 168 | } else { 169 | errors.push('You must provide a child course.'); 170 | } 171 | updateMsgs(); 172 | } 173 | 174 | 175 | function updateMsgs() { 176 | var msg = document.getElementById('jj_cross_msg'); 177 | if (!msg) { 178 | return; 179 | } 180 | if (msg.hasChildNodes()) { 181 | msg.removeChild(msg.childNodes[0]); 182 | } 183 | if (typeof errors === 'undefined' || errors.length === 0) { 184 | msg.style.display = 'none'; 185 | } else { 186 | var ul = document.createElement('ul'); 187 | var li; 188 | for (var i = 0; i < errors.length; i++) { 189 | li = document.createElement('li'); 190 | li.textContent = errors[i]; 191 | ul.appendChild(li); 192 | } 193 | msg.appendChild(ul); 194 | msg.style.display = 'inline-block'; 195 | } 196 | } 197 | 198 | 199 | })(); 200 | -------------------------------------------------------------------------------- /Canvas Remove Student Tool.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Canvas Student Bulk Remove Enrollments Tool 3 | // @namespace https://github.com/sukotsuchido/CanvasUserScripts 4 | // @version 2.11 5 | // @description A Canvas UserScript to bulk remove student enrollments from a course. 6 | // @author Chad Scott (ChadScott@katyisd.org) 7 | // @include https://*.instructure.com/courses/*/users 8 | // @require https://code.jquery.com/jquery-3.4.1.min.js 9 | // @grant none 10 | // ==/UserScript== 11 | (function() { 12 | 'use strict'; 13 | var assocRegex3 = new RegExp('^/courses/([0-9]+)/users'); 14 | var errors = []; 15 | var courses = []; 16 | var sections = []; 17 | var array =[]; 18 | var courseID = $(location).attr('pathname'); 19 | courseID.indexOf(1); 20 | courseID = courseID.split("/")[2]; 21 | var currURL = false; 22 | var nextURL; 23 | var results = [] 24 | var coursesLength; 25 | var allStudents = []; 26 | /* role setup */ 27 | var roles = ENV.current_user_roles; 28 | var buttonRoles = ["admin", "root_admin"]; 29 | var test1 = buttonRoles.some(el => roles.includes(el)); 30 | if( (test1 === true) && (assocRegex3.test(window.location.pathname))){ 31 | add_button(); 32 | } 33 | 34 | function add_button() { 35 | var parent = document.querySelector('div.ic-Action-header__Secondary'); 36 | if (parent) { 37 | var el = parent.querySelector('#manage_enrollments'); 38 | if (!el) { 39 | el = document.createElement('button'); 40 | el.classList.add('Button','button-primary','element_toggler'); 41 | el.type = 'button'; 42 | el.id = 'manage_enrollments'; 43 | var icon = document.createElement('i'); 44 | icon.classList.add('icon-user'); 45 | el.appendChild(icon); 46 | var txt = document.createTextNode(' Remove Bulk Student Enrollments'); 47 | el.appendChild(txt); 48 | el.addEventListener('click', openDialog); 49 | parent.prepend(el); 50 | } 51 | } 52 | } 53 | 54 | function getSections(){ 55 | var url = "/api/v1/courses/"+courseID+"/sections?&per_page=99"; 56 | $.ajax({ 57 | 'async': false, 58 | 'type': "GET", 59 | 'global': true, 60 | 'dataType': 'JSON', 61 | 'data': JSON.stringify(sections), 62 | 'contentType': "application/json", 63 | 'url': url, 64 | 'success': function (data, textStatus, response) { 65 | 66 | $.each(data,function(i,o){ 67 | var sectionID = o.id; 68 | var sectionName = o.name; 69 | 70 | sections.push({ 71 | key: sectionID, 72 | value: sectionName 73 | }); 74 | 75 | }); 76 | } 77 | }); 78 | } 79 | 80 | 81 | 82 | function getStudents(){ 83 | // Reset global variable errors 84 | errors= []; 85 | var url; 86 | if(!currURL){ 87 | url = "/api/v1/courses/"+courseID+"/enrollments?type[]=StudentEnrollment&per_page=99&page="; 88 | }else{ 89 | url = "/api/v1/courses/"+courseID+"/enrollments?type[]=StudentEnrollment&page="+nextURL; 90 | }; 91 | var jqxhr = $.ajax({ 92 | 'async': false, 93 | 'type': "GET", 94 | 'global': true, 95 | 'dataType': 'JSON', 96 | 'data': JSON.stringify(courses), 97 | 'contentType': "application/json", 98 | 'url': url, 99 | 'success': function (data, textStatus, response) { 100 | const linkTxt = response.getResponseHeader('link'); 101 | coursesLength = data.length; 102 | results.push(data); 103 | 104 | let links = linkTxt.split(","); 105 | let nextRegEx = new RegExp('&page=(.*)>; rel="next"'); 106 | for (let i = 0; i < links.length; i++) { 107 | let matches = nextRegEx.exec(links[i]); 108 | 109 | if (matches && matches[1]) { 110 | nextURL = matches[1]; 111 | } 112 | } 113 | } 114 | }); 115 | if(currURL!=nextURL){ 116 | currURL = nextURL; 117 | getStudents(); 118 | }; 119 | allStudents = results.flat(); 120 | } 121 | function setStudents(){ 122 | var toAppend = ''; 123 | $.each(allStudents,function(i,o){ 124 | var dateStr; 125 | var dateEnrStr; 126 | 127 | var stuSectionID; 128 | var stuSectionName; 129 | stuSectionID = o.course_section_id; 130 | 131 | stuSectionName = sections.find(item => item.key === stuSectionID).value; 132 | 133 | var date2 = new Date(o.created_at); 134 | var day2 = date2.getDate(); 135 | var year2 = date2.getFullYear(); 136 | var month2 = date2.getMonth()+1; 137 | if(day2<10){ 138 | day2='0'+day2; 139 | } 140 | if(month2<10){ 141 | month2='0'+month2; 142 | } 143 | dateEnrStr = month2+"/"+day2+"/"+year2; 144 | 145 | //last activity date 146 | if(o.last_activity_at == null){ 147 | dateStr = "None"; 148 | }else{ 149 | var date = new Date(o.last_activity_at); 150 | var day = date.getDate(); 151 | var year = date.getFullYear(); 152 | var month = date.getMonth()+1; 153 | if(day<10){ 154 | day='0'+day; 155 | } 156 | if(month<10){ 157 | month='0'+month; 158 | } 159 | dateStr = month+"/"+day+"/"+year; 160 | } 161 | 162 | toAppend += ''+o.user.sortable_name+''+stuSectionName+''+dateEnrStr+''+dateStr+''; 163 | }); 164 | $('#table_header').append(toAppend); 165 | } 166 | 167 | async function sleep(sleepTime) { 168 | return new Promise((resolve) => setTimeout(resolve, sleepTime)); 169 | } 170 | 171 | 172 | async function deleteEnrollments(){ 173 | window.requestAnimationFrame(() => { 174 | var footer = document.querySelector('#progress'); 175 | footer.style.background = "url(https://imagizer.imageshack.us/a/img922/9776/IinEAt.gif) no-repeat right center"; 176 | $("
").css({ 177 | position: "absolute", 178 | width: "100%", 179 | height: "100%", 180 | left: 0, 181 | top: 0, 182 | zIndex: 1000000, 183 | }).appendTo($("#events_dialog").css("position", "relative")); 184 | } ); 185 | await sleep(500); 186 | 187 | while (array.length > 0){ 188 | var arrayBatch = array.splice(0,40); 189 | await sleep(5000); 190 | 191 | $.each(arrayBatch, function(index,item){ 192 | 193 | var stuID = item; 194 | var url = "/api/v1/courses/"+courseID+"/enrollments/"+stuID+"?task=delete"; 195 | $.ajax({ 196 | 'async': true, 197 | 'cache': false, 198 | 'type': "DELETE", 199 | 'dataType': 'JSON', 200 | 'data': JSON.stringify(), 201 | 'contentType': "application/json", 202 | 'url': url 203 | }); 204 | }); 205 | } 206 | open_success_dialog(); 207 | } 208 | 209 | function createDialog() { 210 | var el = document.querySelector('#events_dialog'); 211 | if (!el) { 212 | el = document.createElement('div'); 213 | el.id = 'events_dialog'; 214 | //Events Table 215 | var table = document.createElement('TABLE'); 216 | table.id = 'table_header'; 217 | table.style.width = '100%'; 218 | table.classList.add("ic-Table", "ic-Table--hover-row", "ic-Table--striped"); 219 | el.appendChild(table); 220 | var tr = document.createElement('TR'); 221 | table.appendChild(tr); 222 | var th = document.createElement('TH'); 223 | var input = document.createElement('input'); 224 | input.type = 'checkbox'; 225 | input.name = 'select-all'; 226 | input.id = 'select-all'; 227 | input.onchange = setEvents; 228 | th.appendChild(input); 229 | th.classList.add('ic-Checkbox-group'); 230 | tr.appendChild(th); 231 | th = document.createElement('TH'); 232 | th.textContent = 'Student Name'; 233 | th.onmouseover= function(){ 234 | this.style.cursor='pointer'; 235 | }; 236 | th.onclick = function (){ 237 | sortTable(1); 238 | }; 239 | tr.appendChild(th); 240 | th = document.createElement('TH'); 241 | th.textContent = 'Section'; 242 | th.onmouseover= function(){ 243 | this.style.cursor='pointer'; 244 | }; 245 | th.onclick = function (){ 246 | sortTable(2); 247 | }; 248 | tr.appendChild(th); 249 | th = document.createElement('TH'); 250 | th.textContent = 'Enrollment Date'; 251 | th.onmouseover= function(){ 252 | this.style.cursor='pointer'; 253 | }; 254 | th.onclick = function (){ 255 | sortTable(3); 256 | }; 257 | tr.appendChild(th); 258 | th = document.createElement('TH'); 259 | th.textContent = 'Last Activity'; 260 | th.onmouseover= function(){ 261 | this.style.cursor='pointer'; 262 | }; 263 | th.onclick = function (){ 264 | sortTable(4); 265 | }; 266 | tr.appendChild(th); 267 | var tbody = document.createElement('tbody'); 268 | tbody.id = 'inner_table'; 269 | tbody.onchange= setEvents; 270 | table.appendChild(tbody); 271 | 272 | 273 | 274 | //message flash 275 | var msg = document.createElement('div'); 276 | msg.id = 'events_msg'; 277 | //msg.classList.add('ic-flash-warning'); 278 | msg.style.display = 'none'; 279 | el.appendChild(msg); 280 | var parent = document.querySelector('body'); 281 | parent.appendChild(el); 282 | 283 | } 284 | 285 | $('#select-all').click(function(event) { 286 | var state = this.checked; $(':checkbox').each(function() { this.checked = state; }); 287 | }); 288 | 289 | } 290 | 291 | 292 | function setEvents() { 293 | array = $.map($('input[name="students"]:checked'), function(c){return c.value; }); 294 | } 295 | 296 | function successDialog(){ 297 | var el2 = document.querySelector('#success_dialog'); 298 | if (!el2) { 299 | el2 = document.createElement('div'); 300 | el2.id = 'success_dialog'; 301 | var div1 = document.createElement('div'); 302 | div1.classList.add('ic-flash-success'); 303 | el2.appendChild(div1); 304 | var div2 = document.createElement('div'); 305 | div2.classList.add('ic-flash__icon'); 306 | div2.classList.add('aria-hidden="true"'); 307 | div1.appendChild(div2); 308 | var icon = document.createElement('i'); 309 | icon.classList.add('icon-check'); 310 | div2.appendChild(icon); 311 | var msg = document.createTextNode("The action completed successfully!"); 312 | div1.appendChild(msg); 313 | var parent = document.querySelector('body'); 314 | parent.appendChild(el2); 315 | } 316 | 317 | } 318 | 319 | async function open_success_dialog(){ 320 | try { 321 | successDialog(); 322 | $('#success_dialog').dialog({ 323 | 'autoOpen' : false, 324 | 'closeOnEscape': false, 325 | 'open': function () { $(".ui-dialog-titlebar").hide(); $(".ui-widget-content").css("background", "rgba(255, 255, 255, 0)"); $(".ui-dialog.ui-widget-content").css("box-shadow", "none");}, 326 | 'modal' : true, 327 | 'resizable' : false, 328 | 'height' : 'auto', 329 | 'width' : '40%', 330 | }); 331 | 332 | if (!$('#success_dialog').dialog('isOpen')) { 333 | $('#success_dialog').dialog('open'); 334 | 335 | } 336 | 337 | 338 | } catch (e) { 339 | console.log(e); 340 | } 341 | window.requestAnimationFrame(() => { 342 | window.location.reload(true); 343 | } ); 344 | await sleep(2000); 345 | 346 | } 347 | 348 | async function openDialog() { 349 | try { 350 | window.requestAnimationFrame(() => { 351 | createDialog(); 352 | $('#events_dialog').dialog({ 353 | 'title' : 'Manage Student Enrollments', 354 | 'autoOpen' : false, 355 | 'closeOnEscape': false, 356 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px"); 357 | $(".ui-dialog-buttonpane").prop("id","footerDiv"); 358 | var progress = document.createElement('div'); 359 | progress.id='progress'; 360 | progress.style.width='65%'; 361 | progress.style.float='left'; 362 | progress.style.height='40px'; 363 | progress.style.background = "url(https://imagizer.imageshack.us/a/img922/9776/IinEAt.gif) no-repeat right center"; 364 | var footer = document.querySelector('#footerDiv'); 365 | footer.style.backgroundColor='white'; 366 | footer.insertBefore(progress, footer.childNodes[0]); 367 | }, 368 | 'buttons' : [{ 369 | 'text' : 'Cancel', 370 | 'click' : function() { 371 | results = [] 372 | coursesLength; 373 | allStudents = []; 374 | $(this).dialog('destroy').remove(); 375 | errors = []; 376 | updateMsgs(); 377 | } 378 | },{ 379 | 'text' : 'Remove Students', 380 | 'class': 'Button Button--primary', 381 | 'click' : deleteEnrollments 382 | 383 | 384 | } ], 385 | 'modal' : true, 386 | 'resizable' : false, 387 | 'height' : '600', 388 | 'width' : '40%', 389 | 'scrollable' : true 390 | }); 391 | if (!$('#events_dialog').dialog('isOpen')) { 392 | $('#events_dialog').dialog('open'); 393 | } 394 | } ); 395 | } catch (e) { 396 | console.log(e); 397 | } 398 | await sleep(500); 399 | 400 | getSections(); 401 | getStudents(); 402 | setStudents(); 403 | var x = document.querySelector('#progress'); 404 | x.style.background = "none"; 405 | } 406 | 407 | 408 | async function sortTable(n) { 409 | window.requestAnimationFrame(() => { 410 | var footer = document.querySelector('#progress'); 411 | footer.style.background = "url(https://imagizer.imageshack.us/a/img922/9776/IinEAt.gif) no-repeat right center"; 412 | }); 413 | var el = document.querySelector('#events_dialog'); 414 | if (el) { 415 | var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; 416 | table = document.getElementById("table_header"); 417 | switching = true; 418 | // Set the sorting direction to ascending: 419 | dir = "asc"; 420 | /* Make a loop that will continue until 421 | no switching has been done: */ 422 | while (switching) { 423 | // Start by saying: no switching is done: 424 | switching = false; 425 | rows = table.rows; 426 | /* Loop through all table rows (except the 427 | first, which contains table headers): */ 428 | for (i = 1; i < (rows.length - 1); i++) { 429 | // Start by saying there should be no switching: 430 | shouldSwitch = false; 431 | /* Get the two elements you want to compare, 432 | one from current row and one from the next: */ 433 | x = rows[i].getElementsByTagName("TD")[n]; 434 | y = rows[i + 1].getElementsByTagName("TD")[n]; 435 | /* Check if the two rows should switch place, 436 | based on the direction, asc or desc: */ 437 | if (dir == "asc") { 438 | if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { 439 | // If so, mark as a switch and break the loop: 440 | shouldSwitch = true; 441 | break; 442 | } 443 | } else if (dir == "desc") { 444 | if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { 445 | // If so, mark as a switch and break the loop: 446 | shouldSwitch = true; 447 | break; 448 | } 449 | } 450 | } 451 | if (shouldSwitch) { 452 | /* If a switch has been marked, make the switch 453 | and mark that a switch has been done: */ 454 | rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); 455 | switching = true; 456 | // Each time a switch is done, increase this count by 1: 457 | switchcount ++; 458 | } else { 459 | /* If no switching has been done AND the direction is "asc", 460 | set the direction to "desc" and run the while loop again. */ 461 | if (switchcount == 0 && dir == "asc") { 462 | dir = "desc"; 463 | switching = true; 464 | } 465 | } 466 | } 467 | var footer = document.querySelector('#progress'); 468 | footer.style.background = "none"; 469 | } 470 | } 471 | 472 | function updateMsgs() { 473 | var msg = document.getElementById('events_msg'); 474 | if (!msg) { 475 | return; 476 | } 477 | if (msg.hasChildNodes()) { 478 | msg.removeChild(msg.childNodes[0]); 479 | } 480 | if (typeof errors === 'undefined' || errors.length === 0) { 481 | msg.style.display = 'none'; 482 | } else { 483 | var div1 = document.createElement('div'); 484 | div1.classList.add('ic-flash-error'); 485 | var div2; 486 | div2 = document.createElement('div'); 487 | div2.classList.add('ic-flash__icon'); 488 | div2.classList.add('aria-hidden="true"'); 489 | div1.appendChild(div2); 490 | var icon; 491 | icon = document.createElement('i'); 492 | icon.classList.add('icon-warning'); 493 | div2.appendChild(icon); 494 | var ul = document.createElement('ul'); 495 | for (var i = 0; i < errors.length; i++) { 496 | var li; 497 | li = document.createElement('li'); 498 | li.textContent = errors[i]; 499 | ul.appendChild(li); 500 | } 501 | div1.appendChild(ul); 502 | var button; 503 | button = document.createElement('button'); 504 | button.type = 'button'; 505 | button.classList.add("Button", "Button--icon-action", "close_link"); 506 | div1.appendChild(button); 507 | icon = document.createElement('i'); 508 | icon.classList.add('ic-icon-x'); 509 | icon.classList.add('aria-hidden="true"'); 510 | button.appendChild(icon); 511 | msg.appendChild(div1); 512 | msg.style.display = 'inline-block'; 513 | } 514 | } 515 | $.noConflict(true); 516 | })(); 517 | -------------------------------------------------------------------------------- /Instructor Crosslisting and Decrosslisting with Admin Crosslisting.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Canvas Crosslisting Instructor Tool 3 | // @namespace https://github.com/sukotsuchido/CanvasUserScripts 4 | // @version 2.1 5 | // @description A Canvas UserScript to facilitate crosslisting and de-crosslisting of courses. 6 | // @author Chad Scott (ChadScott@katyisd.org) 7 | // @include https://*.instructure.com/courses 8 | // @include https://*.instructure.com/accounts/* 9 | // @grant none 10 | // ==/UserScript== 11 | 'use strict'; 12 | var assocRegex = new RegExp('^/courses$'); 13 | var assocRegex2 = new RegExp('^/accounts/([0-9]+)$'); 14 | var acc = window.location.pathname; 15 | var errors = []; 16 | var parentId = []; 17 | var maxValue = 1; 18 | var termId = ''; 19 | var courses = {}; 20 | var dedupThings = []; 21 | var wholeName = ''; 22 | var array =[]; 23 | var user = ''; 24 | /* role setup: Change the roles you want to have access to the crosslisting features. assocRegex is for the button on the all courses page and assocRegex2 is for the admin page. */ 25 | var roles = ENV.current_user_roles; 26 | var cxbuttonRoles = ["admin", "teacher", "root_admin"]; 27 | var admincxbuttonRoles = ["root_admin"]; 28 | var test1 = cxbuttonRoles.some(el => roles.includes(el)); 29 | var test2 = admincxbuttonRoles.some(el => roles.includes(el)); 30 | if( (test1 === true) && (assocRegex.test(window.location.pathname))){ 31 | getCourses(); 32 | } 33 | if( (test2 === true) && (assocRegex2.test(window.location.pathname))){ 34 | add_buttonAdmin(); 35 | } 36 | function add_button() { 37 | var parent = document.querySelector('div.ic-Action-header__Secondary'); 38 | if (parent) { 39 | var el = parent.querySelector('#jj_cross'); 40 | if (!el) { 41 | el = document.createElement('button'); 42 | el.classList.add('Button','element_toggler'); 43 | el.type = 'button'; 44 | el.id = 'jj_cross'; 45 | var icon = document.createElement('i'); 46 | icon.classList.add('icon-sis-synced'); 47 | el.appendChild(icon); 48 | var txt = document.createTextNode(' Crosslist Courses'); 49 | el.appendChild(txt); 50 | el.addEventListener('click', openDialog); 51 | parent.appendChild(el); 52 | } 53 | //de-crosslist button 54 | var el2 = parent.querySelector('#jj_decross'); 55 | if (!el2) { 56 | el2 = document.createElement('button'); 57 | el2.classList.add('Button', 'element_toggler'); 58 | el2.type = 'button'; 59 | el2.id = 'jj_decross'; 60 | var icon2 = document.createElement('i'); 61 | icon2.classList.add('icon-sis-not-synced'); 62 | el2.appendChild(icon2); 63 | var txt2 = document.createTextNode(' De-Crosslist Courses'); 64 | el2.appendChild(txt2); 65 | el2.addEventListener('click', openDialog2); 66 | parent.appendChild(el2); 67 | } 68 | } 69 | } 70 | /* This function creates the main popup window users interact with the crosslist their courses. 71 | I followed the Canvas Style Guide as much as possible to the CSS already available to create the form elements. */ 72 | function createDialog() { 73 | var el = document.querySelector('#jj_cross_dialog'); 74 | if (!el) { 75 | el = document.createElement('form'); 76 | el.id = 'jj_cross_dialog'; 77 | el.classList.add('ic-Form-group'); 78 | //Parent Course selection 79 | var help = document.createElement('div'); 80 | help.innerHTML = '
Directions: Complete for each step to crosslist and rename your courses.
Click OPTIONS for more information about Crosslisting.
Options
'; 81 | help.classList.add('ic-Label'); 82 | el.appendChild(help); 83 | var el5 = document.createElement('div'); 84 | el5.classList.add('ic-Form-control'); 85 | el.appendChild(el5); 86 | var label = document.createElement('label'); 87 | label.htmlFor = 'jj_cross_parentCourse'; 88 | label.innerHTML = 'Step 1: Select Bucket Course (Hover over step for more help)'; 89 | label.classList.add('ic-Label'); 90 | el5.appendChild(label); 91 | var select = document.createElement('select'); 92 | select.id = 'jj_cross_parentCourse'; 93 | select.classList.add('ic-Input'); 94 | select.onchange = getChildren; 95 | el5.appendChild(select); 96 | //childcourse checkboxes 97 | var el6 = document.createElement('fieldset'); 98 | el6.id = 'child_list'; 99 | el6.style.visibility = 'hidden'; 100 | el6.classList.add("ic-Fieldset", "ic-Fieldset--radio-checkbox"); 101 | el.appendChild(el6); 102 | var el7 = document.createElement('legend'); 103 | el7.classList.add('ic-Legend'); 104 | el7.innerHTML = 'Step 2: Choose Courses to Crosslist Into Bucket Course (Hover over step for more help)'; 105 | el6.appendChild(el7); 106 | var el8 = document.createElement('div'); 107 | el8.id = 'checkboxes'; 108 | el8.classList.add('ic-Checkbox-group'); 109 | el6.appendChild(el8); 110 | //Course Name 111 | var el9 = document.createElement('div'); 112 | el9.id = 'course_div'; 113 | el9.style.visibility = 'hidden'; 114 | el9.classList.add('ic-Form-control'); 115 | el.appendChild(el9); 116 | label = document.createElement('label'); 117 | label.htmlFor = 'course_name'; 118 | label.innerHTML = ' Step 3: Set Course Name (Hover over step for more help)'; 119 | label.classList.add('ic-Label'); 120 | el9.appendChild(label); 121 | var input = document.createElement('input'); 122 | input.id = 'course_name'; 123 | input.classList.add('ic-Input'); 124 | input.type = 'text'; 125 | //input.placeholder = 'Campus Initials Course Name Teacher Name (First Initial.Last Name)'; 126 | el9.appendChild(input); 127 | //Course Name Examples 128 | var el10 = document.createElement('p'); 129 | el10.id = 'examples'; 130 | el10.style.visibility = 'hidden'; 131 | el10.classList = 'text-info'; 132 | el.appendChild(el10); 133 | var ol = document.createElement('ol'); 134 | ol.textContent = 'Examples:'; 135 | //ol.style.border = "thin solid #0000FF"; 136 | ol.classList = 'unstyled'; 137 | el10.appendChild(ol); 138 | var li = document.createElement('li'); 139 | li.textContent = 'High School: KHS English 3 A M.Smith'; 140 | ol.appendChild(li); 141 | li = document.createElement('li'); 142 | li.textContent = 'Junior High: BJH Spanish 1 PreAP G.Moreno'; 143 | ol.appendChild(li); 144 | li = document.createElement('li'); 145 | li.textContent = 'Elementary: KDE 4 Math G.Rorey'; 146 | ol.appendChild(li); 147 | //message flash 148 | var msg = document.createElement('div'); 149 | msg.id = 'jj_cross_msg'; 150 | //msg.classList.add('ic-flash-warning'); 151 | msg.style.display = 'none'; 152 | el.appendChild(msg); 153 | var parent = document.querySelector('body'); 154 | parent.appendChild(el); 155 | } 156 | setParent(); 157 | /* opens the help dialog window */ 158 | document.getElementById("action_helper").addEventListener("click", function(){ 159 | openHelp(); 160 | }); 161 | } 162 | 163 | /* Help dialog window, explains the steps of how to crosslist */ 164 | function createhelpDialog(){ 165 | var el = document.querySelector('#help_dialog'); 166 | if (!el) { 167 | el = document.createElement('div'); 168 | el.innerHTML= '
Crosslist and Name Course: Complete all 3 steps
Crosslist and Don\'t Rename Course: Complete steps 1 and 2
Only Rename Course: Complete steps 1 and 3

Hover over each step for more help.
'; 169 | el.id = 'help_dialog'; 170 | //Parent Course selection 171 | //message flash 172 | var msg = document.createElement('div'); 173 | msg.id = 'jj_cross_msg'; 174 | //msg.classList.add('ic-flash-warning'); 175 | msg.style.display = 'none'; 176 | el.appendChild(msg); 177 | var parent = document.querySelector('body'); 178 | parent.appendChild(el); 179 | } 180 | } 181 | 182 | /* This function creates the modal window for the help dialog, I have hidden the titlebar close button and disabled the ability to esc close also. */ 183 | function openHelp() { 184 | try { 185 | createhelpDialog(); 186 | $('#help_dialog').dialog({ 187 | 'title' : 'Possible Actions', 188 | 'autoOpen' : false, 189 | 'closeOnEscape': false, 190 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 191 | 'buttons' : [ { 192 | 'text' : 'Close', 193 | 'click' : function() { 194 | $(this).dialog('destroy').remove(); 195 | } 196 | } ], 197 | 'modal' : true, 198 | 'resizable' : false, 199 | 'height' : 'auto', 200 | 'width' : '30%' 201 | }); 202 | if (!$('#help_dialog').dialog('isOpen')) { 203 | $('#help_dialog').dialog('open'); 204 | } 205 | } catch (e) { 206 | console.log(e); 207 | } 208 | } 209 | 210 | /* This function sends an api request to get the current users course list. */ 211 | function getCourses(){ 212 | // Reset global variable errors 213 | errors= []; 214 | var url = "/api/v1/users/self/courses?inlcude[]=term&include[]=sections&per_page=100"; 215 | $.ajax({ 216 | 'async': true, 217 | 'type': "GET", 218 | 'global': true, 219 | 'dataType': 'JSON', 220 | 'data': JSON.stringify(courses), 221 | 'contentType': "application/json", 222 | 'url': url, 223 | 'success': function(courses){ 224 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 225 | add_button(); 226 | } 227 | }); 228 | } 229 | /* This function sorts and returns only the most recent term id number. This prevents users from crosslisting into manually created courses. */ 230 | function maxTerm(dedupThings){ 231 | for(var i=0;i maxValue){ 233 | maxValue = Number(dedupThings[i].enrollment_term_id); 234 | } 235 | } 236 | return maxValue; 237 | } 238 | 239 | /* This function takes the return from getTerm and then filters the courses for only that term id and sets the courses in the dropdown. */ 240 | function setParent(){ 241 | var toAppend = ''; 242 | var select = document.getElementById('jj_cross_parentCourse'); 243 | select.options.length = 0; // clear out existing items 244 | termId = maxTerm(dedupThings); 245 | $.each(dedupThings, function(i, o){ 246 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher") { 247 | toAppend += ''; 248 | } 249 | }); 250 | var blank =''; 251 | blank += ''; 252 | $('#jj_cross_parentCourse').append(blank); 253 | $('#jj_cross_parentCourse').append(toAppend); 254 | } 255 | 256 | 257 | /* This function reveals the rest of the form after the parent course is selected. It adds the remaining courses not chosen to be the 258 | parent course as check boxes.*/ 259 | function getChildren(){ 260 | var show = document.getElementById('child_list'); 261 | show.style.visibility = 'visible'; 262 | var show2 = document.getElementById('course_div'); 263 | show2.style.visibility = 'visible'; 264 | var show3 = document.getElementById('examples'); 265 | show3.style.visibility = 'visible'; 266 | var clear = document.getElementById('checkboxes'); 267 | var clear3=''; 268 | if (clear.innerHTML !== null){ 269 | clear.innerHTML = ""; 270 | } 271 | parentId = document.getElementById("jj_cross_parentCourse").value; 272 | var labelAppend = ''; 273 | var inputAppend = ''; 274 | $.each(dedupThings,function(i,o){ 275 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher" && o.id != parentId) { 276 | labelAppend += ''+''; 277 | clear3=labelAppend; 278 | if (labelAppend !== null){ 279 | labelAppend = ''; 280 | } 281 | inputAppend += '
'+clear3+'
'; 282 | } 283 | }); 284 | $('#checkboxes').append(inputAppend); 285 | } 286 | /* Users are able to change the course name. This sets the text input to wholeName.*/ 287 | function courseName(){ 288 | var newName= []; 289 | newName = $.map($('input[id="course_name"]'), function(i){return i.value; }); 290 | $.each(newName, function(index, item){ 291 | if (item !==null){ 292 | wholeName = item; 293 | } 294 | }); 295 | } 296 | 297 | /* This functions sends an API command to change the name of the parent course.*/ 298 | function updateName(){ 299 | var url = "/api/v1/courses/" + parentId + "?course[name]=" + wholeName; 300 | $.ajax({ 301 | 'cache' : false, 302 | 'url' : url , 303 | 'type' : 'PUT', 304 | }).done(function() { 305 | closeDialog(); 306 | }); 307 | } 308 | 309 | /* This function creates the modal window for the form dialog box */ 310 | function openDialog() { 311 | try { 312 | createDialog(); 313 | $('#jj_cross_dialog').dialog({ 314 | 'title' : 'Crosslist Courses', 315 | 'autoOpen' : false, 316 | 'closeOnEscape': false, 317 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 318 | 'buttons' : [ { 319 | 'text' : 'Cancel', 320 | 'click' : function() { 321 | $(this).dialog('destroy').remove(); 322 | errors = []; 323 | updateMsgs(); 324 | } 325 | },{ 326 | 'text' : 'Submit', 327 | 'class': 'Button Button--primary', 328 | 'click' : submitButton 329 | 330 | } ], 331 | 'modal' : true, 332 | 'resizable' : false, 333 | 'height' : 'auto', 334 | 'width' : '40%' 335 | }); 336 | if (!$('#jj_cross_dialog').dialog('isOpen')) { 337 | $('#jj_cross_dialog').dialog('open'); 338 | } 339 | } catch (e) { 340 | console.log(e); 341 | } 342 | } 343 | 344 | /* this function stores the courses checked in step 2 to the array variable */ 345 | function setChild() { 346 | array = $.map($('input[name="childCourses"]:checked'), function(c){return c.value; }); 347 | } 348 | /* This function sends an API command to crosslist the courses stored in the array variable with the parent course. 349 | When it's done, it will execute the function to set the course to the users dashboard and then close the window.*/ 350 | function processDialog() { 351 | $.each(array, function(index,item){ 352 | var childCourse = item; 353 | var childSection; 354 | var url = "/api/v1/courses/" + childCourse + "/sections?"; 355 | $.ajax({ 356 | 'async': true, 357 | 'type': "GET", 358 | 'global': true, 359 | 'dataType': 'JSON', 360 | 'data': JSON.stringify(childSection), 361 | 'contentType': "application/json", 362 | 'url': url, 363 | 'success': function (data) { 364 | $.each(data, function(i,o){ 365 | childSection = o.id; 366 | var url2 = "/api/v1/sections/" + childSection + "/crosslist/" + parentId +"?"; 367 | $.ajax({ 368 | 'cache' : false, 369 | 'url' : url2 , 370 | 'type' : 'POST', 371 | }).done(function() { 372 | setFavorite(); 373 | closeDialog(); 374 | }); 375 | }); 376 | } 377 | }); 378 | }); 379 | } 380 | 381 | /* Sets the course to the user's dashboard */ 382 | function setFavorite (){ 383 | var url = "/api/v1/users/self/favorites/courses/" + parentId; 384 | $.ajax({ 385 | 'cache' : false, 386 | 'url' : url , 387 | 'type' : 'POST', 388 | }); 389 | } 390 | 391 | /* If the user omits step 3, a dialog windows pops up verifying if the user doesn't want to rename the course. 392 | The confirmation button says crosslist only. If the user does want to rename, they can hit close and rename it in step 3. */ 393 | function nonameDialog(){ 394 | var el = document.querySelector('#nonamedialog'); 395 | if (!el) { 396 | el = document.createElement('div'); 397 | el.id = 'nonamedialog'; 398 | var el2 = document.createElement('div'); 399 | el.appendChild(el2); 400 | var el3 = document.createElement('p'); 401 | el3.textContent = ' No course name entered!'; 402 | el2.appendChild(el3); 403 | //direction 1 404 | var div1 = document.createElement('div'); 405 | div1.classList.add('ic-image-text-combo'); 406 | el.appendChild(div1); 407 | var icon; 408 | icon = document.createElement('i'); 409 | icon.classList.add('icon-check'); 410 | div1.appendChild(icon); 411 | var text = document.createElement('div'); 412 | text.classList.add("text-success","ic-image-text-combo__text"); 413 | text.textContent = 'Click "Crosslist Only" to continue without naming'; 414 | div1.appendChild(text); 415 | //direction 2 416 | div1 = document.createElement('div'); 417 | div1.classList.add('ic-image-text-combo'); 418 | el.appendChild(div1); 419 | icon = document.createElement('i'); 420 | icon.classList.add('icon-warning'); 421 | div1.appendChild(icon); 422 | text = document.createElement('p'); 423 | text.classList.add("text-warning","ic-image-text-combo__text"); 424 | text.textContent = 'Click "Cancel" to go back and name your course.'; 425 | div1.appendChild(text); 426 | var parent = document.querySelector('body'); 427 | parent.appendChild(el); 428 | } 429 | } 430 | /* This creates the modal window for the noname dialog box */ 431 | function opennonameDialog(){ 432 | try { 433 | nonameDialog(); 434 | $('#nonamedialog').dialog({ 435 | 'title' : 'Crosslist Courses Only', 436 | 'autoOpen' : false, 437 | 'closeOnEscape': false, 438 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); }, 439 | 'buttons' : [{ 440 | 'text' : 'Cancel', 441 | 'click' : function() { 442 | $(this).dialog('destroy').remove(); 443 | errors = []; 444 | updateMsgs(); 445 | } 446 | },{ 447 | 'text' : 'Crosslist Only', 448 | 'class': 'Button Button--primary', 449 | 'click' : processDialog 450 | } ], 451 | 'modal' : true, 452 | 'resizable' : false, 453 | 'height' : 'auto', 454 | 'width' : '40%', 455 | }); 456 | if (!$('#nonamedialog').dialog('isOpen')) { 457 | $('#nonamedialog').dialog('open'); 458 | } 459 | } catch (e) { 460 | console.log(e); 461 | } 462 | } 463 | /* If the user omits step 2, a dialog windows pops up verifying if the user doesn't want to crosslist any courses. 464 | The confirmation button says rename only. If the user does want to crosslist, they can hit close and choose courses to crosslist in step 2. */ 465 | function nocrossDialog(){ 466 | var el = document.querySelector('#nocrossdialog'); 467 | if (!el) { 468 | el = document.createElement('div'); 469 | el.id = 'nocrossdialog'; 470 | var el2 = document.createElement('div'); 471 | el.appendChild(el2); 472 | var el3 = document.createElement('p'); 473 | el3.textContent = ' No courses selected to crosslist!'; 474 | el2.appendChild(el3); 475 | //direction 1 476 | var div1 = document.createElement('div'); 477 | div1.classList.add('ic-image-text-combo'); 478 | el.appendChild(div1); 479 | var icon; 480 | icon = document.createElement('i'); 481 | icon.classList.add('icon-check'); 482 | div1.appendChild(icon); 483 | var text = document.createElement('div'); 484 | text.classList.add("text-success","ic-image-text-combo__text"); 485 | text.textContent = 'Click "Update Name" to continue without crosslisting'; 486 | div1.appendChild(text); 487 | //direction 2 488 | div1 = document.createElement('div'); 489 | div1.classList.add('ic-image-text-combo'); 490 | el.appendChild(div1); 491 | icon = document.createElement('i'); 492 | icon.classList.add('icon-warning'); 493 | div1.appendChild(icon); 494 | text = document.createElement('p'); 495 | text.classList.add("text-warning","ic-image-text-combo__text"); 496 | text.textContent = 'Click "Cancel" to go back and choose courses to crosslist.'; 497 | div1.appendChild(text); 498 | var parent = document.querySelector('body'); 499 | parent.appendChild(el); 500 | } 501 | } 502 | /* Creates the modal window for the nocross dialog box */ 503 | function opennocrossDialog(){ 504 | try { 505 | nocrossDialog(); 506 | $('#nocrossdialog').dialog({ 507 | 'title' : 'Update Course Name Only', 508 | 'autoOpen' : false, 509 | 'closeOnEscape': false, 510 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); }, 511 | 'buttons' : [ { 512 | 'text' : 'Cancel', 513 | 'click' : function() { 514 | $(this).dialog('destroy').remove(); 515 | errors = []; 516 | updateMsgs(); 517 | } 518 | },{ 519 | 'text' : 'Update Name', 520 | 'class': 'Button Button--primary', 521 | 'click' : updateName 522 | } ], 523 | 'modal' : true, 524 | 'resizable' : false, 525 | 'height' : 'auto', 526 | 'width' : '40%' 527 | }); 528 | if (!$('#nocrossdialog').dialog('isOpen')) { 529 | $('#nocrossdialog').dialog('open'); 530 | } 531 | } catch (e) { 532 | console.log(e); 533 | } 534 | } 535 | /* This function processes the request of the main crosslist dialog window. It executes the appropriate functions based on steps completed. 536 | If step 2 and step 3 are skipped, it throws an error stating to complete step 2 and or step 3. */ 537 | function submitButton(){ 538 | errors = []; 539 | courseName(); 540 | setChild(); 541 | if (wholeName !=='' || array !=+ ''){ 542 | if (wholeName !=='' && array !=+ ''){ 543 | updateName(); 544 | processDialog(); 545 | } else if (wholeName ==='' && array !=+ ''){ 546 | opennonameDialog(); 547 | }else{ 548 | opennocrossDialog(); 549 | } 550 | }else{ 551 | errors.push('You must choose a course to crosslist or input a course name.'); 552 | updateMsgs(); 553 | } 554 | } 555 | /* This function closes all dialog windows and launches a success dialog */ 556 | function closeDialog(){ 557 | $('#nocrossDialog').dialog('close'); 558 | $('#nonameDialog').dialog('close'); 559 | $('#jj_cross_dialog').dialog('close'); 560 | $('#jj_cross_dialog2').dialog('close'); 561 | window.location.reload(true); 562 | open_success_dialog(); 563 | } 564 | /* This creates error messages at the bottom of the crosslist dialog window */ 565 | function updateMsgs() { 566 | var msg = document.getElementById('jj_cross_msg'); 567 | if (!msg) { 568 | return; 569 | } 570 | if (msg.hasChildNodes()) { 571 | msg.removeChild(msg.childNodes[0]); 572 | } 573 | if (typeof errors === 'undefined' || errors.length === 0) { 574 | msg.style.display = 'none'; 575 | } else { 576 | var div1 = document.createElement('div'); 577 | div1.classList.add('ic-flash-error'); 578 | var div2; 579 | div2 = document.createElement('div'); 580 | div2.classList.add('ic-flash__icon'); 581 | div2.classList.add('aria-hidden="true"'); 582 | div1.appendChild(div2); 583 | var icon; 584 | icon = document.createElement('i'); 585 | icon.classList.add('icon-warning'); 586 | div2.appendChild(icon); 587 | var ul = document.createElement('ul'); 588 | for (var i = 0; i < errors.length; i++) { 589 | var li; 590 | li = document.createElement('li'); 591 | li.textContent = errors[i]; 592 | ul.appendChild(li); 593 | } 594 | div1.appendChild(ul); 595 | var button; 596 | button = document.createElement('button'); 597 | button.type = 'button'; 598 | button.classList.add("Button", "Button--icon-action", "close_link"); 599 | div1.appendChild(button); 600 | icon = document.createElement('i'); 601 | icon.classList.add('ic-icon-x'); 602 | icon.classList.add('aria-hidden="true"'); 603 | button.appendChild(icon); 604 | msg.appendChild(div1); 605 | msg.style.display = 'inline-block'; 606 | } 607 | } 608 | /* This creates the success dialog window */ 609 | function successDialog(){ 610 | var el = document.querySelector('#success_dialog'); 611 | if (!el) { 612 | el = document.createElement('div'); 613 | el.id = 'success_dialog'; 614 | var div1 = document.createElement('div'); 615 | div1.classList.add('ic-flash-success'); 616 | el.appendChild(div1); 617 | var div2 = document.createElement('div'); 618 | div2.classList.add('ic-flash__icon'); 619 | div2.classList.add('aria-hidden="true"'); 620 | div1.appendChild(div2); 621 | var icon = document.createElement('i'); 622 | icon.classList.add('icon-check'); 623 | div2.appendChild(icon); 624 | var msg = document.createTextNode("The action completed successfully!"); 625 | div1.appendChild(msg); 626 | var button = document.createElement('button'); 627 | button.type = 'button'; 628 | button.classList.add("Button", "Button--icon-action", "close_link"); 629 | el.appendChild(button); 630 | icon = document.createElement('i'); 631 | icon.classList.add('ic-icon-x'); 632 | icon.classList.add('aria-hidden="true"'); 633 | button.appendChild(icon); 634 | var parent = document.querySelector('body'); 635 | parent.appendChild(el); 636 | } 637 | } 638 | 639 | /* This creates the modal window for the success dialog and it closes with the page refresh in the closeDialog function */ 640 | function open_success_dialog(){ 641 | try { 642 | successDialog(); 643 | $('#success_dialog').dialog({ 644 | 'autoOpen' : false, 645 | 'closeOnEscape': false, 646 | 'open': function () { $(".ui-dialog-titlebar").hide(); $(".ui-widget-content").css("background", "rgba(255, 255, 255, 0)"); $(".ui-dialog.ui-widget-content").css("box-shadow", "none");}, 647 | 'modal' : true, 648 | 'resizable' : false, 649 | 'height' : 'auto', 650 | 'width' : '40%', 651 | }); 652 | if (!$('#success_dialog').dialog('isOpen')) { 653 | $('#success_dialog').dialog('open'); 654 | } 655 | } catch (e) { 656 | console.log(e); 657 | } 658 | } 659 | /* You can remove the following if an admin panel is not needed. I'll come add comments to this section soon! */ 660 | //Admin De-Crosslist 661 | function searchUser() { 662 | // Reset global variable errors 663 | errors = []; 664 | var userName; 665 | var el = document.getElementById('jj_cross_user'); 666 | if (el.value && el.value.trim() !== '') { 667 | userName = el.value; 668 | var url = "/api/v1" + acc + "/users?search_term=" + userName + "&per_page=100"; 669 | var userInfo; 670 | var x = document.getElementById("jj_cross_user"); 671 | if (x.className === "ic-Input") { 672 | x.style.background = "url(https://imagizer.imageshack.us/a/img922/9776/IinEAt.gif) no-repeat right center"; 673 | } 674 | $.ajax({ 675 | 'async': true, 676 | 'type': "GET", 677 | 'global': true, 678 | 'dataType': 'JSON', 679 | 'data': JSON.stringify(userInfo), 680 | 'contentType': "application/json", 681 | 'url': url, 682 | 'success': function(data){ 683 | if(data.length > 0){ 684 | var toAppend = ''; 685 | var blank = ''; 686 | var select = document.getElementById('jj_cross_chooseuser'); 687 | select.options.length = 0; // clear out existing items 688 | $.each(data,function(i,o){ 689 | var n = o.name; 690 | if (n.toUpperCase() !== n){ 691 | toAppend += ''; 692 | } 693 | }); 694 | blank += ''; 695 | $('#jj_cross_chooseuser').append(blank); 696 | $('#jj_cross_chooseuser').append(toAppend); 697 | var x = document.getElementById("jj_cross_user"); 698 | if (x.className === "ic-Input") { 699 | x.style.background = "#fff"; 700 | } 701 | }else{ 702 | errors.push('No user found'); 703 | updateMsgs(); 704 | } 705 | } 706 | }); 707 | }else { 708 | errors.push('You must type in a name.'); 709 | } 710 | updateMsgs(); 711 | } 712 | function getCoursesAdmin(){ 713 | // Reset global variable errors 714 | errors= []; 715 | user = document.getElementById('jj_cross_chooseuser').value; 716 | var url = "/api/v1/users/"+ user +"/courses?include[]=term&per_page=100"; 717 | $.ajax({ 718 | 'async': true, 719 | 'type': "GET", 720 | 'global': true, 721 | 'dataType': 'JSON', 722 | 'data': JSON.stringify(courses), 723 | 'contentType': "application/json", 724 | 'url': url, 725 | 'success': function(courses){ 726 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 727 | var toAppend = ''; 728 | var blank =''; 729 | var select2 = document.getElementById('jj_cross_parentCourse'); 730 | select2.options.length = 0; // clear out existing items 731 | termId = maxTerm(dedupThings); 732 | $.each(dedupThings, function(i, o){ 733 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher") { 734 | toAppend += ''; 735 | } 736 | }); 737 | blank += ''; 738 | $('#jj_cross_parentCourse').append(blank); 739 | $('#jj_cross_parentCourse').append(toAppend); 740 | } 741 | }); 742 | } 743 | function setParentDecross(){ 744 | // Reset global variable errors 745 | errors= []; 746 | user = document.getElementById('jj_cross_chooseuser').value; 747 | var url = "/api/v1/users/"+ user +"/courses?include[]=term&include[]=sections&per_page=100"; 748 | $.ajax({ 749 | 'async': true, 750 | 'type': "GET", 751 | 'global': true, 752 | 'dataType': 'JSON', 753 | 'data': JSON.stringify(courses), 754 | 'contentType': "application/json", 755 | 'url': url, 756 | 'success': function(courses){ 757 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 758 | var toAppend = ''; 759 | var blank =''; 760 | var select2 = document.getElementById('jj_cross_parentCourse'); 761 | select2.options.length = 0; // clear out existing items 762 | termId = maxTerm(dedupThings); 763 | $.each(dedupThings, function(i, o){ 764 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher" && o.sections.length > 1) { 765 | toAppend += ''; 766 | } 767 | }); 768 | blank += ''; 769 | $('#jj_cross_parentCourse').append(blank); 770 | $('#jj_cross_parentCourse').append(toAppend); 771 | } 772 | }); 773 | } 774 | function getSections(){ 775 | var courseSections; 776 | parentId = document.getElementById("jj_cross_parentCourse").value; 777 | var url = "/api/v1/courses/" + parentId + "/sections?"; 778 | $.ajax({ 779 | 'async': true, 780 | 'type': "GET", 781 | 'global': true, 782 | 'dataType': 'JSON', 783 | 'data': JSON.stringify(courseSections), 784 | 'contentType': "application/json", 785 | 'url': url, 786 | 'success': function (courseSections) { 787 | $.each(courseSections, function(index,item){ 788 | array = item.id; 789 | if(array !== parentId){ 790 | var url2 = "/api/v1/sections/" + array + "/crosslist/"; 791 | $.ajax({ 792 | 'cache' : false, 793 | 'url' : url2 , 794 | 'type' : 'DELETE', 795 | 796 | }).done(function() { 797 | closeDialog(); 798 | }); 799 | } 800 | }); 801 | } 802 | }); 803 | } 804 | function openDialog2() { 805 | try { 806 | createDialog2(); 807 | $('#jj_cross_dialog2').dialog({ 808 | 'title' : 'Admin De-Crosslist Tool', 809 | 'autoOpen' : false, 810 | 'closeOnEscape': false, 811 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 812 | 'buttons' : [ { 813 | 'text' : 'Cancel', 814 | 'click' : function() { 815 | $(this).dialog('destroy').remove(); 816 | errors = []; 817 | updateMsgs(); 818 | } 819 | },{ 820 | 'text' : 'Submit', 821 | 'class': 'Button Button--primary', 822 | 'click' : getSections 823 | } ], 824 | 'modal' : true, 825 | 'resizable' : false, 826 | 'height' : 'auto', 827 | 'width' : '40%', 828 | }); 829 | if (!$('#jj_cross_dialog2').dialog('isOpen')) { 830 | $('#jj_cross_dialog2').dialog('open'); 831 | } 832 | } catch (e) { 833 | console.log(e); 834 | } 835 | } 836 | function createDialog2() { 837 | var el = document.querySelector('#jj_cross_dialog2'); 838 | if (!el) { 839 | el = document.createElement('form'); 840 | el.id = 'jj_cross_dialog2'; 841 | el.classList.add("ic-Form-control","account_search_form"); 842 | var label = document.createElement('label'); 843 | label.htmlFor = 'jj_cross_user'; 844 | label.textContent = 'Search For Teacher:'; 845 | label.classList.add('ic-Label'); 846 | el.appendChild(label); 847 | var el11 = document.createElement('div'); 848 | el11.style =('margin: 0 0 10px 0'); 849 | el11.classList.add('ic-Input-group'); 850 | el.appendChild(el11); 851 | var input = document.createElement('input'); 852 | input.classList.add('ic-Input'); 853 | input.id = 'jj_cross_user'; 854 | input.type = 'text'; 855 | input.placeholder = 'Enter Teacher Name'; 856 | el11.appendChild(input); 857 | $("#jj_cross_user").keyup(function(event){ 858 | if(event.keyCode == 13){ 859 | $("#btnSearch").click(); 860 | } 861 | }); 862 | var searchButton = document.createElement('button'); 863 | searchButton.type = 'button'; 864 | searchButton.id = 'btnSearch'; 865 | searchButton.textContent = 'Search'; 866 | searchButton.onclick = searchUser; 867 | searchButton.classList.add('Button'); 868 | el11.appendChild(searchButton); 869 | //teacher dropdown 870 | label = document.createElement('label'); 871 | label.htmlFor = 'jj_cross_choosuser'; 872 | label.textContent = 'Search Results'; 873 | label.classList.add('ic-Label'); 874 | el.appendChild(label); 875 | var select = document.createElement('select'); 876 | select.id = 'jj_cross_chooseuser'; 877 | select.classList.add('ic-Input'); 878 | select.placeholder = 'Select Teacher:'; 879 | select.onchange = setParentDecross; 880 | el.appendChild(select); 881 | var el5 = document.createElement('div'); 882 | el5.classList.add('ic-Form-control'); 883 | el.appendChild(el5); 884 | var br = document.createElement('hr'); 885 | el5.appendChild(br); 886 | label = document.createElement('label'); 887 | label.htmlFor = 'jj_cross_parentCourse'; 888 | label.textContent = 'Step 1: Select Bucket Course:'; 889 | label.classList.add('ic-Label'); 890 | el5.appendChild(label); 891 | select = document.createElement('select'); 892 | select.id = 'jj_cross_parentCourse'; 893 | select.classList.add('ic-Input'); 894 | el5.appendChild(select); 895 | //message flash 896 | var msg = document.createElement('div'); 897 | msg.id = 'jj_cross_msg2'; 898 | //msg.classList.add('ic-flash-warning'); 899 | msg.style.display = 'none'; 900 | el.appendChild(msg); 901 | var parent = document.querySelector('body'); 902 | parent.appendChild(el); 903 | } 904 | } 905 | function updateMsgs2() { 906 | var msg = document.getElementById('jj_cross_msg2'); 907 | if (!msg) { 908 | return; 909 | } 910 | if (msg.hasChildNodes()) { 911 | msg.removeChild(msg.childNodes[0]); 912 | } 913 | if (typeof errors === 'undefined' || errors.length === 0) { 914 | msg.style.display = 'none'; 915 | } else { 916 | var div1 = document.createElement('div'); 917 | div1.classList.add('ic-flash-error'); 918 | var div2; 919 | div2 = document.createElement('div'); 920 | div2.classList.add('ic-flash__icon'); 921 | div2.classList.add('aria-hidden="true"'); 922 | div1.appendChild(div2); 923 | var icon; 924 | icon = document.createElement('i'); 925 | icon.classList.add('icon-warning'); 926 | div2.appendChild(icon); 927 | var ul = document.createElement('ul'); 928 | for (var i = 0; i < errors.length; i++) { 929 | var li; 930 | li = document.createElement('li'); 931 | li.textContent = errors[i]; 932 | ul.appendChild(li); 933 | } 934 | div1.appendChild(ul); 935 | var button; 936 | button = document.createElement('button'); 937 | button.type = 'button'; 938 | button.classList.add("Button", "Button--icon-action", "close_link"); 939 | div1.appendChild(button); 940 | icon = document.createElement('i'); 941 | icon.classList.add('ic-icon-x'); 942 | icon.classList.add('aria-hidden="true"'); 943 | button.appendChild(icon); 944 | msg.appendChild(div1); 945 | msg.style.display = 'inline-block'; 946 | } 947 | } 948 | //Admin Crosslist 949 | function add_buttonAdmin(){ 950 | 951 | var rightDiv = document.querySelector('div#right-side-wrapper'); 952 | rightDiv.style.display='list-item'; 953 | 954 | var parent = document.querySelector('aside#right-side'); 955 | if (parent) { 956 | var el = parent.querySelector('#jj_cross'); 957 | if (!el) { 958 | el = document.createElement('button'); 959 | el.classList.add('Button','Button--primary','button-sidebar-wide','element_toggler'); 960 | el.type = 'button'; 961 | el.id = 'jj_cross'; 962 | var icon = document.createElement('i'); 963 | icon.classList.add('icon-sis-synced'); 964 | el.appendChild(icon); 965 | var txt = document.createTextNode(' Admin Crosslist Tool'); 966 | el.appendChild(txt); 967 | el.addEventListener('click', openDialog3); 968 | parent.appendChild(el); 969 | } 970 | //decrosslist button 971 | var el2 = parent.querySelector('#jj_decross'); 972 | if (!el2) { 973 | el2 = document.createElement('button'); 974 | el2.classList.add('Button','Button--secondary','button-sidebar-wide','element_toggler'); 975 | el2.type = 'button'; 976 | el2.id = 'jj_decross'; 977 | var icon2 = document.createElement('i'); 978 | icon2.classList.add('icon-sis-not-synced'); 979 | el2.appendChild(icon2); 980 | var txt2 = document.createTextNode(' De-Crosslist Courses'); 981 | el2.appendChild(txt2); 982 | el2.addEventListener('click', openDialog2); 983 | parent.appendChild(el2); 984 | } 985 | } 986 | } 987 | function adminDialog() { 988 | var el = document.querySelector('#jj_admin_dialog'); 989 | if (!el) { 990 | //User Search 991 | el = document.createElement('form'); 992 | el.id = 'jj_admin_dialog'; 993 | el.classList.add("ic-Form-control","account_search_form"); 994 | var label = document.createElement('label'); 995 | label.htmlFor = 'jj_cross_user'; 996 | label.textContent = 'Search For Teacher:'; 997 | label.classList.add('ic-Label'); 998 | el.appendChild(label); 999 | var el11 = document.createElement('div'); 1000 | el11.style =('margin: 0 0 10px 0'); 1001 | el11.classList.add('ic-Input-group'); 1002 | el.appendChild(el11); 1003 | var input = document.createElement('input'); 1004 | input.classList.add('ic-Input'); 1005 | input.id = 'jj_cross_user'; 1006 | input.type = 'text'; 1007 | input.placeholder = 'Enter Teacher Name'; 1008 | el11.appendChild(input); 1009 | var searchButton = document.createElement('button'); 1010 | searchButton.type = 'button'; 1011 | searchButton.id = 'btnSearch'; 1012 | searchButton.textContent = 'Search'; 1013 | searchButton.onclick = searchUser; 1014 | searchButton.classList.add('Button'); 1015 | el11.appendChild(searchButton); 1016 | $("#jj_cross_user").keyup(function(event){ 1017 | if(event.keyCode == 13){ 1018 | $("#btnSearch").click(); 1019 | } 1020 | }); 1021 | //teacher dropdown 1022 | label = document.createElement('label'); 1023 | label.htmlFor = 'jj_cross_Results'; 1024 | label.textContent = 'Search Results'; 1025 | label.classList.add('ic-Label'); 1026 | el.appendChild(label); 1027 | var select = document.createElement('select'); 1028 | select.id = 'jj_cross_chooseuser'; 1029 | select.classList.add('ic-Input'); 1030 | select.placeholder = 'Select Teacher:'; 1031 | select.onchange = getCoursesAdmin; 1032 | el.appendChild(select); 1033 | var el5 = document.createElement('div'); 1034 | el5.classList.add('ic-Form-control'); 1035 | el.appendChild(el5); 1036 | var br = document.createElement('hr'); 1037 | el5.appendChild(br); 1038 | label = document.createElement('label'); 1039 | label.htmlFor = 'jj_cross_parentCourse'; 1040 | label.textContent = 'Step 1: Select Bucket Course:'; 1041 | label.classList.add('ic-Label'); 1042 | el5.appendChild(label); 1043 | select = document.createElement('select'); 1044 | select.id = 'jj_cross_parentCourse'; 1045 | select.classList.add('ic-Input'); 1046 | select.onchange = getChildren; 1047 | el5.appendChild(select); 1048 | //childcourse checkboxes 1049 | var el6 = document.createElement('fieldset'); 1050 | el6.id = 'child_list'; 1051 | el6.style.visibility = 'none'; 1052 | el6.classList.add("ic-Fieldset", "ic-Fieldset--radio-checkbox"); 1053 | el.appendChild(el6); 1054 | var el7 = document.createElement('legend'); 1055 | el7.classList.add('ic-Legend'); 1056 | el7.textContent = 'Step 2: Choose Courses to Crosslist Into Bucket Course:'; 1057 | el6.appendChild(el7); 1058 | var el8 = document.createElement('div'); 1059 | el8.id = 'checkboxes'; 1060 | el8.classList.add('ic-Checkbox-group'); 1061 | el6.appendChild(el8); 1062 | //Course Name 1063 | var el9 = document.createElement('div'); 1064 | el9.id = 'course_div'; 1065 | el9.style.visibility = 'none'; 1066 | el9.classList.add('ic-Form-control'); 1067 | el.appendChild(el9); 1068 | label = document.createElement('label'); 1069 | label.htmlFor = 'course_name'; 1070 | label.textContent = 'Step 3: Course Name:'; 1071 | label.classList.add('ic-Label'); 1072 | el9.appendChild(label); 1073 | input = document.createElement('input'); 1074 | input.id = 'course_name'; 1075 | input.classList.add('ic-Input'); 1076 | input.type = 'text'; 1077 | input.placeholder = 'Campus Initials Course Name Teacher Name (First Initial.Last Name)'; 1078 | el9.appendChild(input); 1079 | //Course Name Examples 1080 | var el10 = document.createElement('p'); 1081 | el10.id = 'examples'; 1082 | el10.style.visibility = 'none'; 1083 | el10.classList = 'text-info'; 1084 | el.appendChild(el10); 1085 | var ol = document.createElement('ol'); 1086 | ol.textContent = 'Examples:'; 1087 | ol.classList = 'unstyled'; 1088 | el10.appendChild(ol); 1089 | var li = document.createElement('li'); 1090 | li.textContent = 'KHS English III A M.Smith'; 1091 | ol.appendChild(li); 1092 | li = document.createElement('li'); 1093 | li.textContent = 'BJH Spanish 1 PreAP G.Moreno'; 1094 | ol.appendChild(li); 1095 | li = document.createElement('li'); 1096 | li.textContent = 'Elementary: KDE 4 Math G.Rorey'; 1097 | ol.appendChild(li); 1098 | //message flash 1099 | var msg = document.createElement('div'); 1100 | msg.id = 'jj_cross_msg'; 1101 | //msg.classList.add('ic-flash-warning'); 1102 | msg.style.display = 'none'; 1103 | el.appendChild(msg); 1104 | var parent = document.querySelector('body'); 1105 | parent.appendChild(el); 1106 | } 1107 | } 1108 | function openDialog3() { 1109 | try { 1110 | adminDialog(); 1111 | $('#jj_admin_dialog').dialog({ 1112 | 'title' : 'Admin Crosslist Tool', 1113 | 'autoOpen' : false, 1114 | 'closeOnEscape': false, 1115 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 1116 | 'buttons' : [ { 1117 | 'text' : 'Cancel', 1118 | 'click' : function() { 1119 | $(this).dialog('destroy').remove(); 1120 | errors = []; 1121 | updateMsgs(); 1122 | } 1123 | },{ 1124 | 'text' : 'Submit', 1125 | 'class': 'Button Button--primary', 1126 | 'click' : submitButton 1127 | } ], 1128 | 'modal' : true, 1129 | 'resizable' : false, 1130 | 'height' : 'auto', 1131 | 'width' : '40%', 1132 | }); 1133 | if (!$('#jj_admin_dialog').dialog('isOpen')) { 1134 | $('#jj_admin_dialog').dialog('open'); 1135 | } 1136 | } catch (e) { 1137 | console.log(e); 1138 | } 1139 | } 1140 | /* Remove to here if the admin panel isn't needed */ 1141 | })(); 1142 | -------------------------------------------------------------------------------- /KatyISD Specific Scripts/KatyISD specific crosslisting with admin crosslisting and decrosslisting tool: -------------------------------------------------------------------------------- 1 | /* globals jQuery, $, waitForKeyElements */ 2 | // ==UserScript== 3 | // @name KatyISD Instructor and Admin Crosslisting/Decrosslisting Tools 4 | // @namespace https://github.com/sukotsuchido/CanvasUserScripts 5 | // @version 2.4 6 | // @description A Canvas UserScript to facilitate crosslisting of courses. 7 | // @author Chad Scott (ChadScott@katyisd.org) 8 | // @include https://*.instructure.com/courses 9 | // @include https://*.instructure.com/accounts/* 10 | // @require https://code.jquery.com/jquery-3.4.1.min.js 11 | // @grant none 12 | // ==/UserScript== 13 | (function() { 14 | 'use strict'; 15 | var assocRegex = new RegExp('^/courses$'); 16 | var assocRegex2 = new RegExp('^/accounts/([0-9]+)$'); 17 | var acc = window.location.pathname; 18 | var errors = []; 19 | var parentId = []; 20 | var termId = ''; 21 | var maxValue = 1; 22 | var courses = {}; 23 | var dedupThings = []; 24 | var wholeName = ''; 25 | var array =[]; 26 | var user = ''; 27 | /* role setup */ 28 | 29 | if( (assocRegex.test(window.location.pathname))){ 30 | var roles = ENV.current_user_roles; 31 | var cxbuttonRoles = ["admin", "teacher", "root_admin"]; 32 | var test1 = cxbuttonRoles.some(el => roles.includes(el)); 33 | if(test1===true){ 34 | getCourses(); 35 | } 36 | } 37 | if( (assocRegex2.test(window.location.pathname))){ 38 | var roles2 = ENV.current_user_roles; 39 | var admincxbuttonRoles = ["root_admin"]; 40 | var test2 = admincxbuttonRoles.some(el => roles2.includes(el)); 41 | if(test2===true){ 42 | add_buttonAdmin(); 43 | } 44 | } 45 | function add_button() { 46 | var parent = document.querySelector('div.ic-Action-header__Secondary'); 47 | if (parent) { 48 | var el = parent.querySelector('#cs_cross'); 49 | if (!el) { 50 | el = document.createElement('button'); 51 | el.classList.add('Button','element_toggler'); 52 | el.type = 'button'; 53 | el.id = 'cs_cross'; 54 | var icon = document.createElement('i'); 55 | icon.classList.add('icon-sis-synced'); 56 | el.appendChild(icon); 57 | var txt = document.createTextNode(' Crosslist Courses'); 58 | el.appendChild(txt); 59 | el.addEventListener('click', openDialog); 60 | parent.appendChild(el); 61 | } 62 | } 63 | } 64 | function createDialog() { 65 | var el = document.querySelector('#cs_cross_dialog'); 66 | if (!el) { 67 | el = document.createElement('form'); 68 | el.id = 'cs_cross_dialog'; 69 | el.classList.add('ic-Form-group'); 70 | //Parent Course selection 71 | var help = document.createElement('div'); 72 | help.innerHTML = '
Directions: Complete for each step to crosslist and rename your courses.
Click OPTIONS for more information about Crosslisting.
Options
'; 73 | help.classList.add('ic-Label'); 74 | el.appendChild(help); 75 | var el5 = document.createElement('div'); 76 | el5.classList.add('ic-Form-control'); 77 | el.appendChild(el5); 78 | var label = document.createElement('label'); 79 | label.htmlFor = 'cs_cross_parentCourse'; 80 | label.innerHTML = 'Step 1: Select Bucket Course (Hover over step for more help)'; 81 | label.classList.add('ic-Label'); 82 | el5.appendChild(label); 83 | var select = document.createElement('select'); 84 | select.id = 'cs_cross_parentCourse'; 85 | select.classList.add('ic-Input'); 86 | select.onchange = getChildren; 87 | el5.appendChild(select); 88 | //childcourse checkboxes 89 | var el6 = document.createElement('fieldset'); 90 | el6.id = 'child_list'; 91 | el6.style.visibility = 'hidden'; 92 | el6.classList.add("ic-Fieldset", "ic-Fieldset--radio-checkbox"); 93 | el.appendChild(el6); 94 | var el7 = document.createElement('legend'); 95 | el7.classList.add('ic-Legend'); 96 | el7.innerHTML = 'Step 2: Choose Courses to Crosslist Into Bucket Course (Hover over step for more help)'; 97 | el6.appendChild(el7); 98 | var el8 = document.createElement('div'); 99 | el8.id = 'checkboxes'; 100 | el8.classList.add('ic-Checkbox-group'); 101 | el6.appendChild(el8); 102 | //Course Name 103 | var el9 = document.createElement('div'); 104 | el9.id = 'course_div'; 105 | el9.style.visibility = 'hidden'; 106 | el9.classList.add('ic-Form-control'); 107 | el.appendChild(el9); 108 | label = document.createElement('label'); 109 | label.htmlFor = 'course_name'; 110 | label.innerHTML = ' Step 3: Set Course Name (Hover over step for more help)'; 111 | label.classList.add('ic-Label'); 112 | el9.appendChild(label); 113 | var input = document.createElement('input'); 114 | input.id = 'course_name'; 115 | input.classList.add('ic-Input'); 116 | input.type = 'text'; 117 | //input.placeholder = 'Campus Initials Course Name Teacher Name (First Initial.Last Name)'; 118 | el9.appendChild(input); 119 | //Course Name Examples 120 | var el10 = document.createElement('p'); 121 | el10.id = 'examples'; 122 | el10.style.visibility = 'hidden'; 123 | el10.classList = 'text-info'; 124 | el.appendChild(el10); 125 | var ol = document.createElement('ol'); 126 | ol.textContent = 'Examples:'; 127 | //ol.style.border = "thin solid #0000FF"; 128 | ol.classList = 'unstyled'; 129 | el10.appendChild(ol); 130 | var li = document.createElement('li'); 131 | li.textContent = 'KHS English 3 A M.Smith'; 132 | ol.appendChild(li); 133 | li = document.createElement('li'); 134 | li.textContent = 'BJH 8 Science KAP G.Moreno'; 135 | ol.appendChild(li); 136 | li = document.createElement('li'); 137 | li.textContent = 'KDE 4 Math G.Rorey'; 138 | ol.appendChild(li); 139 | //message flash 140 | var msg = document.createElement('div'); 141 | msg.id = 'cs_cross_msg'; 142 | //msg.classList.add('ic-flash-warning'); 143 | msg.style.display = 'none'; 144 | el.appendChild(msg); 145 | var parent = document.querySelector('body'); 146 | parent.appendChild(el); 147 | } 148 | setParent(); 149 | document.getElementById("action_helper").addEventListener("click", function(){ 150 | openHelp(); 151 | }); 152 | } 153 | function createhelpDialog(){ 154 | var el = document.querySelector('#help_dialog'); 155 | if (!el) { 156 | el = document.createElement('div'); 157 | el.innerHTML= '
Crosslist and Name Course: Complete all 3 steps
Crosslist and Don\'t Rename Course: Complete steps 1 and 2
Only Rename Course: Complete steps 1 and 3

Hover over each step for more help.
'; 158 | el.id = 'help_dialog'; 159 | //Parent Course selection 160 | //message flash 161 | var msg = document.createElement('div'); 162 | msg.id = 'cs_cross_msg'; 163 | //msg.classList.add('ic-flash-warning'); 164 | msg.style.display = 'none'; 165 | el.appendChild(msg); 166 | var parent = document.querySelector('body'); 167 | parent.appendChild(el); 168 | } 169 | } 170 | function openHelp() { 171 | try { 172 | createhelpDialog(); 173 | $('#help_dialog').dialog({ 174 | 'title' : 'Possible Actions', 175 | 'autoOpen' : false, 176 | 'closeOnEscape': false, 177 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 178 | 'buttons' : [ { 179 | 'text' : 'Close', 180 | 'click' : function() { 181 | $(this).dialog('destroy').remove(); 182 | } 183 | } ], 184 | 'modal' : true, 185 | 'resizable' : false, 186 | 'height' : 'auto', 187 | 'width' : '30%' 188 | }); 189 | if (!$('#help_dialog').dialog('isOpen')) { 190 | $('#help_dialog').dialog('open'); 191 | } 192 | } catch (e) { 193 | console.log(e); 194 | } 195 | } 196 | function getCourses(){ 197 | // Reset global variable errors 198 | errors= []; 199 | var url = "/api/v1/users/self/courses?inlcude[]=term&per_page=100"; 200 | $.ajax({ 201 | 'async': true, 202 | 'type': "GET", 203 | 'global': true, 204 | 'dataType': 'JSON', 205 | 'data': JSON.stringify(courses), 206 | 'contentType': "application/json", 207 | 'url': url, 208 | 'success': function(courses){ 209 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 210 | add_button(); 211 | } 212 | }); 213 | } 214 | function maxTerm(dedupThings){ 215 | for(var i=0;i maxValue){ 217 | maxValue = Number(dedupThings[i].enrollment_term_id); 218 | } 219 | } 220 | return maxValue; 221 | } 222 | 223 | /* This function takes the return from getTerm and then filters the courses for only that term id and sets the courses in the dropdown. */ 224 | function setParent(){ 225 | var toAppend = ''; 226 | var select = document.getElementById('cs_cross_parentCourse'); 227 | select.options.length = 0; // clear out existing items 228 | termId = maxTerm(dedupThings); 229 | $.each(dedupThings, function(i, o){ 230 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher") { 231 | toAppend += ''; 232 | } 233 | }); 234 | var blank =''; 235 | blank += ''; 236 | $('#cs_cross_parentCourse').append(blank); 237 | $('#cs_cross_parentCourse').append(toAppend); 238 | } 239 | 240 | function getChildren(){ 241 | var show = document.getElementById('child_list'); 242 | show.style.visibility = 'visible'; 243 | var show2 = document.getElementById('course_div'); 244 | show2.style.visibility = 'visible'; 245 | var show3 = document.getElementById('examples'); 246 | show3.style.visibility = 'visible'; 247 | var clear = document.getElementById('checkboxes'); 248 | var clear3=''; 249 | if (clear.innerHTML !== null){ 250 | clear.innerHTML = ""; 251 | } 252 | parentId = document.getElementById("cs_cross_parentCourse").value; 253 | var labelAppend = ''; 254 | var inputAppend = ''; 255 | $.each(dedupThings,function(i,o){ 256 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher" && o.id != parentId) { 257 | labelAppend += ''+''; 258 | clear3=labelAppend; 259 | if (labelAppend !== null){ 260 | labelAppend = ''; 261 | } 262 | inputAppend += '
'+clear3+'
'; 263 | } 264 | }); 265 | $('#checkboxes').append(inputAppend); 266 | } 267 | function courseName(){ 268 | var newName= []; 269 | newName = $.map($('input[id="course_name"]'), function(i){return i.value; }); 270 | $.each(newName, function(index, item){ 271 | if (item !==null){ 272 | wholeName = item; 273 | } 274 | }); 275 | } 276 | function updateName(){ 277 | var url = "/api/v1/courses/" + parentId + "?course[name]=" + wholeName; 278 | $.ajax({ 279 | 'cache' : false, 280 | 'url' : url , 281 | 'type' : 'PUT', 282 | }).done(function() { 283 | closeDialog(); 284 | }); 285 | } 286 | /* This function gets the course code to update it. */ 287 | function updatecourseCode(){ 288 | var courseCode = ''; 289 | var url = "/api/v1/courses/" + parentId; 290 | $.ajax({ 291 | 'async': true, 292 | 'type': "GET", 293 | 'global': true, 294 | 'dataType': 'JSON', 295 | 'data': JSON.stringify(courseCode), 296 | 'contentType': "application/json", 297 | 'url': url, 298 | 'success': function data (i,o) { 299 | 300 | courseCode = i.course_code; 301 | 302 | var newcourseCode = courseCode.replace(/^[^A-Z]+/,'').replace(/\s\((.*)\)/g,''); 303 | console.log(newcourseCode); 304 | var url2 = "/api/v1/courses/" + parentId + "?course[course_code]=" + newcourseCode; 305 | $.ajax({ 306 | 'cache' : false, 307 | 'url' : url2 , 308 | 'type' : 'PUT', 309 | }); 310 | }, 311 | }); 312 | } 313 | function openDialog() { 314 | try { 315 | createDialog(); 316 | var wWidth = $(window).width(); 317 | var dWidth = wWidth * 0.4; 318 | var wHeight = $(window).height(); 319 | var dHeight = wHeight * 0.8; 320 | $('#cs_cross_dialog').dialog({ 321 | 'title' : 'Crosslist Courses', 322 | 'autoOpen' : false, 323 | 'closeOnEscape': true, 324 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 325 | 'buttons' : [ { 326 | 'text' : 'Cancel', 327 | 'click' : function() { 328 | $(this).dialog('destroy').remove(); 329 | errors = []; 330 | updateMsgs(); 331 | } 332 | },{ 333 | 'text' : 'Submit', 334 | 'class': 'Button Button--primary', 335 | 'click' : submitButton 336 | 337 | } ], 338 | 'modal' : true, 339 | 'resizable' : false, 340 | 'height' : dHeight, 341 | 'width' : dWidth 342 | }); 343 | if (!$('#cs_cross_dialog').dialog('isOpen')) { 344 | $('#cs_cross_dialog').dialog('open'); 345 | } 346 | } catch (e) { 347 | console.log(e); 348 | } 349 | } 350 | function setChild() { 351 | array = $.map($('input[name="childCourses"]:checked'), function(c){return c.value; }); 352 | } 353 | function processDialog() { 354 | $.each(array, function(index,item){ 355 | var childCourse = item; 356 | var childSection; 357 | var url = "/api/v1/courses/" + childCourse + "/sections?"; 358 | $.ajax({ 359 | 'async': true, 360 | 'type': "GET", 361 | 'global': true, 362 | 'dataType': 'JSON', 363 | 'data': JSON.stringify(childSection), 364 | 'contentType': "application/json", 365 | 'url': url, 366 | 'success': function (data) { 367 | $.each(data, function(i,o){ 368 | childSection = o.id; 369 | var url2 = "/api/v1/sections/" + childSection + "/crosslist/" + parentId +"?"; 370 | $.ajax({ 371 | 'cache' : false, 372 | 'url' : url2 , 373 | 'type' : 'POST', 374 | }).done(function() { 375 | closeDialog(); 376 | }); 377 | }); 378 | } 379 | }); 380 | }); 381 | } 382 | function setFavorite (){ 383 | var url = "/api/v1/users/self/favorites/courses/" + parentId; 384 | $.ajax({ 385 | 'cache' : false, 386 | 'url' : url , 387 | 'type' : 'POST', 388 | }); 389 | } 390 | function nonameDialog(){ 391 | var el = document.querySelector('#nonamedialog'); 392 | if (!el) { 393 | el = document.createElement('div'); 394 | el.id = 'nonamedialog'; 395 | var el2 = document.createElement('div'); 396 | el.appendChild(el2); 397 | var el3 = document.createElement('p'); 398 | el3.textContent = ' No course name entered!'; 399 | el2.appendChild(el3); 400 | //direction 1 401 | var div1 = document.createElement('div'); 402 | div1.classList.add('ic-image-text-combo'); 403 | el.appendChild(div1); 404 | var icon; 405 | icon = document.createElement('i'); 406 | icon.classList.add('icon-check'); 407 | div1.appendChild(icon); 408 | var text = document.createElement('div'); 409 | text.classList.add("text-success","ic-image-text-combo__text"); 410 | text.textContent = 'Click "Crosslist Only" to continue without naming'; 411 | div1.appendChild(text); 412 | //direction 2 413 | div1 = document.createElement('div'); 414 | div1.classList.add('ic-image-text-combo'); 415 | el.appendChild(div1); 416 | icon = document.createElement('i'); 417 | icon.classList.add('icon-warning'); 418 | div1.appendChild(icon); 419 | text = document.createElement('p'); 420 | text.classList.add("text-warning","ic-image-text-combo__text"); 421 | text.textContent = 'Click "Cancel" to go back and name your course.'; 422 | div1.appendChild(text); 423 | var parent = document.querySelector('body'); 424 | parent.appendChild(el); 425 | } 426 | } 427 | function opennonameDialog(){ 428 | try { 429 | nonameDialog(); 430 | $('#nonamedialog').dialog({ 431 | 'title' : 'Crosslist Courses Only', 432 | 'autoOpen' : false, 433 | 'closeOnEscape': false, 434 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); }, 435 | 'buttons' : [{ 436 | 'text' : 'Cancel', 437 | 'click' : function() { 438 | $(this).dialog('destroy').remove(); 439 | errors = []; 440 | updateMsgs(); 441 | } 442 | },{ 443 | 'text' : 'Crosslist Only', 444 | 'class': 'Button Button--primary', 445 | 'click' : processDialog 446 | } ], 447 | 'modal' : true, 448 | 'resizable' : false, 449 | 'height' : 'auto', 450 | 'width' : '40%', 451 | }); 452 | if (!$('#nonamedialog').dialog('isOpen')) { 453 | $('#nonamedialog').dialog('open'); 454 | } 455 | } catch (e) { 456 | console.log(e); 457 | } 458 | } 459 | function nocrossDialog(){ 460 | var el = document.querySelector('#nocrossdialog'); 461 | if (!el) { 462 | el = document.createElement('div'); 463 | el.id = 'nocrossdialog'; 464 | var el2 = document.createElement('div'); 465 | el.appendChild(el2); 466 | var el3 = document.createElement('p'); 467 | el3.textContent = ' No courses selected to crosslist!'; 468 | el2.appendChild(el3); 469 | //direction 1 470 | var div1 = document.createElement('div'); 471 | div1.classList.add('ic-image-text-combo'); 472 | el.appendChild(div1); 473 | var icon; 474 | icon = document.createElement('i'); 475 | icon.classList.add('icon-check'); 476 | div1.appendChild(icon); 477 | var text = document.createElement('div'); 478 | text.classList.add("text-success","ic-image-text-combo__text"); 479 | text.textContent = 'Click "Update Name" to continue without crosslisting'; 480 | div1.appendChild(text); 481 | //direction 2 482 | div1 = document.createElement('div'); 483 | div1.classList.add('ic-image-text-combo'); 484 | el.appendChild(div1); 485 | icon = document.createElement('i'); 486 | icon.classList.add('icon-warning'); 487 | div1.appendChild(icon); 488 | text = document.createElement('p'); 489 | text.classList.add("text-warning","ic-image-text-combo__text"); 490 | text.textContent = 'Click "Cancel" to go back and choose courses to crosslist.'; 491 | div1.appendChild(text); 492 | var parent = document.querySelector('body'); 493 | parent.appendChild(el); 494 | } 495 | } 496 | function opennocrossDialog(){ 497 | try { 498 | nocrossDialog(); 499 | $('#nocrossdialog').dialog({ 500 | 'title' : 'Update Course Name Only', 501 | 'autoOpen' : false, 502 | 'closeOnEscape': false, 503 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); }, 504 | 'buttons' : [ { 505 | 'text' : 'Cancel', 506 | 'click' : function() { 507 | $(this).dialog('destroy').remove(); 508 | errors = []; 509 | updateMsgs(); 510 | } 511 | },{ 512 | 'text' : 'Update Name', 513 | 'class': 'Button Button--primary', 514 | 'click' : updateName 515 | } ], 516 | 'modal' : true, 517 | 'resizable' : false, 518 | 'height' : 'auto', 519 | 'width' : '40%' 520 | }); 521 | if (!$('#nocrossdialog').dialog('isOpen')) { 522 | $('#nocrossdialog').dialog('open'); 523 | } 524 | } catch (e) { 525 | console.log(e); 526 | } 527 | } 528 | function submitButton(){ 529 | errors = []; 530 | courseName(); 531 | setChild(); 532 | if (wholeName !=='' || array !=+ ''){ 533 | if (wholeName !=='' && array !=+ ''){ 534 | updateName(); 535 | updatecourseCode(); 536 | setFavorite(); 537 | processDialog(); 538 | } else if (wholeName ==='' && array !=+ ''){ 539 | updatecourseCode(); 540 | setFavorite(); 541 | opennonameDialog(); 542 | }else{ 543 | updatecourseCode(); 544 | setFavorite(); 545 | opennocrossDialog(); 546 | } 547 | }else{ 548 | errors.push('You must choose a course to crosslist or input a course name.'); 549 | updateMsgs(); 550 | } 551 | } 552 | function closeDialog(){ 553 | $('#nocrossDialog').dialog('close'); 554 | $('#nonameDialog').dialog('close'); 555 | $('#cs_cross_dialog').dialog('close'); 556 | $('#cs_cross_dialog2').dialog('close'); 557 | window.location.reload(true); 558 | open_success_dialog(); 559 | } 560 | function updateMsgs() { 561 | var msg = document.getElementById('cs_cross_msg'); 562 | if (!msg) { 563 | return; 564 | } 565 | if (msg.hasChildNodes()) { 566 | msg.removeChild(msg.childNodes[0]); 567 | } 568 | if (typeof errors === 'undefined' || errors.length === 0) { 569 | msg.style.display = 'none'; 570 | } else { 571 | var div1 = document.createElement('div'); 572 | div1.classList.add('ic-flash-error'); 573 | var div2; 574 | div2 = document.createElement('div'); 575 | div2.classList.add('ic-flash__icon'); 576 | div2.classList.add('aria-hidden="true"'); 577 | div1.appendChild(div2); 578 | var icon; 579 | icon = document.createElement('i'); 580 | icon.classList.add('icon-warning'); 581 | div2.appendChild(icon); 582 | var ul = document.createElement('ul'); 583 | for (var i = 0; i < errors.length; i++) { 584 | var li; 585 | li = document.createElement('li'); 586 | li.textContent = errors[i]; 587 | ul.appendChild(li); 588 | } 589 | div1.appendChild(ul); 590 | var button; 591 | button = document.createElement('button'); 592 | button.type = 'button'; 593 | button.classList.add("Button", "Button--icon-action", "close_link"); 594 | div1.appendChild(button); 595 | icon = document.createElement('i'); 596 | icon.classList.add('ic-icon-x'); 597 | icon.classList.add('aria-hidden="true"'); 598 | button.appendChild(icon); 599 | msg.appendChild(div1); 600 | msg.style.display = 'inline-block'; 601 | } 602 | } 603 | function successDialog(){ 604 | var el = document.querySelector('#success_dialog'); 605 | if (!el) { 606 | el = document.createElement('div'); 607 | el.id = 'success_dialog'; 608 | var div1 = document.createElement('div'); 609 | div1.classList.add('ic-flash-success'); 610 | el.appendChild(div1); 611 | var div2 = document.createElement('div'); 612 | div2.classList.add('ic-flash__icon'); 613 | div2.classList.add('aria-hidden="true"'); 614 | div1.appendChild(div2); 615 | var icon = document.createElement('i'); 616 | icon.classList.add('icon-check'); 617 | div2.appendChild(icon); 618 | var msg = document.createTextNode("The action completed successfully!"); 619 | div1.appendChild(msg); 620 | var button = document.createElement('button'); 621 | button.type = 'button'; 622 | button.classList.add("Button", "Button--icon-action", "close_link"); 623 | el.appendChild(button); 624 | icon = document.createElement('i'); 625 | icon.classList.add('ic-icon-x'); 626 | icon.classList.add('aria-hidden="true"'); 627 | button.appendChild(icon); 628 | var parent = document.querySelector('body'); 629 | parent.appendChild(el); 630 | } 631 | } 632 | function open_success_dialog(){ 633 | try { 634 | successDialog(); 635 | $('#success_dialog').dialog({ 636 | 'autoOpen' : false, 637 | 'closeOnEscape': false, 638 | 'open': function () { $(".ui-dialog-titlebar").hide(); $(".ui-widget-content").css("background", "rgba(255, 255, 255, 0)"); $(".ui-dialog.ui-widget-content").css("box-shadow", "none");}, 639 | 'modal' : true, 640 | 'resizable' : false, 641 | 'height' : 'auto', 642 | 'width' : '40%', 643 | }); 644 | if (!$('#success_dialog').dialog('isOpen')) { 645 | $('#success_dialog').dialog('open'); 646 | } 647 | } catch (e) { 648 | console.log(e); 649 | } 650 | } 651 | //Admin De-Crosslist 652 | function searchUser() { 653 | // Reset global variable errors 654 | errors = []; 655 | var userName; 656 | var el = document.getElementById('cs_cross_user'); 657 | if (el.value && el.value.trim() !== '') { 658 | userName = el.value; 659 | var url = "/api/v1" + acc + "/users?search_term=" + userName + "&per_page=100"; 660 | var userInfo; 661 | var x = document.getElementById("cs_cross_user"); 662 | if (x.className === "ic-Input") { 663 | x.style.background = "url(https://imagizer.imageshack.us/a/img922/9776/IinEAt.gif) no-repeat right center"; 664 | } 665 | $.ajax({ 666 | 'async': true, 667 | 'type': "GET", 668 | 'global': true, 669 | 'dataType': 'JSON', 670 | 'data': JSON.stringify(userInfo), 671 | 'contentType': "application/json", 672 | 'url': url, 673 | 'success': function(data){ 674 | if(data.length > 0){ 675 | var toAppend = ''; 676 | var blank = ''; 677 | var select = document.getElementById('cs_cross_chooseuser'); 678 | select.options.length = 0; // clear out existing items 679 | $.each(data,function(i,o){ 680 | var n = o.name; 681 | if (n.toUpperCase() !== n){ 682 | toAppend += ''; 683 | } 684 | }); 685 | blank += ''; 686 | $('#cs_cross_chooseuser').append(blank); 687 | $('#cs_cross_chooseuser').append(toAppend); 688 | var x = document.getElementById("cs_cross_user"); 689 | if (x.className === "ic-Input") { 690 | x.style.background = "#fff"; 691 | } 692 | }else{ 693 | errors.push('No user found'); 694 | updateMsgs(); 695 | } 696 | } 697 | }); 698 | }else { 699 | errors.push('You must type in a name.'); 700 | } 701 | updateMsgs(); 702 | } 703 | function getCoursesAdmin(){ 704 | // Reset global variable errors 705 | errors= []; 706 | user = document.getElementById('cs_cross_chooseuser').value; 707 | var url = "/api/v1/users/"+ user +"/courses?enrollment_state[]=active&per_page=100&include[]=term"; 708 | $.ajax({ 709 | 'async': true, 710 | 'type': "GET", 711 | 'global': true, 712 | 'dataType': 'JSON', 713 | 'data': JSON.stringify(courses), 714 | 'contentType': "application/json", 715 | 'url': url, 716 | 'success': function(courses){ 717 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 718 | var toAppend = ''; 719 | var blank =''; 720 | var select2 = document.getElementById('cs_cross_parentCourse'); 721 | select2.options.length = 0; // clear out existing items 722 | termId = maxTerm(dedupThings); 723 | $.each(dedupThings, function(i, o){ 724 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher") { 725 | toAppend += ''; 726 | } 727 | }); 728 | blank += ''; 729 | $('#cs_cross_parentCourse').append(blank); 730 | $('#cs_cross_parentCourse').append(toAppend); 731 | } 732 | }); 733 | } 734 | function setParentDecross(){ 735 | // Reset global variable errors 736 | errors= []; 737 | user = document.getElementById('cs_cross_chooseuser').value; 738 | var url = "/api/v1/users/"+ user +"/courses?per_page=100&include[]=term&include[]=sections"; 739 | $.ajax({ 740 | 'async': true, 741 | 'type': "GET", 742 | 'global': true, 743 | 'dataType': 'JSON', 744 | 'data': JSON.stringify(courses), 745 | 'contentType': "application/json", 746 | 'url': url, 747 | 'success': function(courses){ 748 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 749 | var toAppend = ''; 750 | var blank =''; 751 | var select2 = document.getElementById('cs_cross_parentCourse'); 752 | select2.options.length = 0; // clear out existing items 753 | termId = maxTerm(dedupThings); 754 | $.each(dedupThings, function(i, o){ 755 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher" && o.sections.length > 1) { 756 | toAppend += ''; 757 | } 758 | }); 759 | blank += ''; 760 | $('#cs_cross_parentCourse').append(blank); 761 | $('#cs_cross_parentCourse').append(toAppend); 762 | } 763 | }); 764 | } 765 | function getSections(){ 766 | var courseSections; 767 | parentId = document.getElementById("cs_cross_parentCourse").value; 768 | var url = "/api/v1/courses/" + parentId + "/sections?"; 769 | $.ajax({ 770 | 'async': true, 771 | 'type': "GET", 772 | 'global': true, 773 | 'dataType': 'JSON', 774 | 'data': JSON.stringify(courseSections), 775 | 'contentType': "application/json", 776 | 'url': url, 777 | 'success': function (courseSections) { 778 | $.each(courseSections, function(index,item){ 779 | array = item.id; 780 | if(array !== parentId){ 781 | var url2 = "/api/v1/sections/" + array + "/crosslist/"; 782 | $.ajax({ 783 | 'cache' : false, 784 | 'url' : url2 , 785 | 'type' : 'DELETE', 786 | 787 | }).done(function() { 788 | closeDialog(); 789 | }); 790 | } 791 | }); 792 | } 793 | }); 794 | } 795 | function openDialog2() { 796 | try { 797 | createDialog2(); 798 | var wWidth = $(window).width(); 799 | var dWidth = wWidth * 0.4; 800 | var wHeight = $(window).height(); 801 | var dHeight = wHeight * 0.8; 802 | $('#cs_cross_dialog2').dialog({ 803 | 'title' : 'Admin De-Crosslist Tool', 804 | 'autoOpen' : false, 805 | 'closeOnEscape': true, 806 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 807 | 'buttons' : [ { 808 | 'text' : 'Cancel', 809 | 'click' : function() { 810 | $(this).dialog('destroy').remove(); 811 | errors = []; 812 | updateMsgs(); 813 | } 814 | },{ 815 | 'text' : 'Submit', 816 | 'class': 'Button Button--primary', 817 | 'click' : getSections 818 | } ], 819 | 'modal' : true, 820 | 'resizable' : false, 821 | 'height' : dHeight, 822 | 'width' : dWidth, 823 | }); 824 | if (!$('#cs_cross_dialog2').dialog('isOpen')) { 825 | $('#cs_cross_dialog2').dialog('open'); 826 | } 827 | } catch (e) { 828 | console.log(e); 829 | } 830 | } 831 | function createDialog2() { 832 | var el = document.querySelector('#cs_cross_dialog2'); 833 | if (!el) { 834 | el = document.createElement('form'); 835 | el.id = 'cs_cross_dialog2'; 836 | el.classList.add("ic-Form-control","account_search_form"); 837 | var label = document.createElement('label'); 838 | label.htmlFor = 'cs_cross_user'; 839 | label.textContent = 'Search For Teacher:'; 840 | label.classList.add('ic-Label'); 841 | el.appendChild(label); 842 | var el11 = document.createElement('div'); 843 | el11.style =('margin: 0 0 10px 0'); 844 | el11.classList.add('ic-Input-group'); 845 | el.appendChild(el11); 846 | var input = document.createElement('input'); 847 | input.classList.add('ic-Input'); 848 | input.id = 'cs_cross_user'; 849 | input.type = 'text'; 850 | input.placeholder = 'Enter Teacher Name'; 851 | el11.appendChild(input); 852 | $("#cs_cross_user").keyup(function(event){ 853 | if(event.keyCode == 13){ 854 | $("#btnSearch").click(); 855 | } 856 | }); 857 | var searchButton = document.createElement('button'); 858 | searchButton.type = 'button'; 859 | searchButton.id = 'btnSearch'; 860 | searchButton.textContent = 'Search'; 861 | searchButton.onclick = searchUser; 862 | searchButton.classList.add('Button'); 863 | el11.appendChild(searchButton); 864 | //teacher dropdown 865 | label = document.createElement('label'); 866 | label.htmlFor = 'cs_cross_choosuser'; 867 | label.textContent = 'Search Results'; 868 | label.classList.add('ic-Label'); 869 | el.appendChild(label); 870 | var select = document.createElement('select'); 871 | select.id = 'cs_cross_chooseuser'; 872 | select.classList.add('ic-Input'); 873 | select.placeholder = 'Select Teacher:'; 874 | select.onchange = setParentDecross; 875 | el.appendChild(select); 876 | var el5 = document.createElement('div'); 877 | el5.classList.add('ic-Form-control'); 878 | el.appendChild(el5); 879 | var br = document.createElement('hr'); 880 | el5.appendChild(br); 881 | label = document.createElement('label'); 882 | label.htmlFor = 'cs_cross_parentCourse'; 883 | label.textContent = 'Step 1: Select Bucket Course:'; 884 | label.classList.add('ic-Label'); 885 | el5.appendChild(label); 886 | select = document.createElement('select'); 887 | select.id = 'cs_cross_parentCourse'; 888 | select.classList.add('ic-Input'); 889 | el5.appendChild(select); 890 | //message flash 891 | var msg = document.createElement('div'); 892 | msg.id = 'cs_cross_msg2'; 893 | //msg.classList.add('ic-flash-warning'); 894 | msg.style.display = 'none'; 895 | el.appendChild(msg); 896 | var parent = document.querySelector('body'); 897 | parent.appendChild(el); 898 | } 899 | } 900 | function updateMsgs2() { 901 | var msg = document.getElementById('cs_cross_msg2'); 902 | if (!msg) { 903 | return; 904 | } 905 | if (msg.hasChildNodes()) { 906 | msg.removeChild(msg.childNodes[0]); 907 | } 908 | if (typeof errors === 'undefined' || errors.length === 0) { 909 | msg.style.display = 'none'; 910 | } else { 911 | var div1 = document.createElement('div'); 912 | div1.classList.add('ic-flash-error'); 913 | var div2; 914 | div2 = document.createElement('div'); 915 | div2.classList.add('ic-flash__icon'); 916 | div2.classList.add('aria-hidden="true"'); 917 | div1.appendChild(div2); 918 | var icon; 919 | icon = document.createElement('i'); 920 | icon.classList.add('icon-warning'); 921 | div2.appendChild(icon); 922 | var ul = document.createElement('ul'); 923 | for (var i = 0; i < errors.length; i++) { 924 | var li; 925 | li = document.createElement('li'); 926 | li.textContent = errors[i]; 927 | ul.appendChild(li); 928 | } 929 | div1.appendChild(ul); 930 | var button; 931 | button = document.createElement('button'); 932 | button.type = 'button'; 933 | button.classList.add("Button", "Button--icon-action", "close_link"); 934 | div1.appendChild(button); 935 | icon = document.createElement('i'); 936 | icon.classList.add('ic-icon-x'); 937 | icon.classList.add('aria-hidden="true"'); 938 | button.appendChild(icon); 939 | msg.appendChild(div1); 940 | msg.style.display = 'inline-block'; 941 | } 942 | } 943 | //Admin Crosslist 944 | function add_buttonAdmin(){ 945 | 946 | var rightDiv = document.querySelector('div#right-side-wrapper'); 947 | rightDiv.style.display='inline'; 948 | rightDiv.style.width='auto'; 949 | var parent = document.querySelector('aside#right-side'); 950 | if (parent) { 951 | var el = parent.querySelector('#cs_cross'); 952 | if (!el) { 953 | el = document.createElement('button'); 954 | el.classList.add('Button','Button--primary','Button--small','button-sidebar-wide','element_toggler'); 955 | el.type = 'button'; 956 | el.id = 'cs_cross'; 957 | el.style.width = '175px'; 958 | var icon = document.createElement('i'); 959 | icon.classList.add('icon-sis-synced'); 960 | el.appendChild(icon); 961 | var txt = document.createTextNode(' Admin Crosslist Tool'); 962 | el.appendChild(txt); 963 | el.addEventListener('click', openDialog3); 964 | parent.appendChild(el); 965 | } 966 | //decrosslist button 967 | var el2 = parent.querySelector('#cs_decross'); 968 | if (!el2) { 969 | el2 = document.createElement('button'); 970 | el2.classList.add('Button','Button--secondary','Button--small','button-sidebar-wide','element_toggler'); 971 | el2.type = 'button'; 972 | el2.id = 'cs_decross'; 973 | el2.style.width = '175px'; 974 | var icon2 = document.createElement('i'); 975 | icon2.classList.add('icon-sis-not-synced'); 976 | el2.appendChild(icon2); 977 | var txt2 = document.createTextNode(' De-Crosslist Courses'); 978 | el2.appendChild(txt2); 979 | el2.addEventListener('click', openDialog2); 980 | parent.appendChild(el2); 981 | } 982 | } 983 | } 984 | function adminDialog() { 985 | var el = document.querySelector('#cs_admin_dialog'); 986 | if (!el) { 987 | //User Search 988 | el = document.createElement('form'); 989 | el.id = 'cs_admin_dialog'; 990 | el.classList.add("ic-Form-control","account_search_form"); 991 | var label = document.createElement('label'); 992 | label.htmlFor = 'cs_cross_user'; 993 | label.textContent = 'Search For Teacher:'; 994 | label.classList.add('ic-Label'); 995 | el.appendChild(label); 996 | var el11 = document.createElement('div'); 997 | el11.style =('margin: 0 0 10px 0'); 998 | el11.classList.add('ic-Input-group'); 999 | el.appendChild(el11); 1000 | var input = document.createElement('input'); 1001 | input.classList.add('ic-Input'); 1002 | input.id = 'cs_cross_user'; 1003 | input.type = 'text'; 1004 | input.placeholder = 'Enter Teacher Name'; 1005 | el11.appendChild(input); 1006 | var searchButton = document.createElement('button'); 1007 | searchButton.type = 'button'; 1008 | searchButton.id = 'btnSearch'; 1009 | searchButton.textContent = 'Search'; 1010 | searchButton.onclick = searchUser; 1011 | searchButton.classList.add('Button'); 1012 | el11.appendChild(searchButton); 1013 | $("#cs_cross_user").keyup(function(event){ 1014 | if(event.keyCode == 13){ 1015 | $("#btnSearch").click(); 1016 | } 1017 | }); 1018 | //teacher dropdown 1019 | label = document.createElement('label'); 1020 | label.htmlFor = 'cs_cross_Results'; 1021 | label.textContent = 'Search Results'; 1022 | label.classList.add('ic-Label'); 1023 | el.appendChild(label); 1024 | var select = document.createElement('select'); 1025 | select.id = 'cs_cross_chooseuser'; 1026 | select.classList.add('ic-Input'); 1027 | select.placeholder = 'Select Teacher:'; 1028 | select.onchange = getCoursesAdmin; 1029 | el.appendChild(select); 1030 | var el5 = document.createElement('div'); 1031 | el5.classList.add('ic-Form-control'); 1032 | el.appendChild(el5); 1033 | var br = document.createElement('hr'); 1034 | el5.appendChild(br); 1035 | label = document.createElement('label'); 1036 | label.htmlFor = 'cs_cross_parentCourse'; 1037 | label.textContent = 'Step 1: Select Bucket Course:'; 1038 | label.classList.add('ic-Label'); 1039 | el5.appendChild(label); 1040 | select = document.createElement('select'); 1041 | select.id = 'cs_cross_parentCourse'; 1042 | select.classList.add('ic-Input'); 1043 | select.onchange = getChildren; 1044 | el5.appendChild(select); 1045 | //childcourse checkboxes 1046 | var el6 = document.createElement('fieldset'); 1047 | el6.id = 'child_list'; 1048 | el6.style.visibility = 'none'; 1049 | el6.classList.add("ic-Fieldset", "ic-Fieldset--radio-checkbox"); 1050 | el.appendChild(el6); 1051 | var el7 = document.createElement('legend'); 1052 | el7.classList.add('ic-Legend'); 1053 | el7.textContent = 'Step 2: Choose Courses to Crosslist Into Bucket Course:'; 1054 | el6.appendChild(el7); 1055 | var el8 = document.createElement('div'); 1056 | el8.id = 'checkboxes'; 1057 | el8.classList.add('ic-Checkbox-group'); 1058 | el6.appendChild(el8); 1059 | //Course Name 1060 | var el9 = document.createElement('div'); 1061 | el9.id = 'course_div'; 1062 | el9.style.visibility = 'none'; 1063 | el9.classList.add('ic-Form-control'); 1064 | el.appendChild(el9); 1065 | label = document.createElement('label'); 1066 | label.htmlFor = 'course_name'; 1067 | label.textContent = 'Step 3: Course Name:'; 1068 | label.classList.add('ic-Label'); 1069 | el9.appendChild(label); 1070 | input = document.createElement('input'); 1071 | input.id = 'course_name'; 1072 | input.classList.add('ic-Input'); 1073 | input.type = 'text'; 1074 | input.placeholder = 'Campus Initials Course Name Teacher Name (First Initial.Last Name)'; 1075 | el9.appendChild(input); 1076 | //Course Name Examples 1077 | var el10 = document.createElement('p'); 1078 | el10.id = 'examples'; 1079 | el10.style.visibility = 'none'; 1080 | el10.classList = 'text-info'; 1081 | el.appendChild(el10); 1082 | var ol = document.createElement('ol'); 1083 | ol.textContent = 'Examples:'; 1084 | ol.classList = 'unstyled'; 1085 | el10.appendChild(ol); 1086 | var li = document.createElement('li'); 1087 | li.textContent = 'KHS English III A M.Smith'; 1088 | ol.appendChild(li); 1089 | li = document.createElement('li'); 1090 | li.textContent = 'BJH 8 Science KAP G.Moreno'; 1091 | ol.appendChild(li); 1092 | li = document.createElement('li'); 1093 | li.textContent = 'KDE 5 Math G.Rorey'; 1094 | ol.appendChild(li); 1095 | //message flash 1096 | var msg = document.createElement('div'); 1097 | msg.id = 'cs_cross_msg'; 1098 | //msg.classList.add('ic-flash-warning'); 1099 | msg.style.display = 'none'; 1100 | el.appendChild(msg); 1101 | var parent = document.querySelector('body'); 1102 | parent.appendChild(el); 1103 | } 1104 | } 1105 | function openDialog3() { 1106 | try { 1107 | adminDialog(); 1108 | var wWidth = $(window).width(); 1109 | var dWidth = wWidth * 0.4; 1110 | var wHeight = $(window).height(); 1111 | var dHeight = wHeight * 0.8; 1112 | $('#cs_admin_dialog').dialog({ 1113 | 'title' : 'Admin Crosslist Tool', 1114 | 'autoOpen' : false, 1115 | 'closeOnEscape': true, 1116 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 1117 | 'buttons' : [ { 1118 | 'text' : 'Cancel', 1119 | 'click' : function() { 1120 | $(this).dialog('destroy').remove(); 1121 | errors = []; 1122 | updateMsgs(); 1123 | } 1124 | },{ 1125 | 'text' : 'Submit', 1126 | 'class': 'Button Button--primary', 1127 | 'click' : submitButton 1128 | } ], 1129 | 'modal' : true, 1130 | 'resizable' : false, 1131 | 'height' : dHeight, 1132 | 'width' : dWidth, 1133 | }); 1134 | if (!$('#cs_admin_dialog').dialog('isOpen')) { 1135 | $('#cs_admin_dialog').dialog('open'); 1136 | } 1137 | } catch (e) { 1138 | console.log(e); 1139 | } 1140 | } 1141 | 1142 | 1143 | })(); 1144 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Chad Scott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CanvasUserScripts 2 | No Longer Supported 3 | All - I've moved on and my current school does not use Canvas, so unfortunately, I will not be able to maintain these any longer. 4 | 5 | 6 | UserScripts for Canvas LMS 7 | 8 | Canvas Crosslisting.user.js is a very basic tool in which the user inputs the course number of the parent course and child course and then the two are crosslisted together. 9 | 10 | instructor and admin crosslisting tools.js is a more robust script in which the instructor's current term courses are loaded in a dropdown menu to choose the parent course. Then the remaining courses are dynamically created and are selectable to be child courses. Finally, the instructor can rename the parent course and submit to finalize the crosslisting and renaming actions. The instructor can also choose to crosslist without renaming and rename without crosslisting. On the subaccount page, it also adds the ability for root level admins to search for a user and then perform the same tasks as an instructor. 11 | 12 | Canvas Course Event Manager is a script that will allow a user to remove the dates or delete events from a course calendar. The user can select all events displayed (100 at a time) or select specific events. 13 | 14 | Canvas Remove Student Tool is a script that will allow an admin to remove students from courses in bulk. The table is sortable by name or last activity date. The "Add More" button will load the next 100 students. It is useful for managing manually created course enrollments for clubs, activities, and special courses. 15 | 16 | Print Canvas Quizzes is a script that will allow a user to print a quiz from the preview page. 17 |
    18 |
  1. Features
  2. 19 |
      20 |
    1. Adds a "Print Quiz" button below the question navigation pane.
    2. 21 |
    3. Auto-page break: This will keep all question content on the same page and prevents a page break in the middle of a question.
    4. 22 |
    5. The page is set to zoom to 74% to make it sized appropriately for printing.
    6. 23 |
    7. Adjusts certain question types for legibility and space efficiency
    8. 24 |
    9. Hides "This is a preview..." banner and "Submit Quiz" button
    10. 25 |
    11. The print dialog will automatically pop-up for the user
    12. 26 |
        27 |
      • Multiple Choice: Left aligns choices, all one column
      • 28 |
      • Matching: Removes drop-down menu and creates a "answer bank" at the bottom of the question box
      • 29 |
      • Multiple Dropdowns: Expands the dropdowns to width and height of content
      • 30 |
      31 |
    32 |
  3. Limitations
  4. 33 |
      34 |
    1. The quiz must be viewed from the "Preview Quiz" page
    2. 35 |
    3. All questions must be visible on the page, which means the "Show one question at a time" must be unchecked
    4. 36 |
    5. Currently, the zoom level of the page is not editable by the user, except through the printer dialog window
    6. 37 |
    7. Not usable in the Quizzez.next LTI
    8. 38 |
    39 |
40 | 41 | Remove Color Overlay is a script that removes the color overlay of courses with course images on the Dashboard. This is a workaround since admin is unable to set the default Dashboard experience for users. 42 | -------------------------------------------------------------------------------- /instructor and admin crosslisting tools.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name KatyISD Instructor and Admin Crosslisting Tools 3 | // @namespace https://github.com/sukotsuchido/CanvasUserScripts 4 | // @version 2.1 5 | // @description A Canvas UserScript to facilitate crosslisting of courses. 6 | // @author Chad Scott (ChadScott@katyisd.org) 7 | // @include https://*.instructure.com/courses 8 | // @include https://*.instructure.com/accounts/* 9 | // @grant none 10 | // ==/UserScript== 11 | (function() { 12 | 'use strict'; 13 | var assocRegex = new RegExp('^/courses$'); 14 | var assocRegex2 = new RegExp('^/accounts/([0-9]+)$'); 15 | var acc = window.location.pathname; 16 | var errors = []; 17 | var parentId = []; 18 | var maxValue = 1; 19 | var termId = ''; 20 | var courses = {}; 21 | var dedupThings = []; 22 | var wholeName = ''; 23 | var array =[]; 24 | var user = ''; 25 | /* role setup: Change the roles you want to have access to the crosslisting features. assocRegex is for the button on the all courses page and assocRegex2 is for the admin page. */ 26 | var roles = ENV.current_user_roles; 27 | var cxbuttonRoles = ["admin", "teacher", "root_admin"]; 28 | var admincxbuttonRoles = ["root_admin"]; 29 | var test1 = cxbuttonRoles.some(el => roles.includes(el)); 30 | var test2 = admincxbuttonRoles.some(el => roles.includes(el)); 31 | if( (test1 === true) && (assocRegex.test(window.location.pathname))){ 32 | getCourses(); 33 | } 34 | if( (test2 === true) && (assocRegex2.test(window.location.pathname))){ 35 | add_buttonAdmin(); 36 | } 37 | 38 | /* This adds the crosslist button to the all courses page and runs the function openDialog when clicked. */ 39 | function add_button() { 40 | var parent = document.querySelector('div.ic-Action-header__Secondary'); 41 | if (parent) { 42 | var el = parent.querySelector('#jj_cross'); 43 | if (!el) { 44 | el = document.createElement('button'); 45 | el.classList.add('Button','element_toggler'); 46 | el.type = 'button'; 47 | el.id = 'jj_cross'; 48 | var icon = document.createElement('i'); 49 | icon.classList.add('icon-sis-synced'); 50 | el.appendChild(icon); 51 | var txt = document.createTextNode(' Crosslist Courses'); 52 | el.appendChild(txt); 53 | el.addEventListener('click', openDialog); 54 | parent.appendChild(el); 55 | } 56 | } 57 | } 58 | /* This function creates the main popup window users interact with the crosslist their courses. 59 | I followed the Canvas Style Guide as much as possible to the CSS already available to create the form elements. */ 60 | function createDialog() { 61 | var el = document.querySelector('#jj_cross_dialog'); 62 | if (!el) { 63 | el = document.createElement('form'); 64 | el.id = 'jj_cross_dialog'; 65 | el.classList.add('ic-Form-group'); 66 | //Parent Course selection 67 | var help = document.createElement('div'); 68 | help.innerHTML = '
Directions: Complete for each step to crosslist and rename your courses.
Click OPTIONS for more information about Crosslisting.
Options
'; 69 | help.classList.add('ic-Label'); 70 | el.appendChild(help); 71 | var el5 = document.createElement('div'); 72 | el5.classList.add('ic-Form-control'); 73 | el.appendChild(el5); 74 | var label = document.createElement('label'); 75 | label.htmlFor = 'jj_cross_parentCourse'; 76 | label.innerHTML = 'Step 1: Select Bucket Course (Hover over step for more help)'; 77 | label.classList.add('ic-Label'); 78 | el5.appendChild(label); 79 | var select = document.createElement('select'); 80 | select.id = 'jj_cross_parentCourse'; 81 | select.classList.add('ic-Input'); 82 | select.onchange = getChildren; 83 | el5.appendChild(select); 84 | //childcourse checkboxes 85 | var el6 = document.createElement('fieldset'); 86 | el6.id = 'child_list'; 87 | el6.style.visibility = 'hidden'; 88 | el6.classList.add("ic-Fieldset", "ic-Fieldset--radio-checkbox"); 89 | el.appendChild(el6); 90 | var el7 = document.createElement('legend'); 91 | el7.classList.add('ic-Legend'); 92 | el7.innerHTML = 'Step 2: Choose Courses to Crosslist Into Bucket Course (Hover over step for more help)'; 93 | el6.appendChild(el7); 94 | var el8 = document.createElement('div'); 95 | el8.id = 'checkboxes'; 96 | el8.classList.add('ic-Checkbox-group'); 97 | el6.appendChild(el8); 98 | //Course Name 99 | var el9 = document.createElement('div'); 100 | el9.id = 'course_div'; 101 | el9.style.visibility = 'hidden'; 102 | el9.classList.add('ic-Form-control'); 103 | el.appendChild(el9); 104 | label = document.createElement('label'); 105 | label.htmlFor = 'course_name'; 106 | label.innerHTML = ' Step 3: Set Course Name (Hover over step for more help)'; 107 | label.classList.add('ic-Label'); 108 | el9.appendChild(label); 109 | var input = document.createElement('input'); 110 | input.id = 'course_name'; 111 | input.classList.add('ic-Input'); 112 | input.type = 'text'; 113 | //input.placeholder = 'Campus Initials Course Name Teacher Name (First Initial.Last Name)'; 114 | el9.appendChild(input); 115 | //Course Name Examples 116 | var el10 = document.createElement('p'); 117 | el10.id = 'examples'; 118 | el10.style.visibility = 'hidden'; 119 | el10.classList = 'text-info'; 120 | el.appendChild(el10); 121 | var ol = document.createElement('ol'); 122 | ol.textContent = 'Examples:'; 123 | //ol.style.border = "thin solid #0000FF"; 124 | ol.classList = 'unstyled'; 125 | el10.appendChild(ol); 126 | var li = document.createElement('li'); 127 | li.textContent = 'High School: KHS English 3 A M.Smith'; 128 | ol.appendChild(li); 129 | li = document.createElement('li'); 130 | li.textContent = 'Junior High: BJH Spanish 1 PreAP G.Moreno'; 131 | ol.appendChild(li); 132 | li = document.createElement('li'); 133 | li.textContent = 'Elementary: KDE 4 Math G.Rorey'; 134 | ol.appendChild(li); 135 | //message flash 136 | var msg = document.createElement('div'); 137 | msg.id = 'jj_cross_msg'; 138 | //msg.classList.add('ic-flash-warning'); 139 | msg.style.display = 'none'; 140 | el.appendChild(msg); 141 | var parent = document.querySelector('body'); 142 | parent.appendChild(el); 143 | } 144 | setParent(); 145 | /* opens the help dialog window */ 146 | document.getElementById("action_helper").addEventListener("click", function(){ 147 | openHelp(); 148 | }); 149 | } 150 | 151 | /* Help dialog window, explains the steps of how to crosslist */ 152 | function createhelpDialog(){ 153 | var el = document.querySelector('#help_dialog'); 154 | if (!el) { 155 | el = document.createElement('div'); 156 | el.innerHTML= '
Crosslist and Name Course: Complete all 3 steps
Crosslist and Don\'t Rename Course: Complete steps 1 and 2
Only Rename Course: Complete steps 1 and 3

Hover over each step for more help.
'; 157 | el.id = 'help_dialog'; 158 | //Parent Course selection 159 | //message flash 160 | var msg = document.createElement('div'); 161 | msg.id = 'jj_cross_msg'; 162 | //msg.classList.add('ic-flash-warning'); 163 | msg.style.display = 'none'; 164 | el.appendChild(msg); 165 | var parent = document.querySelector('body'); 166 | parent.appendChild(el); 167 | } 168 | } 169 | 170 | /* This function creates the modal window for the help dialog, I have hidden the titlebar close button and disabled the ability to esc close also. */ 171 | function openHelp() { 172 | try { 173 | createhelpDialog(); 174 | $('#help_dialog').dialog({ 175 | 'title' : 'Possible Actions', 176 | 'autoOpen' : false, 177 | 'closeOnEscape': false, 178 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 179 | 'buttons' : [ { 180 | 'text' : 'Close', 181 | 'click' : function() { 182 | $(this).dialog('destroy').remove(); 183 | } 184 | } ], 185 | 'modal' : true, 186 | 'resizable' : false, 187 | 'height' : 'auto', 188 | 'width' : '30%' 189 | }); 190 | if (!$('#help_dialog').dialog('isOpen')) { 191 | $('#help_dialog').dialog('open'); 192 | } 193 | } catch (e) { 194 | console.log(e); 195 | } 196 | } 197 | 198 | /* This function sends an api request to get the current users course list. */ 199 | function getCourses(){ 200 | // Reset global variable errors 201 | errors= []; 202 | var url = "/api/v1/users/self/courses?inlcude[]=term&include[]=sections&per_page=100"; 203 | $.ajax({ 204 | 'async': true, 205 | 'type': "GET", 206 | 'global': true, 207 | 'dataType': 'JSON', 208 | 'data': JSON.stringify(courses), 209 | 'contentType': "application/json", 210 | 'url': url, 211 | 'success': function(courses){ 212 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 213 | add_button(); 214 | } 215 | }); 216 | } 217 | /* This function sorts and returns only the most recent term id number. This prevents users from crosslisting into manually created courses. */ 218 | function maxTerm(dedupThings){ 219 | for(var i=0;i maxValue){ 221 | maxValue = Number(dedupThings[i].enrollment_term_id); 222 | } 223 | } 224 | return maxValue; 225 | } 226 | 227 | /* This function takes the return from getTerm and then filters the courses for only that term id and sets the courses in the dropdown. */ 228 | function setParent(){ 229 | var toAppend = ''; 230 | var select = document.getElementById('jj_cross_parentCourse'); 231 | select.options.length = 0; // clear out existing items 232 | termId = maxTerm(dedupThings); 233 | $.each(dedupThings, function(i, o){ 234 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher") { 235 | toAppend += ''; 236 | } 237 | }); 238 | var blank =''; 239 | blank += ''; 240 | $('#jj_cross_parentCourse').append(blank); 241 | $('#jj_cross_parentCourse').append(toAppend); 242 | } 243 | 244 | /* This function reveals the rest of the form after the parent course is selected. It adds the remaining courses not chosen to be the 245 | parent course as check boxes.*/ 246 | function getChildren(){ 247 | var show = document.getElementById('child_list'); 248 | show.style.visibility = 'visible'; 249 | var show2 = document.getElementById('course_div'); 250 | show2.style.visibility = 'visible'; 251 | var show3 = document.getElementById('examples'); 252 | show3.style.visibility = 'visible'; 253 | var clear = document.getElementById('checkboxes'); 254 | var clear3=''; 255 | if (clear.innerHTML !== null){ 256 | clear.innerHTML = ""; 257 | } 258 | parentId = document.getElementById("jj_cross_parentCourse").value; 259 | var labelAppend = ''; 260 | var inputAppend = ''; 261 | $.each(dedupThings,function(i,o){ 262 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher" && o.id != parentId) { 263 | labelAppend += ''+''; 264 | clear3=labelAppend; 265 | if (labelAppend !== null){ 266 | labelAppend = ''; 267 | } 268 | inputAppend += '
'+clear3+'
'; 269 | } 270 | }); 271 | $('#checkboxes').append(inputAppend); 272 | } 273 | /* Users are able to change the course name. This sets the text input to wholeName.*/ 274 | function courseName(){ 275 | var newName= []; 276 | newName = $.map($('input[id="course_name"]'), function(i){return i.value; }); 277 | $.each(newName, function(index, item){ 278 | if (item !==null){ 279 | wholeName = item; 280 | } 281 | }); 282 | } 283 | 284 | /* This functions sends an API command to change the name of the parent course.*/ 285 | function updateName(){ 286 | var url = "/api/v1/courses/" + parentId + "?course[name]=" + wholeName; 287 | $.ajax({ 288 | 'cache' : false, 289 | 'url' : url , 290 | 'type' : 'PUT', 291 | }).done(function() { 292 | closeDialog(); 293 | }); 294 | } 295 | 296 | /* This function creates the modal window for the form dialog box */ 297 | function openDialog() { 298 | try { 299 | createDialog(); 300 | $('#jj_cross_dialog').dialog({ 301 | 'title' : 'Crosslist Courses', 302 | 'autoOpen' : false, 303 | 'closeOnEscape': false, 304 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 305 | 'buttons' : [ { 306 | 'text' : 'Cancel', 307 | 'click' : function() { 308 | $(this).dialog('destroy').remove(); 309 | errors = []; 310 | updateMsgs(); 311 | } 312 | },{ 313 | 'text' : 'Submit', 314 | 'class': 'Button Button--primary', 315 | 'click' : submitButton 316 | 317 | } ], 318 | 'modal' : true, 319 | 'resizable' : false, 320 | 'height' : 'auto', 321 | 'width' : '40%' 322 | }); 323 | if (!$('#jj_cross_dialog').dialog('isOpen')) { 324 | $('#jj_cross_dialog').dialog('open'); 325 | } 326 | } catch (e) { 327 | console.log(e); 328 | } 329 | } 330 | 331 | /* this function stores the courses checked in step 2 to the array variable */ 332 | function setChild() { 333 | array = $.map($('input[name="childCourses"]:checked'), function(c){return c.value; }); 334 | } 335 | /* This function sends an API command to crosslist the courses stored in the array variable with the parent course. 336 | When it's done, it will execute the function to set the course to the users dashboard and then close the window.*/ 337 | function processDialog() { 338 | $.each(array, function(index,item){ 339 | var childCourse = item; 340 | var childSection; 341 | var url = "/api/v1/courses/" + childCourse + "/sections?"; 342 | $.ajax({ 343 | 'async': true, 344 | 'type': "GET", 345 | 'global': true, 346 | 'dataType': 'JSON', 347 | 'data': JSON.stringify(childSection), 348 | 'contentType': "application/json", 349 | 'url': url, 350 | 'success': function (data) { 351 | $.each(data, function(i,o){ 352 | childSection = o.id; 353 | var url2 = "/api/v1/sections/" + childSection + "/crosslist/" + parentId +"?"; 354 | $.ajax({ 355 | 'cache' : false, 356 | 'url' : url2 , 357 | 'type' : 'POST', 358 | }).done(function() { 359 | setFavorite(); 360 | closeDialog(); 361 | }); 362 | }); 363 | } 364 | }); 365 | }); 366 | } 367 | 368 | /* Sets the course to the user's dashboard */ 369 | function setFavorite (){ 370 | var url = "/api/v1/users/self/favorites/courses/" + parentId; 371 | $.ajax({ 372 | 'cache' : false, 373 | 'url' : url , 374 | 'type' : 'POST', 375 | }); 376 | } 377 | 378 | /* If the user omits step 3, a dialog windows pops up verifying if the user doesn't want to rename the course. 379 | The confirmation button says crosslist only. If the user does want to rename, they can hit close and rename it in step 3. */ 380 | function nonameDialog(){ 381 | var el = document.querySelector('#nonamedialog'); 382 | if (!el) { 383 | el = document.createElement('div'); 384 | el.id = 'nonamedialog'; 385 | var el2 = document.createElement('div'); 386 | el.appendChild(el2); 387 | var el3 = document.createElement('p'); 388 | el3.textContent = ' No course name entered!'; 389 | el2.appendChild(el3); 390 | //direction 1 391 | var div1 = document.createElement('div'); 392 | div1.classList.add('ic-image-text-combo'); 393 | el.appendChild(div1); 394 | var icon; 395 | icon = document.createElement('i'); 396 | icon.classList.add('icon-check'); 397 | div1.appendChild(icon); 398 | var text = document.createElement('div'); 399 | text.classList.add("text-success","ic-image-text-combo__text"); 400 | text.textContent = 'Click "Crosslist Only" to continue without naming'; 401 | div1.appendChild(text); 402 | //direction 2 403 | div1 = document.createElement('div'); 404 | div1.classList.add('ic-image-text-combo'); 405 | el.appendChild(div1); 406 | icon = document.createElement('i'); 407 | icon.classList.add('icon-warning'); 408 | div1.appendChild(icon); 409 | text = document.createElement('p'); 410 | text.classList.add("text-warning","ic-image-text-combo__text"); 411 | text.textContent = 'Click "Cancel" to go back and name your course.'; 412 | div1.appendChild(text); 413 | var parent = document.querySelector('body'); 414 | parent.appendChild(el); 415 | } 416 | } 417 | /* This creates the modal window for the noname dialog box */ 418 | function opennonameDialog(){ 419 | try { 420 | nonameDialog(); 421 | $('#nonamedialog').dialog({ 422 | 'title' : 'Crosslist Courses Only', 423 | 'autoOpen' : false, 424 | 'closeOnEscape': false, 425 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); }, 426 | 'buttons' : [{ 427 | 'text' : 'Cancel', 428 | 'click' : function() { 429 | $(this).dialog('destroy').remove(); 430 | errors = []; 431 | updateMsgs(); 432 | } 433 | },{ 434 | 'text' : 'Crosslist Only', 435 | 'class': 'Button Button--primary', 436 | 'click' : processDialog 437 | } ], 438 | 'modal' : true, 439 | 'resizable' : false, 440 | 'height' : 'auto', 441 | 'width' : '40%', 442 | }); 443 | if (!$('#nonamedialog').dialog('isOpen')) { 444 | $('#nonamedialog').dialog('open'); 445 | } 446 | } catch (e) { 447 | console.log(e); 448 | } 449 | } 450 | /* If the user omits step 2, a dialog windows pops up verifying if the user doesn't want to crosslist any courses. 451 | The confirmation button says rename only. If the user does want to crosslist, they can hit close and choose courses to crosslist in step 2. */ 452 | function nocrossDialog(){ 453 | var el = document.querySelector('#nocrossdialog'); 454 | if (!el) { 455 | el = document.createElement('div'); 456 | el.id = 'nocrossdialog'; 457 | var el2 = document.createElement('div'); 458 | el.appendChild(el2); 459 | var el3 = document.createElement('p'); 460 | el3.textContent = ' No courses selected to crosslist!'; 461 | el2.appendChild(el3); 462 | //direction 1 463 | var div1 = document.createElement('div'); 464 | div1.classList.add('ic-image-text-combo'); 465 | el.appendChild(div1); 466 | var icon; 467 | icon = document.createElement('i'); 468 | icon.classList.add('icon-check'); 469 | div1.appendChild(icon); 470 | var text = document.createElement('div'); 471 | text.classList.add("text-success","ic-image-text-combo__text"); 472 | text.textContent = 'Click "Update Name" to continue without crosslisting'; 473 | div1.appendChild(text); 474 | //direction 2 475 | div1 = document.createElement('div'); 476 | div1.classList.add('ic-image-text-combo'); 477 | el.appendChild(div1); 478 | icon = document.createElement('i'); 479 | icon.classList.add('icon-warning'); 480 | div1.appendChild(icon); 481 | text = document.createElement('p'); 482 | text.classList.add("text-warning","ic-image-text-combo__text"); 483 | text.textContent = 'Click "Cancel" to go back and choose courses to crosslist.'; 484 | div1.appendChild(text); 485 | var parent = document.querySelector('body'); 486 | parent.appendChild(el); 487 | } 488 | } 489 | /* Creates the modal window for the nocross dialog box */ 490 | function opennocrossDialog(){ 491 | try { 492 | nocrossDialog(); 493 | $('#nocrossdialog').dialog({ 494 | 'title' : 'Update Course Name Only', 495 | 'autoOpen' : false, 496 | 'closeOnEscape': false, 497 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); }, 498 | 'buttons' : [ { 499 | 'text' : 'Cancel', 500 | 'click' : function() { 501 | $(this).dialog('destroy').remove(); 502 | errors = []; 503 | updateMsgs(); 504 | } 505 | },{ 506 | 'text' : 'Update Name', 507 | 'class': 'Button Button--primary', 508 | 'click' : updateName 509 | } ], 510 | 'modal' : true, 511 | 'resizable' : false, 512 | 'height' : 'auto', 513 | 'width' : '40%' 514 | }); 515 | if (!$('#nocrossdialog').dialog('isOpen')) { 516 | $('#nocrossdialog').dialog('open'); 517 | } 518 | } catch (e) { 519 | console.log(e); 520 | } 521 | } 522 | /* This function processes the request of the main crosslist dialog window. It executes the appropriate functions based on steps completed. 523 | If step 2 and step 3 are skipped, it throws an error stating to complete step 2 and or step 3. */ 524 | function submitButton(){ 525 | errors = []; 526 | courseName(); 527 | setChild(); 528 | if (wholeName !=='' || array !=+ ''){ 529 | if (wholeName !=='' && array !=+ ''){ 530 | updateName(); 531 | processDialog(); 532 | } else if (wholeName ==='' && array !=+ ''){ 533 | opennonameDialog(); 534 | }else{ 535 | opennocrossDialog(); 536 | } 537 | }else{ 538 | errors.push('You must choose a course to crosslist or input a course name.'); 539 | updateMsgs(); 540 | } 541 | } 542 | /* This function closes all dialog windows and launches a success dialog */ 543 | function closeDialog(){ 544 | $('#nocrossDialog').dialog('close'); 545 | $('#nonameDialog').dialog('close'); 546 | $('#jj_cross_dialog').dialog('close'); 547 | $('#jj_cross_dialog2').dialog('close'); 548 | window.location.reload(true); 549 | open_success_dialog(); 550 | } 551 | /* This creates error messages at the bottom of the crosslist dialog window */ 552 | function updateMsgs() { 553 | var msg = document.getElementById('jj_cross_msg'); 554 | if (!msg) { 555 | return; 556 | } 557 | if (msg.hasChildNodes()) { 558 | msg.removeChild(msg.childNodes[0]); 559 | } 560 | if (typeof errors === 'undefined' || errors.length === 0) { 561 | msg.style.display = 'none'; 562 | } else { 563 | var div1 = document.createElement('div'); 564 | div1.classList.add('ic-flash-error'); 565 | var div2; 566 | div2 = document.createElement('div'); 567 | div2.classList.add('ic-flash__icon'); 568 | div2.classList.add('aria-hidden="true"'); 569 | div1.appendChild(div2); 570 | var icon; 571 | icon = document.createElement('i'); 572 | icon.classList.add('icon-warning'); 573 | div2.appendChild(icon); 574 | var ul = document.createElement('ul'); 575 | for (var i = 0; i < errors.length; i++) { 576 | var li; 577 | li = document.createElement('li'); 578 | li.textContent = errors[i]; 579 | ul.appendChild(li); 580 | } 581 | div1.appendChild(ul); 582 | var button; 583 | button = document.createElement('button'); 584 | button.type = 'button'; 585 | button.classList.add("Button", "Button--icon-action", "close_link"); 586 | div1.appendChild(button); 587 | icon = document.createElement('i'); 588 | icon.classList.add('ic-icon-x'); 589 | icon.classList.add('aria-hidden="true"'); 590 | button.appendChild(icon); 591 | msg.appendChild(div1); 592 | msg.style.display = 'inline-block'; 593 | } 594 | } 595 | /* This creates the success dialog window */ 596 | function successDialog(){ 597 | var el = document.querySelector('#success_dialog'); 598 | if (!el) { 599 | el = document.createElement('div'); 600 | el.id = 'success_dialog'; 601 | var div1 = document.createElement('div'); 602 | div1.classList.add('ic-flash-success'); 603 | el.appendChild(div1); 604 | var div2 = document.createElement('div'); 605 | div2.classList.add('ic-flash__icon'); 606 | div2.classList.add('aria-hidden="true"'); 607 | div1.appendChild(div2); 608 | var icon = document.createElement('i'); 609 | icon.classList.add('icon-check'); 610 | div2.appendChild(icon); 611 | var msg = document.createTextNode("The action completed successfully!"); 612 | div1.appendChild(msg); 613 | var button = document.createElement('button'); 614 | button.type = 'button'; 615 | button.classList.add("Button", "Button--icon-action", "close_link"); 616 | el.appendChild(button); 617 | icon = document.createElement('i'); 618 | icon.classList.add('ic-icon-x'); 619 | icon.classList.add('aria-hidden="true"'); 620 | button.appendChild(icon); 621 | var parent = document.querySelector('body'); 622 | parent.appendChild(el); 623 | } 624 | } 625 | 626 | /* This creates the modal window for the success dialog and it closes with the page refresh in the closeDialog function */ 627 | function open_success_dialog(){ 628 | try { 629 | successDialog(); 630 | $('#success_dialog').dialog({ 631 | 'autoOpen' : false, 632 | 'closeOnEscape': false, 633 | 'open': function () { $(".ui-dialog-titlebar").hide(); $(".ui-widget-content").css("background", "rgba(255, 255, 255, 0)"); $(".ui-dialog.ui-widget-content").css("box-shadow", "none");}, 634 | 'modal' : true, 635 | 'resizable' : false, 636 | 'height' : 'auto', 637 | 'width' : '40%', 638 | }); 639 | if (!$('#success_dialog').dialog('isOpen')) { 640 | $('#success_dialog').dialog('open'); 641 | } 642 | } catch (e) { 643 | console.log(e); 644 | } 645 | } 646 | /* You can remove the following if an admin panel is not needed. I'll come add comments to this section soon! */ 647 | //Admin De-Crosslist 648 | function searchUser() { 649 | // Reset global variable errors 650 | errors = []; 651 | var userName; 652 | var el = document.getElementById('jj_cross_user'); 653 | if (el.value && el.value.trim() !== '') { 654 | userName = el.value; 655 | var url = "/api/v1" + acc + "/users?search_term=" + userName + "&per_page=100"; 656 | var userInfo; 657 | var x = document.getElementById("jj_cross_user"); 658 | if (x.className === "ic-Input") { 659 | x.style.background = "url(https://imagizer.imageshack.us/a/img922/9776/IinEAt.gif) no-repeat right center"; 660 | } 661 | $.ajax({ 662 | 'async': true, 663 | 'type': "GET", 664 | 'global': true, 665 | 'dataType': 'JSON', 666 | 'data': JSON.stringify(userInfo), 667 | 'contentType': "application/json", 668 | 'url': url, 669 | 'success': function(data){ 670 | if(data.length > 0){ 671 | var toAppend = ''; 672 | var blank = ''; 673 | var select = document.getElementById('jj_cross_chooseuser'); 674 | select.options.length = 0; // clear out existing items 675 | $.each(data,function(i,o){ 676 | // var n = o.name; 677 | //if (n.toUpperCase() !== n){ 678 | toAppend += ''; 679 | //} 680 | }); 681 | blank += ''; 682 | $('#jj_cross_chooseuser').append(blank); 683 | $('#jj_cross_chooseuser').append(toAppend); 684 | var x = document.getElementById("jj_cross_user"); 685 | if (x.className === "ic-Input") { 686 | x.style.background = "#fff"; 687 | } 688 | }else{ 689 | errors.push('No user found'); 690 | updateMsgs(); 691 | } 692 | } 693 | }); 694 | }else { 695 | errors.push('You must type in a name.'); 696 | } 697 | updateMsgs(); 698 | } 699 | function getCoursesAdmin(){ 700 | // Reset global variable errors 701 | errors= []; 702 | user = document.getElementById('jj_cross_chooseuser').value; 703 | var url = "/api/v1/users/"+ user +"/courses?include[]=term&per_page=100"; 704 | $.ajax({ 705 | 'async': true, 706 | 'type': "GET", 707 | 'global': true, 708 | 'dataType': 'JSON', 709 | 'data': JSON.stringify(courses), 710 | 'contentType': "application/json", 711 | 'url': url, 712 | 'success': function(courses){ 713 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 714 | var toAppend = ''; 715 | var blank =''; 716 | var select2 = document.getElementById('jj_cross_parentCourse'); 717 | select2.options.length = 0; // clear out existing items 718 | 719 | termId = maxTerm(dedupThings); 720 | $.each(dedupThings, function(i, o){ 721 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher") { 722 | toAppend += ''; 723 | } 724 | }); 725 | blank += ''; 726 | $('#jj_cross_parentCourse').append(blank); 727 | $('#jj_cross_parentCourse').append(toAppend); 728 | } 729 | }); 730 | } 731 | function setParentDecross(){ 732 | // Reset global variable errors 733 | errors= []; 734 | user = document.getElementById('jj_cross_chooseuser').value; 735 | var url = "/api/v1/users/"+ user +"/courses?include[]=term&include[]=sections&per_page=100"; 736 | $.ajax({ 737 | 'async': true, 738 | 'type': "GET", 739 | 'global': true, 740 | 'dataType': 'JSON', 741 | 'data': JSON.stringify(courses), 742 | 'contentType': "application/json", 743 | 'url': url, 744 | 'success': function(courses){ 745 | dedupThings = Array.from(courses.reduce((m, t) => m.set(t.id, t), new Map()).values()); 746 | var toAppend = ''; 747 | var blank =''; 748 | var select2 = document.getElementById('jj_cross_parentCourse'); 749 | select2.options.length = 0; // clear out existing items 750 | 751 | termId = maxTerm(dedupThings); 752 | $.each(dedupThings, function(i, o){ 753 | if (o.enrollment_term_id == termId && o.enrollments[0].type == "teacher" && o.sections.length > 1) { 754 | toAppend += ''; 755 | } 756 | }); 757 | blank += ''; 758 | $('#jj_cross_parentCourse').append(blank); 759 | $('#jj_cross_parentCourse').append(toAppend); 760 | } 761 | }); 762 | } 763 | function getSections(){ 764 | var courseSections; 765 | parentId = document.getElementById("jj_cross_parentCourse").value; 766 | var url = "/api/v1/courses/" + parentId + "/sections?"; 767 | $.ajax({ 768 | 'async': true, 769 | 'type': "GET", 770 | 'global': true, 771 | 'dataType': 'JSON', 772 | 'data': JSON.stringify(courseSections), 773 | 'contentType': "application/json", 774 | 'url': url, 775 | 'success': function (courseSections) { 776 | $.each(courseSections, function(index,item){ 777 | array = item.id; 778 | if(array !== parentId){ 779 | var url2 = "/api/v1/sections/" + array + "/crosslist/"; 780 | $.ajax({ 781 | 'cache' : false, 782 | 'url' : url2 , 783 | 'type' : 'DELETE', 784 | 785 | }).done(function() { 786 | closeDialog(); 787 | }); 788 | } 789 | }); 790 | } 791 | }); 792 | } 793 | function openDialog2() { 794 | try { 795 | createDialog2(); 796 | $('#jj_cross_dialog2').dialog({ 797 | 'title' : 'Admin De-Crosslist Tool', 798 | 'autoOpen' : false, 799 | 'closeOnEscape': false, 800 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 801 | 'buttons' : [ { 802 | 'text' : 'Cancel', 803 | 'click' : function() { 804 | $(this).dialog('destroy').remove(); 805 | errors = []; 806 | updateMsgs(); 807 | } 808 | },{ 809 | 'text' : 'Submit', 810 | 'class': 'Button Button--primary', 811 | 'click' : getSections 812 | } ], 813 | 'modal' : true, 814 | 'resizable' : false, 815 | 'height' : 'auto', 816 | 'width' : '40%', 817 | }); 818 | if (!$('#jj_cross_dialog2').dialog('isOpen')) { 819 | $('#jj_cross_dialog2').dialog('open'); 820 | } 821 | } catch (e) { 822 | console.log(e); 823 | } 824 | } 825 | function createDialog2() { 826 | var el = document.querySelector('#jj_cross_dialog2'); 827 | if (!el) { 828 | el = document.createElement('form'); 829 | el.id = 'jj_cross_dialog2'; 830 | el.classList.add("ic-Form-control","account_search_form"); 831 | var label = document.createElement('label'); 832 | label.htmlFor = 'jj_cross_user'; 833 | label.textContent = 'Search For Teacher:'; 834 | label.classList.add('ic-Label'); 835 | el.appendChild(label); 836 | var el11 = document.createElement('div'); 837 | el11.style =('margin: 0 0 10px 0'); 838 | el11.classList.add('ic-Input-group'); 839 | el.appendChild(el11); 840 | var input = document.createElement('input'); 841 | input.classList.add('ic-Input'); 842 | input.id = 'jj_cross_user'; 843 | input.type = 'text'; 844 | input.placeholder = 'Enter Teacher Name'; 845 | el11.appendChild(input); 846 | $("#jj_cross_user").keyup(function(event){ 847 | if(event.keyCode == 13){ 848 | $("#btnSearch").click(); 849 | } 850 | }); 851 | var searchButton = document.createElement('button'); 852 | searchButton.type = 'button'; 853 | searchButton.id = 'btnSearch'; 854 | searchButton.textContent = 'Search'; 855 | searchButton.onclick = searchUser; 856 | searchButton.classList.add('Button'); 857 | el11.appendChild(searchButton); 858 | //teacher dropdown 859 | label = document.createElement('label'); 860 | label.htmlFor = 'jj_cross_choosuser'; 861 | label.textContent = 'Search Results'; 862 | label.classList.add('ic-Label'); 863 | el.appendChild(label); 864 | var select = document.createElement('select'); 865 | select.id = 'jj_cross_chooseuser'; 866 | select.classList.add('ic-Input'); 867 | select.placeholder = 'Select Teacher:'; 868 | select.onchange = setParentDecross; 869 | el.appendChild(select); 870 | var el5 = document.createElement('div'); 871 | el5.classList.add('ic-Form-control'); 872 | el.appendChild(el5); 873 | var br = document.createElement('hr'); 874 | el5.appendChild(br); 875 | label = document.createElement('label'); 876 | label.htmlFor = 'jj_cross_parentCourse'; 877 | label.textContent = 'Step 1: Select Bucket Course:'; 878 | label.classList.add('ic-Label'); 879 | el5.appendChild(label); 880 | select = document.createElement('select'); 881 | select.id = 'jj_cross_parentCourse'; 882 | select.classList.add('ic-Input'); 883 | el5.appendChild(select); 884 | //message flash 885 | var msg = document.createElement('div'); 886 | msg.id = 'jj_cross_msg2'; 887 | //msg.classList.add('ic-flash-warning'); 888 | msg.style.display = 'none'; 889 | el.appendChild(msg); 890 | var parent = document.querySelector('body'); 891 | parent.appendChild(el); 892 | } 893 | } 894 | function updateMsgs2() { 895 | var msg = document.getElementById('jj_cross_msg2'); 896 | if (!msg) { 897 | return; 898 | } 899 | if (msg.hasChildNodes()) { 900 | msg.removeChild(msg.childNodes[0]); 901 | } 902 | if (typeof errors === 'undefined' || errors.length === 0) { 903 | msg.style.display = 'none'; 904 | } else { 905 | var div1 = document.createElement('div'); 906 | div1.classList.add('ic-flash-error'); 907 | var div2; 908 | div2 = document.createElement('div'); 909 | div2.classList.add('ic-flash__icon'); 910 | div2.classList.add('aria-hidden="true"'); 911 | div1.appendChild(div2); 912 | var icon; 913 | icon = document.createElement('i'); 914 | icon.classList.add('icon-warning'); 915 | div2.appendChild(icon); 916 | var ul = document.createElement('ul'); 917 | for (var i = 0; i < errors.length; i++) { 918 | var li; 919 | li = document.createElement('li'); 920 | li.textContent = errors[i]; 921 | ul.appendChild(li); 922 | } 923 | div1.appendChild(ul); 924 | var button; 925 | button = document.createElement('button'); 926 | button.type = 'button'; 927 | button.classList.add("Button", "Button--icon-action", "close_link"); 928 | div1.appendChild(button); 929 | icon = document.createElement('i'); 930 | icon.classList.add('ic-icon-x'); 931 | icon.classList.add('aria-hidden="true"'); 932 | button.appendChild(icon); 933 | msg.appendChild(div1); 934 | msg.style.display = 'inline-block'; 935 | } 936 | } 937 | //Admin Crosslist 938 | function add_buttonAdmin(){ 939 | 940 | var rightDiv = document.querySelector('div#right-side-wrapper'); 941 | rightDiv.style.display='list-item'; 942 | 943 | var parent = document.querySelector('aside#right-side'); 944 | if (parent) { 945 | var el = parent.querySelector('#jj_cross'); 946 | if (!el) { 947 | el = document.createElement('button'); 948 | el.classList.add('Button','Button--primary','button-sidebar-wide','element_toggler'); 949 | el.type = 'button'; 950 | el.id = 'jj_cross'; 951 | var icon = document.createElement('i'); 952 | icon.classList.add('icon-sis-synced'); 953 | el.appendChild(icon); 954 | var txt = document.createTextNode(' Admin Crosslist Tool'); 955 | el.appendChild(txt); 956 | el.addEventListener('click', openDialog3); 957 | parent.appendChild(el); 958 | } 959 | //decrosslist button 960 | var el2 = parent.querySelector('#jj_decross'); 961 | if (!el2) { 962 | el2 = document.createElement('button'); 963 | el2.classList.add('Button','Button--secondary','button-sidebar-wide','element_toggler'); 964 | el2.type = 'button'; 965 | el2.id = 'jj_decross'; 966 | var icon2 = document.createElement('i'); 967 | icon2.classList.add('icon-sis-not-synced'); 968 | el2.appendChild(icon2); 969 | var txt2 = document.createTextNode(' De-Crosslist Courses'); 970 | el2.appendChild(txt2); 971 | el2.addEventListener('click', openDialog2); 972 | parent.appendChild(el2); 973 | } 974 | } 975 | } 976 | function adminDialog() { 977 | var el = document.querySelector('#jj_admin_dialog'); 978 | if (!el) { 979 | //User Search 980 | el = document.createElement('form'); 981 | el.id = 'jj_admin_dialog'; 982 | el.classList.add("ic-Form-control","account_search_form"); 983 | var label = document.createElement('label'); 984 | label.htmlFor = 'jj_cross_user'; 985 | label.textContent = 'Search For Teacher:'; 986 | label.classList.add('ic-Label'); 987 | el.appendChild(label); 988 | var el11 = document.createElement('div'); 989 | el11.style =('margin: 0 0 10px 0'); 990 | el11.classList.add('ic-Input-group'); 991 | el.appendChild(el11); 992 | var input = document.createElement('input'); 993 | input.classList.add('ic-Input'); 994 | input.id = 'jj_cross_user'; 995 | input.type = 'text'; 996 | input.placeholder = 'Enter Teacher Name'; 997 | el11.appendChild(input); 998 | var searchButton = document.createElement('button'); 999 | searchButton.type = 'button'; 1000 | searchButton.id = 'btnSearch'; 1001 | searchButton.textContent = 'Search'; 1002 | searchButton.onclick = searchUser; 1003 | searchButton.classList.add('Button'); 1004 | el11.appendChild(searchButton); 1005 | $("#jj_cross_user").keyup(function(event){ 1006 | if(event.keyCode == 13){ 1007 | $("#btnSearch").click(); 1008 | } 1009 | }); 1010 | //teacher dropdown 1011 | label = document.createElement('label'); 1012 | label.htmlFor = 'jj_cross_Results'; 1013 | label.textContent = 'Search Results'; 1014 | label.classList.add('ic-Label'); 1015 | el.appendChild(label); 1016 | var select = document.createElement('select'); 1017 | select.id = 'jj_cross_chooseuser'; 1018 | select.classList.add('ic-Input'); 1019 | select.placeholder = 'Select Teacher:'; 1020 | select.onchange = getCoursesAdmin; 1021 | el.appendChild(select); 1022 | var el5 = document.createElement('div'); 1023 | el5.classList.add('ic-Form-control'); 1024 | el.appendChild(el5); 1025 | var br = document.createElement('hr'); 1026 | el5.appendChild(br); 1027 | label = document.createElement('label'); 1028 | label.htmlFor = 'jj_cross_parentCourse'; 1029 | label.textContent = 'Step 1: Select Bucket Course:'; 1030 | label.classList.add('ic-Label'); 1031 | el5.appendChild(label); 1032 | select = document.createElement('select'); 1033 | select.id = 'jj_cross_parentCourse'; 1034 | select.classList.add('ic-Input'); 1035 | select.onchange = getChildren; 1036 | el5.appendChild(select); 1037 | //childcourse checkboxes 1038 | var el6 = document.createElement('fieldset'); 1039 | el6.id = 'child_list'; 1040 | el6.style.visibility = 'none'; 1041 | el6.classList.add("ic-Fieldset", "ic-Fieldset--radio-checkbox"); 1042 | el.appendChild(el6); 1043 | var el7 = document.createElement('legend'); 1044 | el7.classList.add('ic-Legend'); 1045 | el7.textContent = 'Step 2: Choose Courses to Crosslist Into Bucket Course:'; 1046 | el6.appendChild(el7); 1047 | var el8 = document.createElement('div'); 1048 | el8.id = 'checkboxes'; 1049 | el8.classList.add('ic-Checkbox-group'); 1050 | el6.appendChild(el8); 1051 | //Course Name 1052 | var el9 = document.createElement('div'); 1053 | el9.id = 'course_div'; 1054 | el9.style.visibility = 'none'; 1055 | el9.classList.add('ic-Form-control'); 1056 | el.appendChild(el9); 1057 | label = document.createElement('label'); 1058 | label.htmlFor = 'course_name'; 1059 | label.textContent = 'Step 3: Course Name:'; 1060 | label.classList.add('ic-Label'); 1061 | el9.appendChild(label); 1062 | input = document.createElement('input'); 1063 | input.id = 'course_name'; 1064 | input.classList.add('ic-Input'); 1065 | input.type = 'text'; 1066 | input.placeholder = 'Campus Initials Course Name Teacher Name (First Initial.Last Name)'; 1067 | el9.appendChild(input); 1068 | //Course Name Examples 1069 | var el10 = document.createElement('p'); 1070 | el10.id = 'examples'; 1071 | el10.style.visibility = 'none'; 1072 | el10.classList = 'text-info'; 1073 | el.appendChild(el10); 1074 | var ol = document.createElement('ol'); 1075 | ol.textContent = 'Examples:'; 1076 | ol.classList = 'unstyled'; 1077 | el10.appendChild(ol); 1078 | var li = document.createElement('li'); 1079 | li.textContent = 'KHS English III A M.Smith'; 1080 | ol.appendChild(li); 1081 | li = document.createElement('li'); 1082 | li.textContent = 'BJH Spanish 1 PreAP G.Moreno'; 1083 | ol.appendChild(li); 1084 | li = document.createElement('li'); 1085 | li.textContent = 'Elementary: KDE 4 Math G.Rorey'; 1086 | ol.appendChild(li); 1087 | //message flash 1088 | var msg = document.createElement('div'); 1089 | msg.id = 'jj_cross_msg'; 1090 | //msg.classList.add('ic-flash-warning'); 1091 | msg.style.display = 'none'; 1092 | el.appendChild(msg); 1093 | var parent = document.querySelector('body'); 1094 | parent.appendChild(el); 1095 | } 1096 | } 1097 | function openDialog3() { 1098 | try { 1099 | adminDialog(); 1100 | $('#jj_admin_dialog').dialog({ 1101 | 'title' : 'Admin Crosslist Tool', 1102 | 'autoOpen' : false, 1103 | 'closeOnEscape': false, 1104 | 'open': function () { $(".ui-dialog-titlebar-close").hide(); $(".ui-dialog").css("top", "10px");}, 1105 | 'buttons' : [ { 1106 | 'text' : 'Cancel', 1107 | 'click' : function() { 1108 | $(this).dialog('destroy').remove(); 1109 | errors = []; 1110 | updateMsgs(); 1111 | } 1112 | },{ 1113 | 'text' : 'Submit', 1114 | 'class': 'Button Button--primary', 1115 | 'click' : submitButton 1116 | } ], 1117 | 'modal' : true, 1118 | 'resizable' : false, 1119 | 'height' : 'auto', 1120 | 'width' : '40%', 1121 | }); 1122 | if (!$('#jj_admin_dialog').dialog('isOpen')) { 1123 | $('#jj_admin_dialog').dialog('open'); 1124 | } 1125 | } catch (e) { 1126 | console.log(e); 1127 | } 1128 | } 1129 | /* Remove to here if the admin panel isn't needed */ 1130 | })(); 1131 | -------------------------------------------------------------------------------- /printCanvasQuizzes.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Print Canvas Quiz 3 | // @namespace https://github.com/sukotsuchido/CanvasUserScripts 4 | // @version 1.2 5 | // @description Allows the user to print quizzes from the preview page. 6 | // @author Chad Scott (ChadScott@katyisd.org) 7 | // @include https://*.instructure.com/courses/*/quizzes/*/take?preview* 8 | // @require https://code.jquery.com/jquery-3.4.1.min.js 9 | 10 | // ==/UserScript== 11 | (function() { 12 | $(document).ready ( function(){ 13 | var parent = document.querySelector('#right-side'); 14 | el = document.createElement('button'); 15 | el.classList.add('Button','element_toggler','button-sidebar-wide'); 16 | el.type = 'button'; 17 | el.id = 'printQuizButton'; 18 | var icon = document.createElement('i'); 19 | icon.classList.add('icon-document'); 20 | el.appendChild(icon); 21 | var txt = document.createTextNode(' Print'); 22 | el.appendChild(txt); 23 | el.addEventListener('click', allMatchQuestions); 24 | parent.appendChild(el); 25 | }); 26 | function allMatchQuestions(){ 27 | var allMatchQuestions = document.querySelectorAll("div.matching_question"); 28 | for (var z = 0; z < allMatchQuestions.length; z++) { 29 | var options = allMatchQuestions[z].querySelector("select").options; 30 | var list = document.createElement('div'); 31 | var matchText = document.createElement('div'); 32 | matchText.style.verticalAign = 'middle'; 33 | matchText.innerHTML ='Match Choices:'; 34 | for (var t = 0; t < options.length; t++) { 35 | if(options[t].textContent !=="[ Choose ]"){ 36 | temp = document.createElement('div'); 37 | temp.innerHTML = options[t].text; 38 | temp.style.display = 'inline-block'; 39 | temp.style.padding ='20px'; 40 | temp.style.maxWidth = '25%'; 41 | temp.style.verticalAlign = 'Top'; 42 | list.appendChild(temp); 43 | } 44 | list.style.width = 'inherit'; 45 | list.style.border = "thin dotted black"; 46 | list.style.padding = "0px 0px 0px 10px"; 47 | var optionsList = allMatchQuestions[z].querySelector(".answers"); 48 | optionsList.appendChild(matchText); 49 | matchText.appendChild(list); 50 | var hideOptions = allMatchQuestions[z].querySelectorAll("select"); 51 | console.log(hideOptions); 52 | for (var q = 0; q < hideOptions.length; q++) { 53 | var hideChoice = hideOptions[q].querySelector("select"); 54 | hideOptions[q].style.visibility="hidden"; 55 | } 56 | } 57 | } 58 | multiSelectQuestions(); 59 | printQuizStyle(); 60 | } 61 | function multiSelectQuestions(){ 62 | var allMultiSelectQuestions = document.querySelectorAll("div.multiple_dropdowns_question select"); 63 | for (var q = 0; q < allMultiSelectQuestions.length; q++) { 64 | var len = allMultiSelectQuestions[q].options.length; 65 | allMultiSelectQuestions[q].setAttribute('size', len); 66 | allMultiSelectQuestions[q].style.width = 'fit-content'; 67 | allMultiSelectQuestions[q].style.maxWidth =''; 68 | } 69 | } 70 | function printQuizStyle(){ 71 | var scale = document.querySelector("div.ic-Layout-contentMain"); 72 | scale.style.zoom = "74%"; 73 | var questionBlocks = document.querySelectorAll("div.question_holder"); 74 | for (var i = 0; i < questionBlocks.length; i++) { 75 | questionBlocks[i].style.pageBreakInside = "avoid"; 76 | } 77 | var answerChoices = document.querySelectorAll("div.answer"); 78 | for (var j = 0; j < answerChoices.length; j++) { 79 | //answerChoices[j].style.display = "inline-block"; 80 | //answerChoices[j].style.width = "22%"; 81 | answerChoices[j].style.verticalAlign = "Top"; 82 | answerChoices[j].style.borderTop = "none"; 83 | } 84 | 85 | //This hides the Submit Quiz footer - delete the /* */ comment tags to hide the footer. 86 | var formActions = document.querySelectorAll("div.alert,div.ic-RichContentEditor,div.rce_links"); 87 | for (var h = 0; h < formActions.length; h++) { 88 | formActions[h].style.visibility = "hidden"; 89 | } 90 | var essayShrink = document.querySelectorAll("div.mce-tinymce"); 91 | for (var m = 0; m < essayShrink.length; m++) { 92 | essayShrink[m].style.height = "200px"; 93 | } 94 | window.print(); 95 | } 96 | })(); 97 | --------------------------------------------------------------------------------