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