· 8 years ago · Feb 13, 2018, 12:30 AM
1/* -----------------------------------------
2Canvas Extensions Toolbar
3------------------------------------------
4
5Javascript for Chome bookmark:
6javascript:(function(){ var script=document.createElement('script'); script.src='https://ilearn.swin.edu.au/bbcswebdav/orgs/TLIP_scripts/shortcut-scripts/canvasExtentionToolbar.js'; document.head.appendChild(script); }())
7
8*/
9// get Current course ID
10
11var query_string = window.location.href;
12var query_string_split = query_string.split("/");
13window.currentCourse = query_string_split.indexOf('courses') >= 0 ? query_string_split[query_string_split.indexOf('courses') + 1] : "";
14
15window.canvasExtension = {};
16window.canvasExtension.extensionMenu = {};
17
18window.canvasExtension.dialog;
19window.canvasExtension.dialogId = "#extensionsDialog";
20
21window.canvasExtension.allItems = [];
22window.canvasExtension.allItemsAjax = [];
23window.canvasExtension.gradeBookColumns = [];
24
25
26/**
27 * init, create the extension menu, each button runs a function or opens a dialog
28 *
29 */
30window.canvasExtension.initCanvasExtensionMenu = function() {
31 window.canvasExtension.buildDialog();
32 //remove any existing extensions menu
33 $('#extensionMenu').remove();
34 //extension menu html
35 var menuHTML = " \
36 <div id='extensionMenu' class='' style='z-index: 10; background: #EEE; position: fixed; top: 0; right: 0; padding: 5px; text-align: right; box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75); font-size: 0.5em; line-height: 1em; '> \
37 <a title='Scroll to top' onClick='window.scrollTo(0,0)' class='btn btn-default' style='padding: 0.5em;'><i class='icon-arrow-open-up'> </i></a> \
38 <a title='Expand all' onClick='window.canvasExtension.expandAll()' class='btn btn-info' style='padding: 0.5em;'><i class='icon-page-down'> </i></a> \
39 <a title='Contract all' onClick='window.canvasExtension.contractAll()' class='btn btn-info' style='padding: 0.5em;'><i class='icon-page-up'> </i></a> \
40 <a title='Publish all' onClick='window.canvasExtension.publishAll()' class='btn btn-success' style='padding: 0.5em;'><i class='icon-publish'> </i></a> \
41 <a title='Unpublish all' onClick='window.canvasExtension.unpublishAll()' class='btn' style='padding: 0.5em;'><i class='icon-unpublish'> </i></a> \
42 <a title='Add groups' onClick='window.canvasExtension.setupAddGroups()' class='btn btn-warning' style='padding: 0.5em;'><i class='icon-group'> </i></a> \
43 <a title='Manage GradeBook columns' onClick='window.canvasExtension.setupGradeBookColumns()' class='btn btn-warning' style='padding: 0.5em;'><i class='icon-gradebook'> </i></a> \
44 <a title='Remove assignment dates' onClick='window.canvasExtension.runDialog(\"RemoveAssignmentDates\")' class='btn btn-danger' style='padding: 0.5em;'><i class='icon-calendar-clock'> </i></a> \
45 <a title='Find/remove empty items' onClick='window.canvasExtension.setupEmptyItems()' class='btn btn-danger' style='padding: 0.5em;'><i class='icon-document'> </i></a> \
46 <a title='Remove empty modules and assignment groups' onClick='window.canvasExtension.runDialog(\"RemoveEmptyModules\")' class='btn btn-danger' style='padding: 0.5em;'><i class='icon-module'> </i></a> \
47 </div> \
48 ";
49 //add extension menu to page
50 window.extensionMenu = $('body').append(menuHTML);
51}
52
53/**
54 * setup the dialog window, add it to the page
55 *
56 */
57window.canvasExtension.buildDialog = function() {
58 //destroy any existing dialogs
59 //if element exists, remove
60 if ($(window.canvasExtension.dialog) > 0) window.canvasExtension.dialog.dialog("destroy");
61 $(window.canvasExtension.dialogId).remove();
62 //add dialog
63 $('body').append('<div id="' + window.canvasExtension.dialogId.substring(1) + '" title=""></div>');
64 window.canvasExtension.dialog = $(window.canvasExtension.dialogId);
65 var dialogHtml = "";
66 window.canvasExtension.dialog.append(dialogHtml);
67}
68
69
70
71/**
72 * Open a dialog window, set the size and content of the dialog
73 *
74 * @param {string} modalType - The switch value for which modal to open.
75 * @param {object} dialogData - A {object} that is used to pass data and properties to the modal.
76 */
77window.canvasExtension.runDialog = function(modalType, dialogData) {
78 // default values for dialog
79 var dWidth = 1000;
80 var dHeight = $(window).height();
81 var dPosition = "";
82 var dTitle = "";
83 var dialogHtml = "";
84
85 // setup for different types of dialogs
86 switch (modalType) {
87
88 case "RemoveAssignmentDates":
89 dialogHtml += "<p class='text-center'>Remove all of the assignment dates for this course (id: " + window.currentCourse + " )?</p>"
90 dialogHtml += "<p class='text-center'><a class='btn btn-danger' onClick='window.canvasExtension.removeAssignmentDates();'>Yes, delete assignment dates</a></p>";
91 dWidth = 400;
92 dHeight = 300;
93 dTitle = "Remove assignment dates";
94 break;
95
96 case "OutcomeRemoveAssignmentDates":
97 dialogHtml += "<p class='text-center'>" + dialogData["number"] + " assignments updated.</p>";
98 dWidth = 400;
99 dHeight = 300;
100 dTitle = "Assignment dates removed";
101 break;
102
103 case "RemoveEmptyModules":
104 dialogHtml += "<p class='text-center'>Delete all <strong>empty</strong> modules for this course (id: " + window.currentCourse + " )?</p>";
105 dialogHtml += "<p class='text-center'><a class='btn btn-danger' onClick='window.canvasExtension.confirmRemoveEmptyModules();'>Yes, find empty modules</a></p>";
106 dialogHtml += "<p class='text-center'>Delete all <strong>empty</strong> assignment groups for this course (id: " + window.currentCourse + " )?</p>";
107 dialogHtml += "<p class='text-center'><a class='btn btn-danger' onClick='window.canvasExtension.confirmRemoveEmptyAssignmentGroups();'>Yes, find empty assignment groups</a></p>";
108 dWidth = 450;
109 dHeight = 350;
110 dTitle = "Remove empty modules and assignment groups";
111 break;
112
113 case "ConfirmRemoveEmptyModule":
114 if (dialogData["modules"].length > 0) {
115 dialogHtml += "<p class='text-center'>The following modules are empty:</p>";
116 dialogHtml += "<ul>";
117 $.each(dialogData["modules"], function(i, mItem) {
118 dialogHtml += "<li>" + mItem.id + " - " + mItem.name + "</li>";
119 });
120 dialogHtml += "</ul>";
121 dialogHtml += "<p class='text-center'><a class='btn btn-danger' onClick='window.canvasExtension.removeEmptyModules();'>REMOVE THESE MODULES</a></p>";
122 } else {
123 dialogHtml += "<p>There are no empty modules to remove.</p>";
124 }
125 dWidth = 400;
126 dHeight = 500;
127 dTitle = "Remove empty modules";
128 break;
129
130
131 case "ConfirmRemoveEmptyAssignmentGroups":
132 if (dialogData["assignment_groups"].length > 0) {
133 dialogHtml += "<p class='text-center'>The following assignment groups are empty:</p>";
134 dialogHtml += "<ul>";
135 $.each(dialogData["assignment_groups"], function(i, gItem) {
136 dialogHtml += "<li>" + gItem.id + " - " + gItem.name + "</li>";
137 });
138 dialogHtml += "</ul>";
139 dialogHtml += "<p class='text-center'><a class='btn btn-danger' onClick='window.canvasExtension.removeEmptyAssignmentGroups();'>REMOVE THESE ASSIGNMENT GROUPS</a></p>";
140 } else {
141 dialogHtml += "<p>There are no empty assignment groups to remove.</p>";
142 }
143 dWidth = 400;
144 dHeight = 500;
145 dTitle = "Remove empty assignment groups";
146 break;
147
148 case "OutcomeRemoveEmptyModules":
149 dialogHtml += "<p class='text-center'>" + dialogData["number"] + " empty modules have been removed.</p>";
150 dialogHtml += "<p class='text-center'>Please refresh the modules page to see the updates.</p>";
151 dialogHtml += "<p class='text-center'><a class='btn btn-warning' onClick='window.location.reload();'>Refresh page</a></p>";
152 dialogHtml += "<p class='text-center'><a class='btn btn-info' href='/courses/" + window.currentCourse + "/undelete'>Undelete items</a></p>";
153 dWidth = 400;
154 dHeight = 450;
155 dTitle += "Empty modules removed";
156 break;
157
158 case "OutcomeRemoveEmptyAssignmentGroups":
159 dialogHtml += "<p class='text-center'>" + dialogData["number"] + " empty assignment groups have been removed.</p>";
160 dialogHtml += "<p class='text-center'>Please refresh the assignments page to see the updates.</p>";
161 dialogHtml += "<p class='text-center'><a class='btn btn-warning' onClick='window.location.reload();'>Refresh page</a></p>";
162 dialogHtml += "<p class='text-center'><a class='btn btn-info' href='/courses/" + window.currentCourse + "/undelete'>Undelete items</a></p>";
163 dWidth = 400;
164 dHeight = 450;
165 dTitle += "Empty assignment groups removed";
166 break;
167
168 case "EmptyItems":
169 dialogHtml += "<p><em>Note: You will have to refresh the Modules page after any removals to see updates.</em></p>";
170 dialogHtml += "<p>The following pages are empty (may take a while to load):</p>";
171 dialogHtml += "<table id='emptyPageList' class='table'><thead><tr><th>id</th><th>type</th><th>title</th><th>link</th><th>delete?</th></tr></thead><tbody></tbody></table>";
172 dialogHtml += "<div class='loading text-center'><img src='/images/ajax-reload-animated.gif'> Loading.</div>";
173 dialogHtml += "<p class='text-center'><a class='btn btn-warning' onClick='window.location.reload();'>Refresh page</a></p>";
174 dialogHtml += "<p class='text-center'><a class='btn btn-info' href='/courses/" + window.currentCourse + "/undelete'>Undelete items</a></p>";
175 dWidth = 1000;
176 dTitle = "Remove empty pages/dicussions/assignments/quizzes";
177 break;
178
179 case "AddGroups":
180 if (dialogData["groupCategories"].length > 0) {
181 dialogHtml += "<p>Add group names on separate lines.</p>";
182 dialogHtml += "<p><strong>Group set</strong>: <select>";
183 $.each(dialogData["groupCategories"], function(i, gItem) {
184 dialogHtml += "<option value='" + gItem.id + "'>" + gItem.name + "</option>";
185 });
186 dialogHtml += "</select></p>";
187 dialogHtml += "<p class='text-center'><textarea style='width: 90%; height: 100px;'></textarea></p>";
188 dialogHtml += "<p class='text-center'><a class='btn btn-warning' onClick='window.canvasExtension.addGroups($(window.canvasExtension.dialogId+\" select option:selected\").val());'>Add groups</a></p>";
189 } else {
190 dialogHtml += "<p>There are no Group Categories. Please add a group category from the People tab.</p>";
191 }
192 dWidth = 500;
193 dHeight = 500;
194 dTitle = "Add groups";
195 break;
196
197 case "OutcomeAddGroups":
198 if (dialogData["groupNames"].length > 0) {
199 dialogHtml += "<p class='text-center'>" + dialogData["groupNames"].length + " groups added.</p>";
200 dialogHtml += "<p>" + dialogData["groupNames"].join(", ") + "</p>";
201 } else {
202 dialogHtml += "<p>No groups added.</p>"
203 }
204 dWidth = 400;
205 dHeight = 300;
206 dTitle = "Added groups";
207 break;
208
209 case "ManageGradeBookColumns":
210 dialogHtml += "<table id='emptyPageList' class='table'><thead><tr><th>title</th><th>hidden</th><th>teacher_notes</th><th>update?</th><th>delete?</th></tr></thead><tbody>";
211 if(window.canvasExtension.gradeBookColumns.length > 0){
212 $.each(window.canvasExtension.gradeBookColumns, function(i, gItem){
213 console.log(gItem);
214 dialogHtml += "<tr>";
215 dialogHtml += "<td><input class='gradebookcolumn_title' type='text' value='"+gItem.title+"'></input></td>";
216 dialogHtml += (gItem.hidden) ? "<td><input type='checkbox' class='gradebookcolumn_hidden' checked='checked'></input></td>" : "<td><input type='checkbox' class='gradebookcolumn_hidden'></input></td>";
217 dialogHtml += (gItem.teacher_notes) ? "<td><input type='checkbox' class='gradebookcolumn_teacher_notes' checked='checked'></input></td>" : "<td><input type='checkbox' class='gradebookcolumn_teacher_notes'></input></td>";
218 dialogHtml += "<td><a class='btn btn-success' onClick='window.canvasExtension.updateGradeBookColumn($(this), "+gItem.id+")'><i class='icon-refresh'> </i></a></td>";
219 dialogHtml += "<td><a class='btn btn-danger' onClick='window.canvasExtension.confirmDeleteGradeBookColumn($(this), "+gItem.id+");'><i class='icon-trash'> </i></a></td>";
220 dialogHtml += "</tr>";
221 });
222 }else{
223 dialogHtml += "<tr><td colspan='5'><p class='text-center'>There are no custom gradebook columns in this unit.</p></td></tr>";
224 }
225 dialogHtml += "</tbody></table>";
226 dialogHtml += "<hr/>";
227 dialogHtml += "<div id='addNewGradeBookColumn'>";
228 dialogHtml += "<p><strong>Add new gradebook column</strong></p>";
229 dialogHtml += "<p><strong>Title:</strong> <input class='gradebookcolumn_title' type='text'></input>";
230 dialogHtml += " <input type='checkbox' class='gradebookcolumn_hidden'></input> <strong>Hidden?</strong> ";
231 dialogHtml += " <input type='checkbox' class='gradebookcolumn_teacher_notes' checked='checked'><strong>Teacher notes?</strong> ";
232 dialogHtml += " <a class='btn btn-warning' onClick='window.canvasExtension.addGradeBookColumn();'>Add column</a></p>";
233 dialogHtml += "</div>"
234 dWidth = 800;
235 dTitle = "Manage gradebook columns";
236 break;
237
238
239 case "Message":
240 dialogHtml += dialogData["message"];
241 dWidth = 400;
242 dHeight = 300;
243 dTitle = dialogData["title"];
244 break;
245
246 default:
247 //nothing
248 }
249
250 //set dialog properties, and open the dialog window
251 window.canvasExtension.dialog.html("");
252 window.canvasExtension.dialog.append(dialogHtml);
253 // have to set the title in a few ways, the title doesn't change after the first time it runs
254 window.canvasExtension.dialog.attr("title", dTitle);
255 $('.ui-dialog-title', window.canvasExtension.dialog).html(dTitle);
256 window.canvasExtension.dialog.dialog({
257 "title": dTitle,
258 buttons: [{ text: "Close", click: function() { $(this).dialog("close"); } }]
259 });
260 window.canvasExtension.dialog.dialog("option", "width", dWidth);
261 window.canvasExtension.dialog.dialog("option", "height", dHeight);
262 window.canvasExtension.dialog.dialog("option", "position", dPosition);
263}
264
265// Expand all modules/assignments
266window.canvasExtension.contractAll = function() {
267 $('.ig-header-title.collapse_module_link:visible, .element_toggler[aria-expanded="true"]:visible').click();
268 $('.item-group-container .item-group-condensed, .ig-header').attr('style', 'padding: 0;').addClass('contractedExpanderGroups');
269 $('.item-group-container .ig-header button').attr('style', 'padding: 0 5px').addClass('contractedExpanderGroups');
270 //$('.ig-header-title, .expand_module_link').attr('style', 'margin: 0;');
271}
272
273// Contract all modules/assignments
274window.canvasExtension.expandAll = function() {
275 $('.ig-header-title.expand_module_link:visible, .element_toggler[aria-expanded="false"]:visible').click();
276 $('.contractedExpanderGroups').attr('style', '').removeClass('contractedExpanderGroups');
277}
278
279// publish all items on page
280window.canvasExtension.publishAll = function() {
281 //publish pages
282 $('#context_modules_sortable_container .context_module_item .ig-admin span[role="button"] > i').each(function() {
283 if ($(this).hasClass("icon-unpublish")) {
284 $(this).parent().trigger("click");
285 }
286 });
287 //publish modules
288 $('#context_modules_sortable_container div.ig-header > .ig-header-admin span[role="button"] > i').each(function() {
289 if ($(this).hasClass("icon-unpublish")) {
290 $(this).parent().trigger("click");
291 }
292 });
293}
294
295// Unpublish all items on page
296window.canvasExtension.unpublishAll = function() {
297 //unpublish pages
298 $('#context_modules_sortable_container .context_module_item .ig-admin span[role="button"] > i').each(function() {
299 if ($(this).hasClass("icon-publish")) {
300 $(this).parent().trigger("click");
301 }
302 });
303 //unpublish modules
304 $('#context_modules_sortable_container div.ig-header > .ig-header-admin span[role="button"] > i').each(function() {
305 if ($(this).hasClass("icon-publish")) {
306 $(this).parent().trigger("click");
307 }
308 });
309}
310
311// Set up page dialog
312window.canvasExtension.setupEmptyItems = function() {
313 window.canvasExtension.runDialog("EmptyItems");
314 window.canvasExtension.getEmptyItems();
315}
316
317// list all coueses in an account
318window.canvasExtension.getEmptyItems = function() {
319 //reset variables
320 window.canvasExtension.allItems = [];
321 window.canvasExtension.allItemsAjax = [];
322 // LIST ALL ITEMS
323 window.canvasExtension.listItemsFromCourse(
324 ["Page", "Assignment", "Discussion", "Quiz"], // types of search
325 { "Page": 1, "Assignment": 1, "Discussion": 1, "Quiz": 1 }, // type paging counters
326 { "Page": false, "Assignment": false, "Discussion": false, "Quiz": false }, // type done yet?
327 window.canvasExtension.allItems, // results array for all items
328 window.canvasExtension.allItemsAjax, // array for all ajax objs
329 window.canvasExtension.resultsEmptyItems // callback
330 );
331}
332
333window.canvasExtension.resultsEmptyItems = function() {
334 $(window.canvasExtension.dialogId + " .loading").remove();
335 $.each(window.canvasExtension.allItems, function(i, item) {
336 switch (item.type) {
337 case "Page":
338 if (!item.body) {
339 $(window.canvasExtension.dialogId + " #emptyPageList tbody").append("<tr><td>" + item.page_id + "</td><td>" + item.type + "</td><td>" + item.title + "</td><td><a href='" + item.html_url + "' target='_blank' class='button'><i class='icon-link'> </i></a></td><td><a class='btn btn-danger' onClick='window.canvasExtension.confirmDeleteItem($(this), \"" + item.type + "\",\"" + item.url + "\")'><i class='icon-trash'> </i></a></td></p>");
340 }
341 break;
342 case "Assignment":
343 if (!item.description) {
344 $(window.canvasExtension.dialogId + " #emptyPageList tbody").append("<tr><td>" + item.id + "</td><td>" + item.type + "</td><td>" + item.name + "</td><td><a href='" + item.html_url + "' target='_blank' class='button'><i class='icon-link'> </i></a></td><td><a class='btn btn-danger' onClick='window.canvasExtension.confirmDeleteItem($(this), \"" + item.type + "\",\"" + item.id + "\")'><i class='icon-trash'> </i></a></td></p>");
345 }
346 break;
347 case "Discussion":
348 if (!item.message) {
349 $(window.canvasExtension.dialogId + " #emptyPageList tbody").append("<tr><td>" + item.id + "</td><td>" + item.type + "</td><td>" + item.title + "</td><td><a href='" + item.html_url + "' target='_blank' class='button'><i class='icon-link'> </i></a></td><td><a class='btn btn-danger' onClick='window.canvasExtension.confirmDeleteItem($(this), \"" + item.type + "\",\"" + item.id + "\")'><i class='icon-trash'> </i></a></td></p>");
350 }
351 break;
352 case "Quiz":
353 if (!item.description && item.question_count <= 0) {
354 $(window.canvasExtension.dialogId + " #emptyPageList tbody").append("<tr><td>" + item.id + "</td><td>" + item.type + "</td><td>" + item.title + "</td><td><a href='" + item.html_url + "' target='_blank' class='button'><i class='icon-link'> </i></a></td><td><a class='btn btn-danger' onClick='window.canvasExtension.confirmDeleteItem($(this), \"" + item.type + "\",\"" + item.id + "\")'><i class='icon-trash'> </i></a></td></p>");
355 }
356 break;
357 default:
358 }
359 });
360}
361
362/**
363 * Confirm the deletion of an item:
364 * Change the button that was pressed into a confirmation button, that when
365 * pressed, will trigger a function to remove the item.
366 *
367 * @param {$element} element - The jQuery element that triggered the call
368 * @param {string} type - The Canvas 'type' of the item, i.e. Page, Assignment, Discussion, Quiz
369 * @param {string} id - The id of the Canvas item
370 */
371window.canvasExtension.confirmDeleteItem = function(element, type, id) {
372 // set up the confirmation button
373 var confirmElement = "<a class='btn btn-danger' onClick='window.canvasExtension.removeItem(\"" + type + "\",\"" + id + "\");$(this).closest(\"tr\").remove();'>Are you sure?</a>";
374 // replace the @param element with the confirmation button
375 $(element).replaceWith(confirmElement);
376}
377
378
379/**
380 * Remove an item from the current course
381 *
382 * @param {string} type - The Canvas 'type' of the item, i.e. Page, Assignment, Discussion, Quiz
383 * @param {string} id - The id of the Canvas item
384 */
385window.canvasExtension.removeItem = function(type, id) {
386 var removeURL = "";
387 // generate the ajax URL that'll remove the item
388 switch (type) {
389 case "Page":
390 removeURL = "/api/v1/courses/" + window.currentCourse + "/pages/" + id
391 break;
392 case "Assignment":
393 removeURL = "/api/v1/courses/" + window.currentCourse + "/assignments/" + id
394 break;
395 case "Discussion":
396 removeURL = "/api/v1/courses/" + window.currentCourse + "/discussion_topics/" + id
397 break;
398 case "Quiz":
399 removeURL = "/api/v1/courses/" + window.currentCourse + "/quizzes/" + id
400 break;
401 default:
402 //ignore
403 }
404 // remove the item
405 $.ajax({
406 type: "DELETE",
407 url: removeURL,
408 dataType: "json",
409 headers: {
410 'Accept': 'application/json',
411 'Content-Type': 'application/json'
412 },
413 success: function(data, textStatus, xhr) {
414 console.log(textStatus, xhr.status, data);
415 },
416 error: function(xhr, textStatus, errorThrown) {
417 console.log("error: " + errorThrown);
418 }
419 });
420}
421
422/**
423 * Set up the Add Groups dialog:
424 * Get the current set of group categories, and pass them to the AddGroups dialog
425 * to use.
426 *
427 */
428window.canvasExtension.setupAddGroups = function() {
429 $.getJSON("/api/v1/courses/" + window.currentCourse + "/group_categories", function(groupCategoryData) {
430 var groupCategories = [];
431 $.each(groupCategoryData, function(i, groupCategory) {
432 groupCategories.push({
433 "id": groupCategory.id,
434 "name": groupCategory.name
435 });
436 });
437 window.canvasExtension.runDialog("AddGroups", { "groupCategories": groupCategories });
438 });
439}
440
441
442/**
443 * Add the groups from the text entred, to the course
444 *
445 * @param {string} groupCategory - The id of the group category to add the groups to.
446 */
447window.canvasExtension.addGroups = function(groupCategory) {
448 var groupNames = [];
449 // read the text area, split each new line into a string for a new group name
450 $.each($(window.canvasExtension.dialogId + ' textarea').attr('value').split("\n"), function() {
451 var groupId = this.trim();
452 if (groupId != "") groupNames.push(groupId);
453 });
454 // create the groups under the @groupCategory
455 $.each(groupNames, function(g, groupName) {
456 $.ajax({
457 type: "POST",
458 url: "/api/v1/group_categories/" + groupCategory + "/groups",
459 dataType: "json",
460 headers: {
461 'Accept': 'application/json',
462 'Content-Type': 'application/json'
463 },
464 data: '{"name":"' + groupName + '"}',
465 success: function(data, textStatus, xhr) {
466 console.log(textStatus, xhr.status, data);
467 },
468 error: function(xhr, textStatus, errorThrown) {
469 console.log("error: " + errorThrown);
470 }
471 });
472 });
473 // run the outcome dialog, returning the list of group names
474 window.canvasExtension.runDialog("OutcomeAddGroups", { "groupNames": groupNames });
475}
476
477
478/**
479 * Confirm the removal of all of the empty modules:
480 * Generate a list of empty modules, and send them to the confirmation dialog.
481 *
482 */
483window.canvasExtension.confirmRemoveEmptyModules = function() {
484 // note: that Canvas is restricted to only get 100 modules per page, if there are more, then you'll have to build in paging.
485 // search for modules in the current course, check to see if they are empty
486 $.getJSON("/api/v1/courses/" + window.currentCourse + "/modules?include=items&per_page=100", function(moduleData) {
487 var modulesForRemoval = [];
488 $.each(moduleData, function(i, mItem) {
489 if (mItem.items.length > 0) {
490 // ignore - not empty
491 } else {
492 modulesForRemoval.push(mItem);
493 }
494 });
495 // run the confirmation dialog
496 window.canvasExtension.runDialog("ConfirmRemoveEmptyModule", { "modules": modulesForRemoval });
497 });
498}
499
500/**
501 * Confirm the removal of all of the empty assignment groups:
502 * Generate a list of empty assignment groups, and send them to the confirmation dialog.
503 *
504 */
505window.canvasExtension.confirmRemoveEmptyAssignmentGroups = function() {
506 // search for assignment_groups in the current course, check to see if they are empty
507 $.getJSON("/api/v1/courses/" + window.currentCourse + "/assignment_groups?include=assignments&per_page=100", function(groupData) {
508 console.log(groupData);
509 var assignmentGroupsForRemoval = [];
510 $.each(groupData, function(i, gItem) {
511 if (gItem.assignments.length > 0) {
512 // ignore - not empty
513 } else {
514 assignmentGroupsForRemoval.push(gItem);
515 }
516 });
517 // run the confirmation dialog
518 window.canvasExtension.runDialog("ConfirmRemoveEmptyAssignmentGroups", { "assignment_groups": assignmentGroupsForRemoval });
519 });
520}
521
522/**
523 * Remove the empty modules from the course
524 *
525 */
526window.canvasExtension.removeEmptyModules = function() {
527 // note: that Canvas is restricted to only get 100 modules per page, if there are more, then you'll have to build in paging.
528 // search all of the modules of the current course
529 $.getJSON("/api/v1/courses/" + window.currentCourse + "/modules?include=items&per_page=100", function(moduleData) {
530 var mCount = 0;
531 $.each(moduleData, function(i, mItem) {
532 if (mItem.items.length > 0) {
533 // ignore - not empty
534 } else {
535 mCount++;
536 // delete the empty module
537 $.ajax({
538 type: "DELETE",
539 url: "/api/v1/courses/" + window.currentCourse + "/modules/" + mItem.id,
540 dataType: "json",
541 headers: {
542 'Accept': 'application/json',
543 'Content-Type': 'application/json'
544 },
545 success: function(data, textStatus, xhr) {
546 console.log(textStatus, xhr.status, data);
547 },
548 error: function(xhr, textStatus, errorThrown) {
549 console.log("error: " + errorThrown);
550 }
551 });
552 }
553 });
554 // show the outcome dialog, with a count of the number of modules removed.
555 window.canvasExtension.runDialog("OutcomeRemoveEmptyModules", { "number": mCount });
556 });
557}
558
559/**
560 * Remove the empty assignment groups from the course
561 *
562 */
563window.canvasExtension.removeEmptyAssignmentGroups = function() {
564 // note: that Canvas is restricted to only get 100 modules per page, if there are more, then you'll have to build in paging.
565 // search all of the modules of the current course
566 $.getJSON("/api/v1/courses/" + window.currentCourse + "/assignment_groups?include=assignments&per_page=100", function(assignmentGroupData) {
567 var gCount = 0;
568 $.each(assignmentGroupData, function(i, gItem) {
569 if (gItem.assignments.length > 0) {
570 // ignore - not empty
571 } else {
572 gCount++;
573 // delete the empty module
574 $.ajax({
575 type: "DELETE",
576 url: "/api/v1/courses/" + window.currentCourse + "/assignment_groups/" + gItem.id,
577 dataType: "json",
578 headers: {
579 'Accept': 'application/json',
580 'Content-Type': 'application/json'
581 },
582 success: function(data, textStatus, xhr) {
583 console.log(textStatus, xhr.status, data);
584 },
585 error: function(xhr, textStatus, errorThrown) {
586 console.log("error: " + errorThrown);
587 }
588 });
589 }
590 });
591 // show the outcome dialog, with a count of the number of modules removed.
592 window.canvasExtension.runDialog("OutcomeRemoveEmptyAssignmentGroups", { "number": gCount });
593 });
594}
595
596
597/**
598 * Remove dates from Assignment pages
599 *
600 */
601window.canvasExtension.removeAssignmentDates = function() {
602 // get all of the assignments in the courses
603 $.ajax({
604 type: "get",
605 url: "/api/v1/courses/" + window.currentCourse + "/assignments?per_page=100",
606 crossDomain: true,
607 cache: false,
608 dataType: "json",
609 contentType: "application/json; charset=UTF-8",
610 success: function(data, textStatus, xhr) {
611 for (var i = 0; i < data.length; i++) {
612 // remove the due date, and start/end dates for each assignment
613 $.ajax({
614 type: "PUT",
615 url: "/api/v1/courses/" + window.currentCourse + "/assignments/" + data[i].id,
616 dataType: "json",
617 headers: {
618 'Accept': 'application/json',
619 'Content-Type': 'application/json'
620 },
621 data: '{"assignment":{"due_at":"","lock_at":"","unlock_at":""}}',
622 success: function(data, textStatus, xhr) {
623 console.log(textStatus, xhr.status, data);
624 },
625 error: function(xhr, textStatus, errorThrown) {
626 console.log("error: " + errorThrown);
627 }
628 });
629 }
630 // show the outcome dialog, send then number of assignments that were updated
631 window.canvasExtension.runDialog("OutcomeRemoveAssignmentDates", { "number": data.length });
632 },
633 error: function(xhr, textStatus, errorThrown) {
634 console.log("error: " + errorThrown);
635 }
636 });
637}
638
639/**
640 * LIST ALL ITEMS FROM COURSE BY TYPE
641 *
642 *
643 * @param {array} itemTypes - set of item types, i.e. ["Page", "Assignment", "Discussion", "Quiz"]
644 * @param {object} itemTypesPageCount - object with page counter matching types
645 * @param {object} resultsByType - object with resutls by type
646 * @param {global array} itemResults - array for item results
647 * @param {global array} itemsResultsAjax - array for ajax calls
648 * @param {requestCallback} callback - callback function, this runs after all of the items have been retrieved
649 */
650window.canvasExtension.listItemsFromCourse = function(itemTypes, itemTypesPageCount, resultsByType, itemResults, itemsResultsAjax, callback) {
651 $.each(itemTypes, function(i, itemType) {
652 var itemType = itemType;
653 var itemTypeURL = "";
654 var itemURL = "";
655 var itemIdOn = "";
656
657 // get URLs for item calls. Canvas is limited to 100 items per 'page', so listItemsFromCourse may be called multiple times
658 switch (itemType) {
659 case "Page":
660 itemTypeURL = "/api/v1/courses/" + window.currentCourse + "/pages?sort=title&page=" + itemTypesPageCount[itemType] + "&per_page=100"
661 itemURL = "/api/v1/courses/" + window.currentCourse + "/pages/"
662 itemIdOn = 'url'
663 break;
664 case "Assignment":
665 itemTypeURL = "/api/v1/courses/" + window.currentCourse + "/assignments?page=" + itemTypesPageCount[itemType] + "&per_page=100"
666 itemURL = "/api/v1/courses/" + window.currentCourse + "/assignments/"
667 itemIdOn = 'id'
668 break;
669 case "Discussion":
670 itemTypeURL = "/api/v1/courses/" + window.currentCourse + "/discussion_topics?page=" + itemTypesPageCount[itemType] + "&per_page=100"
671 itemURL = "/api/v1/courses/" + window.currentCourse + "/discussion_topics/"
672 itemIdOn = 'id'
673 break;
674 case "Quiz":
675 itemTypeURL = "/api/v1/courses/" + window.currentCourse + "/quizzes?page=" + itemTypesPageCount[itemType] + "&per_page=100"
676 itemURL = "/api/v1/courses/" + window.currentCourse + "/quizzes/"
677 itemIdOn = 'id'
678 break;
679 default:
680 }
681
682 itemsResultsAjax.push(
683 $.ajax({
684 type: "GET",
685 url: itemTypeURL,
686 success: function(data, textStatus, xhr) {
687 $.each(data, function(t, tItem) {
688 itemsResultsAjax.push($.ajax({
689 type: "GET",
690 url: itemURL + tItem[itemIdOn],
691 success: function(data) {
692 data.type = itemType;
693 // add item to results
694 itemResults.push(data);
695 }
696 }));
697 });
698 // will throw out of loop if number of courses > 10000 -- if you have more than 10000 units, increase the pNum check
699 if (xhr.getResponseHeader('Link').indexOf('rel="next"') > 0 && itemTypesPageCount[itemType] < 100) {
700 itemTypesPageCount[itemType]++;
701 // get next page
702 // keep getting items, get next set for this item type
703 window.canvasExtension.listItemsFromCourse([itemType], itemTypesPageCount, resultsByType, itemResults, itemsResultsAjax, callback);
704 } else {
705 resultsByType[itemType] = true;
706 //check all items for all item types are done
707 var allTrue = true;
708 $.each(resultsByType, function(n, nDone) {
709 if (!nDone) allTrue = false;
710 });
711 // if they're all done, do results
712 if (allTrue) {
713 // when all the ajax is done, run the callback
714 $.when.apply(undefined, itemsResultsAjax).then(callback);
715 }
716 }
717 },
718 error: function(xhr, textStatus, errorThrown) {
719 console.log("error: " + errorThrown);
720 }
721 })
722 );
723 });
724}
725
726
727
728/**
729 * setupGradeBookColumns
730 */
731window.canvasExtension.setupGradeBookColumns = function(){
732 window.canvasExtension.listGradeBookColumns(function(data){
733 window.canvasExtension.gradeBookColumns = data;
734 window.canvasExtension.runDialog("ManageGradeBookColumns");
735 });
736}
737
738/**
739 * LIST - GET /api/v1/courses/:course_id/custom_gradebook_columns
740 * @param {function} callback
741 */
742window.canvasExtension.listGradeBookColumns = function(callback){
743 $.getJSON("/api/v1/courses/"+window.currentCourse+"/custom_gradebook_columns?include_hidden=true", function(data) {
744 callback(data);
745 //window.canvasExtension.newGradeBookColumn("New column", gradeBookColumns.length+1, false, true)
746 });
747}
748
749/**
750 * Confirm the deletion of an item:
751 * Change the button that was pressed into a confirmation button, that when
752 * pressed, will trigger a function to remove the item.
753 *
754 * @param {$element} element - The jQuery element that triggered the call
755 * @param {string} id - The id of the gradebook column
756 */
757window.canvasExtension.confirmDeleteGradeBookColumn = function(element, id){
758 // set up the confirmation button
759 var confirmElement = "<a class='btn btn-danger' onClick='window.canvasExtension.deleteGradeBookColumn(\"" + id + "\");$(this).closest(\"tr\").remove();'>Are you sure?</a>";
760 // replace the @param element with the confirmation button
761 $(element).replaceWith(confirmElement);
762}
763
764
765/**
766 * LIST - GET /api/v1/courses/:course_id/custom_gradebook_columns
767 * @param {function} callback
768 */
769window.canvasExtension.deleteGradeBookColumn = function(id){
770 // remove the gradebook column
771 $.ajax({
772 type: "DELETE",
773 url: "/api/v1/courses/"+window.currentCourse+"/custom_gradebook_columns/"+id,
774 dataType: "json",
775 headers: {
776 'Accept': 'application/json',
777 'Content-Type': 'application/json'
778 },
779 success: function(data, textStatus, xhr) {
780 console.log(textStatus, xhr.status, data);
781 window.canvasExtension.setupGradeBookColumns();
782 },
783 error: function(xhr, textStatus, errorThrown) {
784 console.log("error: " + errorThrown);
785 }
786 });
787}
788
789
790
791/**
792 * UPDATE - PUT /api/v1/courses/:course_id/custom_gradebook_columns/:id
793 * @param {$element} update button that called function
794 * @param {string} id of gradebook column
795 */
796window.canvasExtension.updateGradeBookColumn = function(element, id){
797 var column_title = $(element).closest('tr').find('.gradebookcolumn_title').attr('value');
798 var column_hidden = ($(element).closest('tr').find('.gradebookcolumn_hidden').attr('checked')) ? true : false;
799 var column_teacher_notes = ($(element).closest('tr').find('.gradebookcolumn_teacher_notes').attr('checked')) ? true : false;
800 console.log("column_title", column_title, "column_hidden", column_hidden, "column_teacher_notes", column_teacher_notes);
801 $.ajax({
802 type: "PUT",
803 url: "/api/v1/courses/" + window.currentCourse + "/custom_gradebook_columns/" + id,
804 dataType: "json",
805 headers: {
806 'Accept': 'application/json',
807 'Content-Type': 'application/json'
808 },
809 data: '{"column": {"title": "'+column_title+'", "hidden": "'+column_hidden+'", "teacher_notes": "'+column_teacher_notes+'"}}',
810 success: function(data, textStatus, xhr) {
811 console.log(textStatus, xhr.status, data);
812 window.canvasExtension.setupGradeBookColumns();
813 },
814 error: function(xhr, textStatus, errorThrown) {
815 console.log("error: " + errorThrown);
816 }
817 });
818}
819
820
821/**
822 * Add gradebook column
823 */
824window.canvasExtension.addGradeBookColumn = function(){
825 var column_title = $(window.canvasExtension.dialogId + " #addNewGradeBookColumn .gradebookcolumn_title").attr('value');
826 var column_position = window.canvasExtension.gradeBookColumns.length+1;
827 var column_hidden = ($(window.canvasExtension.dialogId + " #addNewGradeBookColumn .gradebookcolumn_hidden").attr('checked')) ? true : false;
828 var column_teacher_notes = ($(window.canvasExtension.dialogId + " #addNewGradeBookColumn .gradebookcolumn_teacher_notes").attr('checked')) ? true : false;
829 window.canvasExtension.createGradeBookColumn(column_title, column_position, column_hidden, column_teacher_notes, window.canvasExtension.setupGradeBookColumns);
830}
831
832
833/**
834 * NEW COLUMN - POST /api/v1/courses/:course_id/custom_gradebook_columns
835 * @param {Required string} column_title - no description
836 * @param {integer} column_position - The position of the column relative to other custom columns
837 * @param {boolean} column_hidden - Hidden columns are not displayed in the gradebook
838 * @param {boolean} column_teacher_notes - Set this if the column is created by a teacher. The gradebook only supports one teacher_notes column.
839 * @param {function} callback
840 */
841window.canvasExtension.createGradeBookColumn = function(column_title, column_position, column_hidden, column_teacher_notes, callback){
842 $.ajax({
843 type: "POST",
844 url: "/api/v1/courses/"+window.currentCourse+"/custom_gradebook_columns",
845 dataType: "json",
846 headers: {
847 'Accept': 'application/json',
848 'Content-Type': 'application/json'
849 },
850 data: '{"column":{"title": "'+column_title+'", "position": '+column_position+', "hidden": '+column_hidden+',"teacher_notes": '+column_teacher_notes+'}}',
851 success: function(data, textStatus, xhr) {
852 console.log(textStatus, xhr.status, data);
853 callback();
854 },
855 error: function(xhr, textStatus, errorThrown) {
856 console.log("error: " + errorThrown);
857 }
858 });
859}
860
861
862
863
864// ------------------ WIP::COURSES -----------------
865
866
867window.canvasExtension.allCourses = [];
868
869// list all coueses in an account
870window.canvasExtension.listAllCourses = function() {
871 window.canvasExtension.allCourses = [];
872 var nextPage = 1;
873 window.canvasExtension.listNextCourses(nextPage);
874}
875
876window.canvasExtension.listNextCourses = function(pNum) {
877 $.ajax({
878 type: "GET",
879 url: "/api/v1/accounts/1/courses?page=" + pNum + "&per_page=100",
880 dataType: "json",
881 headers: {
882 'Accept': 'application/json',
883 'Content-Type': 'application/json'
884 },
885 success: function(data, textStatus, xhr) {
886 //console.log(xhr.getResponseHeader('Link'));
887 $.each(data, function(i, tCourse) {
888 window.canvasExtension.allCourses.push({
889 "name": tCourse.name,
890 "id": tCourse.id
891 });
892 //$(window.canvasExtension.dialogId+" #courseList tbody").append('<tr><td>'+tCourse.id+'</td><td>'+tCourse.name+'</td></tr>');
893 });
894 //will throw out of loop if number of courses > 10000 -- if you have more than 10000 units, increase the pNum check
895 if (xhr.getResponseHeader('Link').indexOf('rel="next"') > 0 && pNum < 100) {
896 pNum++;
897 window.canvasExtension.listNextCourses(pNum);
898 } else {
899 window.canvasExtension.addCourseResults();
900 }
901 },
902 error: function(xhr, textStatus, errorThrown) {
903 console.log("error: " + errorThrown);
904 }
905 });
906}
907
908window.canvasExtension.addCourseResults = function() {
909 console.log(window.canvasExtension.allCourses);
910}
911
912
913//---- RUN THE INIT ------------------------------
914
915window.canvasExtension.initCanvasExtensionMenu();