[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('moodle-course-management', function (Y, NAME) { 2 3 /* global DragDrop, Category, Course */ 4 5 /** 6 * Provides drop down menus for list of action links. 7 * 8 * @module moodle-course-management 9 */ 10 11 /** 12 * Management JS console. 13 * 14 * Provides the organisation for course and category management JS. 15 * 16 * @namespace M.course.management 17 * @class Console 18 * @constructor 19 * @extends Base 20 */ 21 function Console() { 22 Console.superclass.constructor.apply(this, arguments); 23 } 24 Console.NAME = 'moodle-course-management'; 25 Console.CSS_PREFIX = 'management'; 26 Console.ATTRS = { 27 /** 28 * The HTML element containing the management interface. 29 * @attribute element 30 * @type Node 31 */ 32 element: { 33 setter: function(node) { 34 if (typeof node === 'string') { 35 node = Y.one('#' + node); 36 } 37 return node; 38 } 39 }, 40 41 /** 42 * The category listing container node. 43 * @attribute categorylisting 44 * @type Node 45 * @default null 46 */ 47 categorylisting: { 48 value: null 49 }, 50 51 /** 52 * The course listing container node. 53 * @attribute courselisting 54 * @type Node 55 * @default null 56 */ 57 courselisting: { 58 value: null 59 }, 60 61 /** 62 * The course details container node. 63 * @attribute coursedetails 64 * @type Node|null 65 * @default null 66 */ 67 coursedetails: { 68 value: null 69 }, 70 71 /** 72 * The id of the currently active category. 73 * @attribute activecategoryid 74 * @type Number 75 * @default null 76 */ 77 activecategoryid: { 78 value: null 79 }, 80 81 /** 82 * The id of the currently active course. 83 * @attribute activecourseid 84 * @type Number 85 * @default Null 86 */ 87 activecourseid: { 88 value: null 89 }, 90 91 /** 92 * The categories that are currently available through the management interface. 93 * @attribute categories 94 * @type Array 95 * @default [] 96 */ 97 categories: { 98 setter: function(item, name) { 99 if (Y.Lang.isArray(item)) { 100 return item; 101 } 102 var items = this.get(name); 103 items.push(item); 104 return items; 105 }, 106 value: [] 107 }, 108 109 /** 110 * The courses that are currently available through the management interface. 111 * @attribute courses 112 * @type Course[] 113 * @default Array 114 */ 115 courses: { 116 validator: function(val) { 117 return Y.Lang.isArray(val); 118 }, 119 value: [] 120 }, 121 122 /** 123 * The currently displayed page of courses. 124 * @attribute page 125 * @type Number 126 * @default null 127 */ 128 page: { 129 getter: function(value, name) { 130 if (value === null) { 131 value = this.get('element').getData(name); 132 this.set(name, value); 133 } 134 return value; 135 }, 136 value: null 137 }, 138 139 /** 140 * The total pages of courses that can be shown for this category. 141 * @attribute totalpages 142 * @type Number 143 * @default null 144 */ 145 totalpages: { 146 getter: function(value, name) { 147 if (value === null) { 148 value = this.get('element').getData(name); 149 this.set(name, value); 150 } 151 return value; 152 }, 153 value: null 154 }, 155 156 /** 157 * The total number of courses belonging to this category. 158 * @attribute totalcourses 159 * @type Number 160 * @default null 161 */ 162 totalcourses: { 163 getter: function(value, name) { 164 if (value === null) { 165 value = this.get('element').getData(name); 166 this.set(name, value); 167 } 168 return value; 169 }, 170 value: null 171 }, 172 173 /** 174 * The URL to use for AJAX actions/requests. 175 * @attribute ajaxurl 176 * @type String 177 * @default /course/ajax/management.php 178 */ 179 ajaxurl: { 180 getter: function(value) { 181 if (value === null) { 182 value = M.cfg.wwwroot + '/course/ajax/management.php'; 183 } 184 return value; 185 }, 186 value: null 187 }, 188 189 /** 190 * The drag drop handler 191 * @attribute dragdrop 192 * @type DragDrop 193 * @default null 194 */ 195 dragdrop: { 196 value: null 197 } 198 }; 199 Console.prototype = { 200 201 /** 202 * Gets set to true once the first categories have been initialised. 203 * @property categoriesinit 204 * @private 205 * @type {boolean} 206 */ 207 categoriesinit: false, 208 209 /** 210 * Initialises a new instance of the Console. 211 * @method initializer 212 */ 213 initializer: function() { 214 Y.log('Initialising course category management console', 'info', 'moodle-course-management'); 215 this.set('element', 'coursecat-management'); 216 var element = this.get('element'), 217 categorylisting = element.one('#category-listing'), 218 courselisting = element.one('#course-listing'), 219 selectedcategory = null, 220 selectedcourse = null; 221 222 if (categorylisting) { 223 selectedcategory = categorylisting.one('.listitem[data-selected="1"]'); 224 } 225 if (courselisting) { 226 selectedcourse = courselisting.one('.listitem[data-selected="1"]'); 227 } 228 this.set('categorylisting', categorylisting); 229 this.set('courselisting', courselisting); 230 this.set('coursedetails', element.one('#course-detail')); 231 if (selectedcategory) { 232 this.set('activecategoryid', selectedcategory.getData('id')); 233 } 234 if (selectedcourse) { 235 this.set('activecourseid', selectedcourse.getData('id')); 236 } 237 this.initialiseCategories(categorylisting); 238 this.initialiseCourses(); 239 240 if (courselisting) { 241 // No need for dragdrop if we don't have a course listing. 242 this.set('dragdrop', new DragDrop({console: this})); 243 } 244 }, 245 246 /** 247 * Initialises all the categories being shown. 248 * @method initialiseCategories 249 * @private 250 * @return {boolean} 251 */ 252 initialiseCategories: function(listing) { 253 var count = 0; 254 if (!listing) { 255 return false; 256 } 257 258 // Disable category bulk actions as nothing will be selected on initialise. 259 var menumovecatto = listing.one('#menumovecategoriesto'); 260 if (menumovecatto) { 261 menumovecatto.setAttribute('disabled', true); 262 } 263 var menuresortcategoriesby = listing.one('#menuresortcategoriesby'); 264 if (menuresortcategoriesby) { 265 menuresortcategoriesby.setAttribute('disabled', true); 266 } 267 var menuresortcoursesby = listing.one('#menuresortcoursesby'); 268 if (menuresortcoursesby) { 269 menuresortcoursesby.setAttribute('disabled', true); 270 } 271 272 listing.all('.listitem[data-id]').each(function(node) { 273 this.set('categories', new Category({ 274 node: node, 275 console: this 276 })); 277 count++; 278 }, this); 279 if (!this.categoriesinit) { 280 this.get('categorylisting').delegate('click', this.handleCategoryDelegation, 'a[data-action]', this); 281 this.get('categorylisting').delegate('click', this.handleCategoryDelegation, 'input[name="bcat[]"]', this); 282 this.get('categorylisting').delegate('click', this.handleBulkSortByaction, '#menuselectsortby', this); 283 this.categoriesinit = true; 284 Y.log(count + ' categories being managed', 'info', 'moodle-course-management'); 285 } else { 286 Y.log(count + ' new categories being managed', 'info', 'moodle-course-management'); 287 } 288 }, 289 290 /** 291 * Initialises all the categories being shown. 292 * @method initialiseCourses 293 * @private 294 * @return {boolean} 295 */ 296 initialiseCourses: function() { 297 var category = this.getCategoryById(this.get('activecategoryid')), 298 listing = this.get('courselisting'), 299 count = 0; 300 if (!listing) { 301 return false; 302 } 303 304 // Disable course move to bulk action as nothing will be selected on initialise. 305 var menumovecoursesto = listing.one('#menumovecoursesto'); 306 if (menumovecoursesto) { 307 menumovecoursesto.setAttribute('disabled', true); 308 } 309 310 listing.all('.listitem[data-id]').each(function(node) { 311 this.registerCourse(new Course({ 312 node: node, 313 console: this, 314 category: category 315 })); 316 count++; 317 }, this); 318 listing.delegate('click', this.handleCourseDelegation, 'a[data-action]', this); 319 listing.delegate('click', this.handleCourseDelegation, 'input[name="bc[]"]', this); 320 Y.log(count + ' courses being managed', 'info', 'moodle-course-management'); 321 }, 322 323 /** 324 * Registers a course within the management display. 325 * @method registerCourse 326 * @param {Course} course 327 */ 328 registerCourse: function(course) { 329 var courses = this.get('courses'); 330 courses.push(course); 331 this.set('courses', courses); 332 }, 333 334 /** 335 * Handles the event fired by a delegated course listener. 336 * 337 * @method handleCourseDelegation 338 * @protected 339 * @param {EventFacade} e 340 */ 341 handleCourseDelegation: function(e) { 342 var target = e.currentTarget, 343 action = target.getData('action'), 344 courseid = target.ancestor('.listitem').getData('id'), 345 course = this.getCourseById(courseid); 346 if (course) { 347 course.handle(action, e); 348 } else { 349 Y.log('Course with ID ' + courseid + ' could not be found for delegation', 'error', 'moodle-course-management'); 350 } 351 }, 352 353 /** 354 * Handles the event fired by a delegated course listener. 355 * 356 * @method handleCategoryDelegation 357 * @protected 358 * @param {EventFacade} e 359 */ 360 handleCategoryDelegation: function(e) { 361 var target = e.currentTarget, 362 action = target.getData('action'), 363 categoryid = target.ancestor('.listitem').getData('id'), 364 category = this.getCategoryById(categoryid); 365 if (category) { 366 category.handle(action, e); 367 } else { 368 Y.log('Could not find category to delegate to.', 'error', 'moodle-course-management'); 369 } 370 }, 371 372 /** 373 * Check if any course is selected. 374 * 375 * @method isCourseSelected 376 * @param {Node} checkboxnode Checkbox node on which action happened. 377 * @return bool 378 */ 379 isCourseSelected: function(checkboxnode) { 380 var selected = false; 381 382 // If any course selected then show move to category select box. 383 if (checkboxnode && checkboxnode.get('checked')) { 384 selected = true; 385 } else { 386 var i, 387 course, 388 courses = this.get('courses'), 389 length = courses.length; 390 for (i = 0; i < length; i++) { 391 if (courses.hasOwnProperty(i)) { 392 course = courses[i]; 393 if (course.get('node').one('input[name="bc[]"]').get('checked')) { 394 selected = true; 395 break; 396 } 397 } 398 } 399 } 400 return selected; 401 }, 402 403 /** 404 * Check if any category is selected. 405 * 406 * @method isCategorySelected 407 * @param {Node} checkboxnode Checkbox node on which action happened. 408 * @return bool 409 */ 410 isCategorySelected: function(checkboxnode) { 411 var selected = false; 412 413 // If any category selected then show move to category select box. 414 if (checkboxnode && checkboxnode.get('checked')) { 415 selected = true; 416 } else { 417 var i, 418 category, 419 categories = this.get('categories'), 420 length = categories.length; 421 for (i = 0; i < length; i++) { 422 if (categories.hasOwnProperty(i)) { 423 category = categories[i]; 424 if (category.get('node').one('input[name="bcat[]"]').get('checked')) { 425 selected = true; 426 break; 427 } 428 } 429 } 430 } 431 return selected; 432 }, 433 434 /** 435 * Handle bulk sort action. 436 * 437 * @method handleBulkSortByaction 438 * @protected 439 * @param {EventFacade} e 440 */ 441 handleBulkSortByaction: function(e) { 442 var sortcategoryby = this.get('categorylisting').one('#menuresortcategoriesby'), 443 sortcourseby = this.get('categorylisting').one('#menuresortcoursesby'), 444 sortbybutton = this.get('categorylisting').one('input[name="bulksort"]'), 445 sortby = e; 446 447 if (!sortby) { 448 sortby = this.get('categorylisting').one('#menuselectsortby'); 449 } else { 450 if (e && e.currentTarget) { 451 sortby = e.currentTarget; 452 } 453 } 454 455 // If no sortby select found then return as we can't do anything. 456 if (!sortby) { 457 return; 458 } 459 460 if ((this.get('categories').length <= 1) || (!this.isCategorySelected() && 461 (sortby.get("options").item(sortby.get('selectedIndex')).getAttribute('value') === 'selectedcategories'))) { 462 if (sortcategoryby) { 463 sortcategoryby.setAttribute('disabled', true); 464 } 465 if (sortcourseby) { 466 sortcourseby.setAttribute('disabled', true); 467 } 468 if (sortbybutton) { 469 sortbybutton.setAttribute('disabled', true); 470 } 471 } else { 472 if (sortcategoryby) { 473 sortcategoryby.removeAttribute('disabled'); 474 } 475 if (sortcourseby) { 476 sortcourseby.removeAttribute('disabled'); 477 } 478 if (sortbybutton) { 479 sortbybutton.removeAttribute('disabled'); 480 } 481 } 482 }, 483 484 /** 485 * Returns the category with the given ID. 486 * @method getCategoryById 487 * @param {Number} id 488 * @return {Category|Boolean} The category or false if it can't be found. 489 */ 490 getCategoryById: function(id) { 491 var i, 492 category, 493 categories = this.get('categories'), 494 length = categories.length; 495 for (i = 0; i < length; i++) { 496 if (categories.hasOwnProperty(i)) { 497 category = categories[i]; 498 if (category.get('categoryid') === id) { 499 return category; 500 } 501 } 502 } 503 return false; 504 }, 505 506 /** 507 * Returns the course with the given id. 508 * @method getCourseById 509 * @param {Number} id 510 * @return {Course|Boolean} The course or false if not found/ 511 */ 512 getCourseById: function(id) { 513 var i, 514 course, 515 courses = this.get('courses'), 516 length = courses.length; 517 for (i = 0; i < length; i++) { 518 if (courses.hasOwnProperty(i)) { 519 course = courses[i]; 520 if (course.get('courseid') === id) { 521 return course; 522 } 523 } 524 } 525 return false; 526 }, 527 528 /** 529 * Removes the course with the given ID. 530 * @method removeCourseById 531 * @param {Number} id 532 */ 533 removeCourseById: function(id) { 534 var courses = this.get('courses'), 535 length = courses.length, 536 course, 537 i; 538 for (i = 0; i < length; i++) { 539 course = courses[i]; 540 if (course.get('courseid') === id) { 541 courses.splice(i, 1); 542 break; 543 } 544 } 545 }, 546 547 /** 548 * Performs an AJAX action. 549 * 550 * @method performAjaxAction 551 * @param {String} action The action to perform. 552 * @param {Object} args The arguments to pass through with teh request. 553 * @param {Function} callback The function to call when all is done. 554 * @param {Object} context The object to use as the context for the callback. 555 */ 556 performAjaxAction: function(action, args, callback, context) { 557 var io = new Y.IO(); 558 args.action = action; 559 args.ajax = '1'; 560 args.sesskey = M.cfg.sesskey; 561 if (callback === null) { 562 callback = function() { 563 Y.log("'Action '" + action + "' completed", 'debug', 'moodle-course-management'); 564 }; 565 } 566 io.send(this.get('ajaxurl'), { 567 method: 'POST', 568 on: { 569 complete: callback 570 }, 571 context: context, 572 data: args, 573 'arguments': args 574 }); 575 } 576 }; 577 Y.extend(Console, Y.Base, Console.prototype); 578 579 M.course = M.course || {}; 580 M.course.management = M.course.management || {}; 581 M.course.management.console = null; 582 583 /** 584 * Initalises the course management console. 585 * 586 * @method M.course.management.init 587 * @static 588 * @param {Object} config 589 */ 590 M.course.management.init = function(config) { 591 M.course.management.console = new Console(config); 592 }; 593 /* global Console */ 594 595 /** 596 * Drag and Drop handler 597 * 598 * @namespace M.course.management 599 * @class DragDrop 600 * @constructor 601 * @extends Base 602 */ 603 function DragDrop(config) { 604 Console.superclass.constructor.apply(this, [config]); 605 } 606 DragDrop.NAME = 'moodle-course-management-dd'; 607 DragDrop.CSS_PREFIX = 'management-dd'; 608 DragDrop.ATTRS = { 609 /** 610 * The management console this drag and drop has been set up for. 611 * @attribute console 612 * @type Console 613 * @writeOnce 614 */ 615 console: { 616 writeOnce: 'initOnly' 617 } 618 }; 619 DragDrop.prototype = { 620 /** 621 * True if the user is dragging a course upwards. 622 * @property goingup 623 * @protected 624 * @default false 625 */ 626 goingup: false, 627 628 /** 629 * The last Y position of the course being dragged 630 * @property lasty 631 * @protected 632 * @default null 633 */ 634 lasty: null, 635 636 /** 637 * The sibling above the course being dragged currently (tracking its original position). 638 * 639 * @property previoussibling 640 * @protected 641 * @default false 642 */ 643 previoussibling: null, 644 645 /** 646 * Initialises the DragDrop instance. 647 * @method initializer 648 */ 649 initializer: function() { 650 var managementconsole = this.get('console'), 651 container = managementconsole.get('element'), 652 categorylisting = container.one('#category-listing'), 653 courselisting = container.one('#course-listing > .course-listing'), 654 categoryul = (categorylisting) ? categorylisting.one('ul.ml') : null, 655 courseul = (courselisting) ? courselisting.one('ul.ml') : null, 656 canmoveoutof = (courselisting) ? courselisting.getData('canmoveoutof') : false, 657 contstraint = (canmoveoutof) ? container : courseul; 658 659 if (!courseul) { 660 // No course listings found. 661 return false; 662 } 663 664 courseul.all('> li').each(function(li) { 665 this.initCourseListing(li, contstraint); 666 }, this); 667 courseul.setData('dd', new Y.DD.Drop({ 668 node: courseul 669 })); 670 if (canmoveoutof && categoryul) { 671 // Category UL may not be there if viewmode is just courses. 672 categoryul.all('li > div').each(function(div) { 673 this.initCategoryListitem(div); 674 }, this); 675 } 676 Y.DD.DDM.on('drag:start', this.dragStart, this); 677 Y.DD.DDM.on('drag:end', this.dragEnd, this); 678 Y.DD.DDM.on('drag:drag', this.dragDrag, this); 679 Y.DD.DDM.on('drop:over', this.dropOver, this); 680 Y.DD.DDM.on('drop:enter', this.dropEnter, this); 681 Y.DD.DDM.on('drop:exit', this.dropExit, this); 682 Y.DD.DDM.on('drop:hit', this.dropHit, this); 683 684 }, 685 686 /** 687 * Initialises a course listing. 688 * @method initCourseListing 689 * @param Node 690 */ 691 initCourseListing: function(node, contstraint) { 692 node.setData('dd', new Y.DD.Drag({ 693 node: node, 694 target: { 695 padding: '0 0 0 20' 696 } 697 }).addHandle( 698 '.drag-handle' 699 ).plug(Y.Plugin.DDProxy, { 700 moveOnEnd: false, 701 borderStyle: false 702 }).plug(Y.Plugin.DDConstrained, { 703 constrain2node: contstraint 704 })); 705 }, 706 707 /** 708 * Initialises a category listing. 709 * @method initCategoryListitem 710 * @param Node 711 */ 712 initCategoryListitem: function(node) { 713 node.setData('dd', new Y.DD.Drop({ 714 node: node 715 })); 716 }, 717 718 /** 719 * Dragging has started. 720 * @method dragStart 721 * @private 722 * @param {EventFacade} e 723 */ 724 dragStart: function(e) { 725 var drag = e.target, 726 node = drag.get('node'), 727 dragnode = drag.get('dragNode'); 728 node.addClass('course-being-dragged'); 729 dragnode.addClass('course-being-dragged-proxy').set('innerHTML', node.one('a.coursename').get('innerHTML')); 730 this.previoussibling = node.get('previousSibling'); 731 }, 732 733 /** 734 * Dragging has ended. 735 * @method dragEnd 736 * @private 737 * @param {EventFacade} e 738 */ 739 dragEnd: function(e) { 740 var drag = e.target, 741 node = drag.get('node'); 742 node.removeClass('course-being-dragged'); 743 this.get('console').get('element').all('#category-listing li.highlight').removeClass('highlight'); 744 }, 745 746 /** 747 * Dragging in progress. 748 * @method dragDrag 749 * @private 750 * @param {EventFacade} e 751 */ 752 dragDrag: function(e) { 753 var y = e.target.lastXY[1]; 754 if (y < this.lasty) { 755 this.goingup = true; 756 } else { 757 this.goingup = false; 758 } 759 this.lasty = y; 760 }, 761 762 /** 763 * The course has been dragged over a drop target. 764 * @method dropOver 765 * @private 766 * @param {EventFacade} e 767 */ 768 dropOver: function(e) { 769 // Get a reference to our drag and drop nodes 770 var drag = e.drag.get('node'), 771 drop = e.drop.get('node'), 772 tag = drop.get('tagName').toLowerCase(); 773 if (tag === 'li' && drop.hasClass('listitem-course')) { 774 if (!this.goingup) { 775 drop = drop.get('nextSibling'); 776 if (!drop) { 777 drop = e.drop.get('node'); 778 drop.get('parentNode').append(drag); 779 return false; 780 } 781 } 782 drop.get('parentNode').insertBefore(drag, drop); 783 e.drop.sizeShim(); 784 } 785 }, 786 787 /** 788 * The course has been dragged over a drop target. 789 * @method dropEnter 790 * @private 791 * @param {EventFacade} e 792 */ 793 dropEnter: function(e) { 794 var drop = e.drop.get('node'), 795 tag = drop.get('tagName').toLowerCase(); 796 if (tag === 'div') { 797 drop.ancestor('li.listitem-category').addClass('highlight'); 798 } 799 }, 800 801 /** 802 * The course has been dragged off a drop target. 803 * @method dropExit 804 * @private 805 * @param {EventFacade} e 806 */ 807 dropExit: function(e) { 808 var drop = e.drop.get('node'), 809 tag = drop.get('tagName').toLowerCase(); 810 if (tag === 'div') { 811 drop.ancestor('li.listitem-category').removeClass('highlight'); 812 } 813 }, 814 815 /** 816 * The course has been dropped on a target. 817 * @method dropHit 818 * @private 819 * @param {EventFacade} e 820 */ 821 dropHit: function(e) { 822 var drag = e.drag.get('node'), 823 drop = e.drop.get('node'), 824 iscategory = (drop.ancestor('.listitem-category') !== null), 825 iscourse = !iscategory && (drop.test('.listitem-course')), 826 managementconsole = this.get('console'), 827 categoryid, 828 category, 829 courseid, 830 course, 831 aftercourseid, 832 previoussibling, 833 previousid; 834 835 if (!drag.test('.listitem-course')) { 836 Y.log('It was not a course being dragged.', 'warn', 'moodle-course-management'); 837 return false; 838 } 839 courseid = drag.getData('id'); 840 if (iscategory) { 841 categoryid = drop.ancestor('.listitem-category').getData('id'); 842 Y.log('Course ' + courseid + ' dragged into category ' + categoryid); 843 category = managementconsole.getCategoryById(categoryid); 844 if (category) { 845 course = managementconsole.getCourseById(courseid); 846 if (course) { 847 category.moveCourseTo(course); 848 } 849 } 850 } else if (iscourse || drop.ancestor('#course-listing')) { 851 course = managementconsole.getCourseById(courseid); 852 previoussibling = drag.get('previousSibling'); 853 aftercourseid = (previoussibling) ? previoussibling.getData('id') || 0 : 0; 854 previousid = (this.previoussibling) ? this.previoussibling.getData('id') : 0; 855 if (aftercourseid !== previousid) { 856 course.moveAfter(aftercourseid, previousid); 857 } 858 } else { 859 Y.log('Course dropped over unhandled target.', 'info', 'moodle-course-management'); 860 } 861 } 862 }; 863 Y.extend(DragDrop, Y.Base, DragDrop.prototype); 864 /** 865 * A managed course. 866 * 867 * @namespace M.course.management 868 * @class Item 869 * @constructor 870 * @extends Base 871 */ 872 function Item() { 873 Item.superclass.constructor.apply(this, arguments); 874 } 875 Item.NAME = 'moodle-course-management-item'; 876 Item.CSS_PREFIX = 'management-item'; 877 Item.ATTRS = { 878 /** 879 * The node for this item. 880 * @attribute node 881 * @type Node 882 */ 883 node: {}, 884 885 /** 886 * The management console. 887 * @attribute console 888 * @type Console 889 */ 890 console: {}, 891 892 /** 893 * Describes the type of this item. Should be set by the extending class. 894 * @attribute itemname 895 * @type {String} 896 * @default item 897 */ 898 itemname: { 899 value: 'item' 900 } 901 }; 902 Item.prototype = { 903 /** 904 * The highlight timeout for this item if there is one. 905 * @property highlighttimeout 906 * @protected 907 * @type Timeout 908 * @default null 909 */ 910 highlighttimeout: null, 911 912 /** 913 * Checks and parses an AJAX response for an item. 914 * 915 * @method checkAjaxResponse 916 * @protected 917 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 918 * @param {Object} response The response from the AJAX request. 919 * @param {Object} args The arguments given to the request. 920 * @return {Object|Boolean} 921 */ 922 checkAjaxResponse: function(transactionid, response, args) { 923 if (response.status !== 200) { 924 Y.log('Error: AJAX response resulted in non 200 status.', 'error', 'Item.checkAjaxResponse'); 925 return false; 926 } 927 if (transactionid === null || args === null) { 928 Y.log('Error: Invalid AJAX response details provided.', 'error', 'Item.checkAjaxResponse'); 929 return false; 930 } 931 var outcome = Y.JSON.parse(response.responseText); 932 if (outcome.error !== false) { 933 new M.core.exception(outcome); 934 } 935 if (outcome.outcome === false) { 936 return false; 937 } 938 return outcome; 939 }, 940 941 /** 942 * Moves an item up by one. 943 * 944 * @method moveup 945 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 946 * @param {Object} response The response from the AJAX request. 947 * @param {Object} args The arguments given to the request. 948 * @return {Boolean} 949 */ 950 moveup: function(transactionid, response, args) { 951 var node, 952 nodeup, 953 nodedown, 954 previous, 955 previousup, 956 previousdown, 957 tmpnode, 958 outcome = this.checkAjaxResponse(transactionid, response, args); 959 if (outcome === false) { 960 Y.log('AJAX request to move ' + this.get('itemname') + ' up failed by outcome.', 'warn', 'moodle-course-management'); 961 return false; 962 } 963 node = this.get('node'); 964 previous = node.previous('.listitem'); 965 if (previous) { 966 previous.insert(node, 'before'); 967 previousup = previous.one(' > div a.action-moveup'); 968 nodedown = node.one(' > div a.action-movedown'); 969 if (!previousup || !nodedown) { 970 // We can have two situations here: 971 // 1. previousup is not set and nodedown is not set. This happens when there are only two courses. 972 // 2. nodedown is not set. This happens when they are moving the bottom course up. 973 // node up and previous down should always be there. They would be required to trigger the action. 974 nodeup = node.one(' > div a.action-moveup'); 975 previousdown = previous.one(' > div a.action-movedown'); 976 if (!previousup && !nodedown) { 977 // Ok, must be two courses. We need to switch the up and down icons. 978 tmpnode = Y.Node.create('<a style="visibility:hidden;"> </a>'); 979 previousdown.replace(tmpnode); 980 nodeup.replace(previousdown); 981 tmpnode.replace(nodeup); 982 tmpnode.destroy(); 983 } else if (!nodedown) { 984 // previous down needs to be given to node. 985 nodeup.insert(previousdown, 'after'); 986 } 987 } 988 nodeup = node.one(' > div a.action-moveup'); 989 if (nodeup) { 990 // Try to re-focus on up. 991 nodeup.focus(); 992 } else { 993 // If we can't focus up we're at the bottom, try to focus on up. 994 nodedown = node.one(' > div a.action-movedown'); 995 if (nodedown) { 996 nodedown.focus(); 997 } 998 } 999 this.updated(true); 1000 Y.log('Success: ' + this.get('itemname') + ' moved up by AJAX.', 'info', 'moodle-course-management'); 1001 } else { 1002 // Aha it succeeded but this is the top item in the list. Pagination is in play! 1003 // Refresh to update the state of things. 1004 Y.log(this.get('itemname') + ' cannot be moved up as its the top item on this page.', 1005 'info', 'moodle-course-management'); 1006 window.location.reload(); 1007 } 1008 }, 1009 1010 /** 1011 * Moves an item down by one. 1012 * 1013 * @method movedown 1014 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1015 * @param {Object} response The response from the AJAX request. 1016 * @param {Object} args The arguments given to the request. 1017 * @return {Boolean} 1018 */ 1019 movedown: function(transactionid, response, args) { 1020 var node, 1021 next, 1022 nodeup, 1023 nodedown, 1024 nextup, 1025 nextdown, 1026 tmpnode, 1027 outcome = this.checkAjaxResponse(transactionid, response, args); 1028 if (outcome === false) { 1029 Y.log('AJAX request to move ' + this.get('itemname') + ' down failed by outcome.', 'warn', 'moodle-course-management'); 1030 return false; 1031 } 1032 node = this.get('node'); 1033 next = node.next('.listitem'); 1034 if (next) { 1035 node.insert(next, 'before'); 1036 nextdown = next.one(' > div a.action-movedown'); 1037 nodeup = node.one(' > div a.action-moveup'); 1038 if (!nextdown || !nodeup) { 1039 // next up and node down should always be there. They would be required to trigger the action. 1040 nextup = next.one(' > div a.action-moveup'); 1041 nodedown = node.one(' > div a.action-movedown'); 1042 if (!nextdown && !nodeup) { 1043 // We can have two situations here: 1044 // 1. nextdown is not set and nodeup is not set. This happens when there are only two courses. 1045 // 2. nodeup is not set. This happens when we are moving the first course down. 1046 // Ok, must be two courses. We need to switch the up and down icons. 1047 tmpnode = Y.Node.create('<a style="visibility:hidden;"> </a>'); 1048 nextup.replace(tmpnode); 1049 nodedown.replace(nextup); 1050 tmpnode.replace(nodedown); 1051 tmpnode.destroy(); 1052 } else if (!nodeup) { 1053 // next up needs to be given to node. 1054 nodedown.insert(nextup, 'before'); 1055 } 1056 } 1057 nodedown = node.one(' > div a.action-movedown'); 1058 if (nodedown) { 1059 // Try to ensure the up is focused again. 1060 nodedown.focus(); 1061 } else { 1062 // If we can't focus up we're at the top, try to focus on down. 1063 nodeup = node.one(' > div a.action-moveup'); 1064 if (nodeup) { 1065 nodeup.focus(); 1066 } 1067 } 1068 this.updated(true); 1069 Y.log('Success: ' + this.get('itemname') + ' moved down by AJAX.', 'info', 'moodle-course-management'); 1070 } else { 1071 // Aha it succeeded but this is the bottom item in the list. Pagination is in play! 1072 // Refresh to update the state of things. 1073 Y.log(this.get('itemname') + ' cannot be moved down as its the top item on this page.', 1074 'info', 'moodle-course-management'); 1075 window.location.reload(); 1076 } 1077 }, 1078 1079 /** 1080 * Makes an item visible. 1081 * 1082 * @method show 1083 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1084 * @param {Object} response The response from the AJAX request. 1085 * @param {Object} args The arguments given to the request. 1086 * @return {Boolean} 1087 */ 1088 show: function(transactionid, response, args) { 1089 var outcome = this.checkAjaxResponse(transactionid, response, args), 1090 hidebtn; 1091 if (outcome === false) { 1092 Y.log('AJAX request to show ' + this.get('itemname') + ' by outcome.', 'warn', 'moodle-course-management'); 1093 return false; 1094 } 1095 1096 this.markVisible(); 1097 hidebtn = this.get('node').one('a[data-action=hide]'); 1098 if (hidebtn) { 1099 hidebtn.focus(); 1100 } 1101 this.updated(); 1102 Y.log('Success: ' + this.get('itemname') + ' made visible by AJAX.', 'info', 'moodle-course-management'); 1103 }, 1104 1105 /** 1106 * Marks the item as visible 1107 * @method markVisible 1108 */ 1109 markVisible: function() { 1110 this.get('node').setAttribute('data-visible', '1'); 1111 Y.log('Marked ' + this.get('itemname') + ' as visible', 'info', 'moodle-course-management'); 1112 return true; 1113 }, 1114 1115 /** 1116 * Hides an item. 1117 * 1118 * @method hide 1119 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1120 * @param {Object} response The response from the AJAX request. 1121 * @param {Object} args The arguments given to the request. 1122 * @return {Boolean} 1123 */ 1124 hide: function(transactionid, response, args) { 1125 var outcome = this.checkAjaxResponse(transactionid, response, args), 1126 showbtn; 1127 if (outcome === false) { 1128 Y.log('AJAX request to hide ' + this.get('itemname') + ' by outcome.', 'warn', 'moodle-course-management'); 1129 return false; 1130 } 1131 this.markHidden(); 1132 showbtn = this.get('node').one('a[data-action=show]'); 1133 if (showbtn) { 1134 showbtn.focus(); 1135 } 1136 this.updated(); 1137 Y.log('Success: ' + this.get('itemname') + ' made hidden by AJAX.', 'info', 'moodle-course-management'); 1138 }, 1139 1140 /** 1141 * Marks the item as hidden. 1142 * @method makeHidden 1143 */ 1144 markHidden: function() { 1145 this.get('node').setAttribute('data-visible', '0'); 1146 Y.log('Marked ' + this.get('itemname') + ' as hidden', 'info', 'moodle-course-management'); 1147 return true; 1148 }, 1149 1150 /** 1151 * Called when ever a node is updated. 1152 * 1153 * @method updated 1154 * @param {Boolean} moved True if this item was moved. 1155 */ 1156 updated: function(moved) { 1157 if (moved) { 1158 this.highlight(); 1159 } 1160 }, 1161 1162 /** 1163 * Highlights this option for a breif time. 1164 * 1165 * @method highlight 1166 */ 1167 highlight: function() { 1168 var node = this.get('node'); 1169 node.siblings('.highlight').removeClass('highlight'); 1170 node.addClass('highlight'); 1171 if (this.highlighttimeout) { 1172 window.clearTimeout(this.highlighttimeout); 1173 } 1174 this.highlighttimeout = window.setTimeout(function() { 1175 node.removeClass('highlight'); 1176 }, 2500); 1177 } 1178 }; 1179 Y.extend(Item, Y.Base, Item.prototype); 1180 /* global Item */ 1181 1182 /** 1183 * A managed category. 1184 * 1185 * @namespace M.course.management 1186 * @class Category 1187 * @constructor 1188 * @extends Item 1189 */ 1190 function Category() { 1191 Category.superclass.constructor.apply(this, arguments); 1192 } 1193 Category.NAME = 'moodle-course-management-category'; 1194 Category.CSS_PREFIX = 'management-category'; 1195 Category.ATTRS = { 1196 /** 1197 * The category ID relating to this category. 1198 * @attribute categoryid 1199 * @type Number 1200 * @writeOnce 1201 * @default null 1202 */ 1203 categoryid: { 1204 getter: function(value, name) { 1205 if (value === null) { 1206 value = this.get('node').getData('id'); 1207 this.set(name, value); 1208 } 1209 return value; 1210 }, 1211 value: null, 1212 writeOnce: true 1213 }, 1214 1215 /** 1216 * True if this category is the currently selected category. 1217 * @attribute selected 1218 * @type Boolean 1219 * @default null 1220 */ 1221 selected: { 1222 getter: function(value, name) { 1223 if (value === null) { 1224 value = this.get('node').getData(name); 1225 if (value === null) { 1226 value = false; 1227 } 1228 this.set(name, value); 1229 } 1230 return value; 1231 }, 1232 value: null 1233 }, 1234 1235 /** 1236 * An array of courses belonging to this category. 1237 * @attribute courses 1238 * @type Course[] 1239 * @default Array 1240 */ 1241 courses: { 1242 validator: function(val) { 1243 return Y.Lang.isArray(val); 1244 }, 1245 value: [] 1246 } 1247 }; 1248 Category.prototype = { 1249 /** 1250 * Initialises an instance of a Category. 1251 * @method initializer 1252 */ 1253 initializer: function() { 1254 this.set('itemname', 'category'); 1255 }, 1256 1257 /** 1258 * Returns the name of the category. 1259 * @method getName 1260 * @return {String} 1261 */ 1262 getName: function() { 1263 return this.get('node').one('a.categoryname').get('innerHTML'); 1264 }, 1265 1266 /** 1267 * Registers a course as belonging to this category. 1268 * @method registerCourse 1269 * @param {Course} course 1270 */ 1271 registerCourse: function(course) { 1272 var courses = this.get('courses'); 1273 courses.push(course); 1274 this.set('courses', courses); 1275 }, 1276 1277 /** 1278 * Handles a category related event. 1279 * 1280 * @method handle 1281 * @param {String} action 1282 * @param {EventFacade} e 1283 * @return {Boolean} 1284 */ 1285 handle: function(action, e) { 1286 var catarg = {categoryid: this.get('categoryid')}, 1287 selected = this.get('console').get('activecategoryid'); 1288 if (selected && selected !== catarg.categoryid) { 1289 catarg.selectedcategory = selected; 1290 } 1291 switch (action) { 1292 case 'moveup': 1293 e.preventDefault(); 1294 this.get('console').performAjaxAction('movecategoryup', catarg, this.moveup, this); 1295 break; 1296 case 'movedown': 1297 e.preventDefault(); 1298 this.get('console').performAjaxAction('movecategorydown', catarg, this.movedown, this); 1299 break; 1300 case 'show': 1301 e.preventDefault(); 1302 this.get('console').performAjaxAction('showcategory', catarg, this.show, this); 1303 break; 1304 case 'hide': 1305 e.preventDefault(); 1306 this.get('console').performAjaxAction('hidecategory', catarg, this.hide, this); 1307 break; 1308 case 'expand': 1309 e.preventDefault(); 1310 if (this.get('node').getData('expanded') === '0') { 1311 this.get('node').setAttribute('data-expanded', '1').setData('expanded', 'true'); 1312 this.get('console').performAjaxAction('getsubcategorieshtml', catarg, this.loadSubcategories, this); 1313 } 1314 this.expand(); 1315 break; 1316 case 'collapse': 1317 e.preventDefault(); 1318 this.collapse(); 1319 break; 1320 case 'select': 1321 var c = this.get('console'), 1322 movecategoryto = c.get('categorylisting').one('#menumovecategoriesto'); 1323 // If any category is selected and there are more then one categories. 1324 if (movecategoryto) { 1325 if (c.isCategorySelected(e.currentTarget) && 1326 c.get('categories').length > 1) { 1327 movecategoryto.removeAttribute('disabled'); 1328 } else { 1329 movecategoryto.setAttribute('disabled', true); 1330 } 1331 c.handleBulkSortByaction(); 1332 } 1333 break; 1334 default: 1335 Y.log('Invalid AJAX action requested of managed category.', 'warn', 'moodle-course-management'); 1336 return false; 1337 } 1338 }, 1339 1340 /** 1341 * Expands the category making its sub categories visible. 1342 * @method expand 1343 */ 1344 expand: function() { 1345 var node = this.get('node'), 1346 action = node.one('a[data-action=expand]'), 1347 ul = node.one('ul[role=group]'); 1348 node.removeClass('collapsed').setAttribute('aria-expanded', 'true'); 1349 action.setAttribute('data-action', 'collapse').setAttrs({ 1350 title: M.util.get_string('collapsecategory', 'moodle', this.getName()) 1351 }).one('img').setAttrs({ 1352 src: M.util.image_url('t/switch_minus', 'moodle'), 1353 alt: M.util.get_string('collapse', 'moodle') 1354 }); 1355 if (ul) { 1356 ul.setAttribute('aria-hidden', 'false'); 1357 } 1358 this.get('console').performAjaxAction('expandcategory', {categoryid: this.get('categoryid')}, null, this); 1359 }, 1360 1361 /** 1362 * Collapses the category making its sub categories hidden. 1363 * @method collapse 1364 */ 1365 collapse: function() { 1366 var node = this.get('node'), 1367 action = node.one('a[data-action=collapse]'), 1368 ul = node.one('ul[role=group]'); 1369 node.addClass('collapsed').setAttribute('aria-expanded', 'false'); 1370 action.setAttribute('data-action', 'expand').setAttrs({ 1371 title: M.util.get_string('expandcategory', 'moodle', this.getName()) 1372 }).one('img').setAttrs({ 1373 src: M.util.image_url('t/switch_plus', 'moodle'), 1374 alt: M.util.get_string('expand', 'moodle') 1375 }); 1376 if (ul) { 1377 ul.setAttribute('aria-hidden', 'true'); 1378 } 1379 this.get('console').performAjaxAction('collapsecategory', {categoryid: this.get('categoryid')}, null, this); 1380 }, 1381 1382 /** 1383 * Loads sub categories provided by an AJAX request.. 1384 * 1385 * @method loadSubcategories 1386 * @protected 1387 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1388 * @param {Object} response The response from the AJAX request. 1389 * @param {Object} args The arguments given to the request. 1390 * @return {Boolean} Returns true on success - false otherwise. 1391 */ 1392 loadSubcategories: function(transactionid, response, args) { 1393 var outcome = this.checkAjaxResponse(transactionid, response, args), 1394 node = this.get('node'), 1395 managementconsole = this.get('console'), 1396 ul, 1397 actionnode; 1398 if (outcome === false) { 1399 Y.log('AJAX failed to load sub categories for ' + this.get('itemname'), 'warn', 'moodle-course-management'); 1400 return false; 1401 } 1402 Y.log('AJAX loaded subcategories for ' + this.get('itemname'), 'info', 'moodle-course-management'); 1403 node.append(outcome.html); 1404 managementconsole.initialiseCategories(node); 1405 if (M.core && M.core.actionmenu && M.core.actionmenu.newDOMNode) { 1406 M.core.actionmenu.newDOMNode(node); 1407 } 1408 ul = node.one('ul[role=group]'); 1409 actionnode = node.one('a[data-action=collapse]'); 1410 if (ul && actionnode) { 1411 actionnode.setAttribute('aria-controls', ul.generateID()); 1412 } 1413 return true; 1414 }, 1415 1416 /** 1417 * Moves the course to this category. 1418 * 1419 * @method moveCourseTo 1420 * @param {Course} course 1421 */ 1422 moveCourseTo: function(course) { 1423 var self = this; 1424 Y.use('moodle-core-notification-confirm', function() { 1425 var confirm = new M.core.confirm({ 1426 title: M.util.get_string('confirm', 'moodle'), 1427 question: M.util.get_string('confirmcoursemove', 'moodle', { 1428 course: course.getName(), 1429 category: self.getName() 1430 }), 1431 yesLabel: M.util.get_string('move', 'moodle'), 1432 noLabel: M.util.get_string('cancel', 'moodle') 1433 }); 1434 confirm.on('complete-yes', function() { 1435 confirm.hide(); 1436 confirm.destroy(); 1437 this.get('console').performAjaxAction('movecourseintocategory', { 1438 categoryid: this.get('categoryid'), 1439 courseid: course.get('courseid') 1440 }, this.completeMoveCourse, this); 1441 }, self); 1442 confirm.show(); 1443 }); 1444 }, 1445 1446 /** 1447 * Completes moving a course to this category. 1448 * @method completeMoveCourse 1449 * @protected 1450 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1451 * @param {Object} response The response from the AJAX request. 1452 * @param {Object} args The arguments given to the request. 1453 * @return {Boolean} 1454 */ 1455 completeMoveCourse: function(transactionid, response, args) { 1456 var outcome = this.checkAjaxResponse(transactionid, response, args), 1457 managementconsole = this.get('console'), 1458 category, 1459 course, 1460 totals; 1461 if (outcome === false) { 1462 Y.log('AJAX failed to move courses into this category: ' + this.get('itemname'), 'warn', 'moodle-course-management'); 1463 return false; 1464 } 1465 course = managementconsole.getCourseById(args.courseid); 1466 if (!course) { 1467 Y.log('Course was moved but the course listing could not be found to reflect this', 'warn', 'moodle-course-management'); 1468 return false; 1469 } 1470 Y.log('Moved the course (' + course.getName() + ') into this category (' + this.getName() + ')', 1471 'debug', 'moodle-course-management'); 1472 this.highlight(); 1473 if (course) { 1474 if (outcome.paginationtotals) { 1475 totals = managementconsole.get('courselisting').one('.listing-pagination-totals'); 1476 if (totals) { 1477 totals.set('innerHTML', outcome.paginationtotals); 1478 } 1479 } 1480 if (outcome.totalcatcourses !== 'undefined') { 1481 totals = this.get('node').one('.course-count span'); 1482 if (totals) { 1483 totals.set('innerHTML', totals.get('innerHTML').replace(/^\d+/, outcome.totalcatcourses)); 1484 } 1485 } 1486 if (typeof outcome.fromcatcoursecount !== 'undefined') { 1487 category = managementconsole.get('activecategoryid'); 1488 category = managementconsole.getCategoryById(category); 1489 if (category) { 1490 totals = category.get('node').one('.course-count span'); 1491 if (totals) { 1492 totals.set('innerHTML', totals.get('innerHTML').replace(/^\d+/, outcome.fromcatcoursecount)); 1493 } 1494 } 1495 } 1496 course.remove(); 1497 } 1498 return true; 1499 }, 1500 1501 /** 1502 * Makes an item visible. 1503 * 1504 * @method show 1505 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1506 * @param {Object} response The response from the AJAX request. 1507 * @param {Object} args The arguments given to the request. 1508 * @return {Boolean} 1509 */ 1510 show: function(transactionid, response, args) { 1511 var outcome = this.checkAjaxResponse(transactionid, response, args), 1512 hidebtn; 1513 if (outcome === false) { 1514 Y.log('AJAX request to show ' + this.get('itemname') + ' by outcome.', 'warn', 'moodle-course-management'); 1515 return false; 1516 } 1517 1518 this.markVisible(); 1519 hidebtn = this.get('node').one('a[data-action=hide]'); 1520 if (hidebtn) { 1521 hidebtn.focus(); 1522 } 1523 if (outcome.categoryvisibility) { 1524 this.updateChildVisibility(outcome.categoryvisibility); 1525 } 1526 if (outcome.coursevisibility) { 1527 this.updateCourseVisiblity(outcome.coursevisibility); 1528 } 1529 this.updated(); 1530 Y.log('Success: category made visible by AJAX.', 'info', 'moodle-course-management'); 1531 }, 1532 1533 /** 1534 * Hides an item. 1535 * 1536 * @method hide 1537 * @param {Number} transactionid The transaction ID of the AJAX request (unique) 1538 * @param {Object} response The response from the AJAX request. 1539 * @param {Object} args The arguments given to the request. 1540 * @return {Boolean} 1541 */ 1542 hide: function(transactionid, response, args) { 1543 var outcome = this.checkAjaxResponse(transactionid, response, args), 1544 showbtn; 1545 if (outcome === false) { 1546 Y.log('AJAX request to hide ' + this.get('itemname') + ' by outcome.', 'warn', 'moodle-course-management'); 1547 return false; 1548 } 1549 this.markHidden(); 1550 showbtn = this.get('node').one('a[data-action=show]'); 1551 if (showbtn) { 1552 showbtn.focus(); 1553 } 1554 if (outcome.categoryvisibility) { 1555 this.updateChildVisibility(outcome.categoryvisibility); 1556 } 1557 if (outcome.coursevisibility) { 1558 this.updateCourseVisiblity(outcome.coursevisibility); 1559 } 1560 this.updated(); 1561 Y.log('Success: ' + this.get('itemname') + ' made hidden by AJAX.', 'info', 'moodle-course-management'); 1562 }, 1563 1564 /** 1565 * Updates the visibility of child courses if required. 1566 * @method updateCourseVisiblity 1567 * @chainable 1568 * @param courses 1569 */ 1570 updateCourseVisiblity: function(courses) { 1571 var managementconsole = this.get('console'), 1572 key, 1573 course; 1574 Y.log('Changing categories course visibility', 'info', 'moodle-course-management'); 1575 try { 1576 for (key in courses) { 1577 if (typeof courses[key] === 'object') { 1578 course = managementconsole.getCourseById(courses[key].id); 1579 if (course) { 1580 if (courses[key].visible === "1") { 1581 course.markVisible(); 1582 } else { 1583 course.markHidden(); 1584 } 1585 } 1586 } 1587 } 1588 } catch (err) { 1589 Y.log('Error trying to update course visibility: ' + err.message, 'warn', 'moodle-course-management'); 1590 } 1591 return this; 1592 }, 1593 1594 /** 1595 * Updates the visibility of subcategories if required. 1596 * @method updateChildVisibility 1597 * @chainable 1598 * @param categories 1599 */ 1600 updateChildVisibility: function(categories) { 1601 var managementconsole = this.get('console'), 1602 key, 1603 category; 1604 Y.log('Changing categories subcategory visibility', 'info', 'moodle-course-management'); 1605 try { 1606 for (key in categories) { 1607 if (typeof categories[key] === 'object') { 1608 category = managementconsole.getCategoryById(categories[key].id); 1609 if (category) { 1610 if (categories[key].visible === "1") { 1611 category.markVisible(); 1612 } else { 1613 category.markHidden(); 1614 } 1615 } 1616 } 1617 } 1618 } catch (err) { 1619 Y.log('Error trying to update category visibility: ' + err.message, 'warn', 'moodle-course-management'); 1620 } 1621 return this; 1622 } 1623 }; 1624 Y.extend(Category, Item, Category.prototype); 1625 /* global Item */ 1626 1627 /** 1628 * A managed course. 1629 * 1630 * @namespace M.course.management 1631 * @class Course 1632 * @constructor 1633 * @extends Item 1634 */ 1635 function Course() { 1636 Course.superclass.constructor.apply(this, arguments); 1637 } 1638 Course.NAME = 'moodle-course-management-course'; 1639 Course.CSS_PREFIX = 'management-course'; 1640 Course.ATTRS = { 1641 1642 /** 1643 * The course ID of this course. 1644 * @attribute courseid 1645 * @type Number 1646 */ 1647 courseid: {}, 1648 1649 /** 1650 * True if this is the selected course. 1651 * @attribute selected 1652 * @type Boolean 1653 * @default null 1654 */ 1655 selected: { 1656 getter: function(value, name) { 1657 if (value === null) { 1658 value = this.get('node').getData(name); 1659 this.set(name, value); 1660 } 1661 return value; 1662 }, 1663 value: null 1664 }, 1665 node: { 1666 1667 }, 1668 /** 1669 * The management console tracking this course. 1670 * @attribute console 1671 * @type Console 1672 * @writeOnce 1673 */ 1674 console: { 1675 writeOnce: 'initOnly' 1676 }, 1677 1678 /** 1679 * The category this course belongs to. 1680 * @attribute category 1681 * @type Category 1682 * @writeOnce 1683 */ 1684 category: { 1685 writeOnce: 'initOnly' 1686 } 1687 }; 1688 Course.prototype = { 1689 /** 1690 * Initialises the new course instance. 1691 * @method initializer 1692 */ 1693 initializer: function() { 1694 var node = this.get('node'), 1695 category = this.get('category'); 1696 this.set('courseid', node.getData('id')); 1697 if (category && category.registerCourse) { 1698 category.registerCourse(this); 1699 } 1700 this.set('itemname', 'course'); 1701 }, 1702 1703 /** 1704 * Returns the name of the course. 1705 * @method getName 1706 * @return {String} 1707 */ 1708 getName: function() { 1709 return this.get('node').one('a.coursename').get('innerHTML'); 1710 }, 1711 1712 /** 1713 * Handles an event relating to this course. 1714 * @method handle 1715 * @param {String} action 1716 * @param {EventFacade} e 1717 * @return {Boolean} 1718 */ 1719 handle: function(action, e) { 1720 var managementconsole = this.get('console'), 1721 args = {courseid: this.get('courseid')}; 1722 switch (action) { 1723 case 'moveup': 1724 e.halt(); 1725 managementconsole.performAjaxAction('movecourseup', args, this.moveup, this); 1726 break; 1727 case 'movedown': 1728 e.halt(); 1729 managementconsole.performAjaxAction('movecoursedown', args, this.movedown, this); 1730 break; 1731 case 'show': 1732 e.halt(); 1733 managementconsole.performAjaxAction('showcourse', args, this.show, this); 1734 break; 1735 case 'hide': 1736 e.halt(); 1737 managementconsole.performAjaxAction('hidecourse', args, this.hide, this); 1738 break; 1739 case 'select': 1740 var c = this.get('console'), 1741 movetonode = c.get('courselisting').one('#menumovecoursesto'); 1742 if (movetonode) { 1743 if (c.isCourseSelected(e.currentTarget)) { 1744 movetonode.removeAttribute('disabled'); 1745 } else { 1746 movetonode.setAttribute('disabled', true); 1747 } 1748 } 1749 break; 1750 default: 1751 Y.log('Invalid AJAX action requested of managed course.', 'warn', 'moodle-course-management'); 1752 return false; 1753 } 1754 }, 1755 1756 /** 1757 * Removes this course. 1758 * @method remove 1759 */ 1760 remove: function() { 1761 this.get('console').removeCourseById(this.get('courseid')); 1762 this.get('node').remove(); 1763 }, 1764 1765 /** 1766 * Moves this course after another course. 1767 * 1768 * @method moveAfter 1769 * @param {Number} moveaftercourse The course to move after or 0 to put it at the top. 1770 * @param {Number} previousid the course it was previously after in case we need to revert. 1771 */ 1772 moveAfter: function(moveaftercourse, previousid) { 1773 var managementconsole = this.get('console'), 1774 args = { 1775 courseid: this.get('courseid'), 1776 moveafter: moveaftercourse, 1777 previous: previousid 1778 }; 1779 managementconsole.performAjaxAction('movecourseafter', args, this.moveAfterResponse, this); 1780 }, 1781 1782 /** 1783 * Performs the actual move. 1784 * 1785 * @method moveAfterResponse 1786 * @protected 1787 * @param {Number} transactionid The transaction ID for the request. 1788 * @param {Object} response The response to the request. 1789 * @param {Objects} args The arguments that were given with the request. 1790 * @return {Boolean} 1791 */ 1792 moveAfterResponse: function(transactionid, response, args) { 1793 var outcome = this.checkAjaxResponse(transactionid, response, args), 1794 node = this.get('node'), 1795 previous; 1796 if (outcome === false) { 1797 previous = node.ancestor('ul').one('li[data-id=' + args.previous + ']'); 1798 Y.log('AJAX failed to move this course after the requested course', 'warn', 'moodle-course-management'); 1799 if (previous) { 1800 // After the last previous. 1801 previous.insertAfter(node, 'after'); 1802 } else { 1803 // Start of the list. 1804 node.ancestor('ul').one('li').insert(node, 'before'); 1805 } 1806 return false; 1807 } 1808 Y.log('AJAX successfully moved course (' + this.getName() + ')', 'info', 'moodle-course-management'); 1809 this.highlight(); 1810 } 1811 }; 1812 Y.extend(Course, Item, Course.prototype); 1813 1814 1815 }, '@VERSION@', { 1816 "requires": [ 1817 "base", 1818 "node", 1819 "io-base", 1820 "moodle-core-notification-exception", 1821 "json-parse", 1822 "dd-constrain", 1823 "dd-proxy", 1824 "dd-drop", 1825 "dd-delegate", 1826 "node-event-delegate" 1827 ] 1828 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |