芝麻web文件管理V1.00
编辑当前文件:/home2/sdektunc/.trash/cepali/course/yui/build/moodle-course-management/moodle-course-management.js
YUI.add('moodle-course-management', function (Y, NAME) { /* global DragDrop, Category, Course */ /** * Provides drop down menus for list of action links. * * @module moodle-course-management */ /** * Management JS console. * * Provides the organisation for course and category management JS. * * @namespace M.course.management * @class Console * @constructor * @extends Base */ function Console() { Console.superclass.constructor.apply(this, arguments); } Console.NAME = 'moodle-course-management'; Console.CSS_PREFIX = 'management'; Console.ATTRS = { /** * The HTML element containing the management interface. * @attribute element * @type Node */ element: { setter: function(node) { if (typeof node === 'string') { node = Y.one('#' + node); } return node; } }, /** * The category listing container node. * @attribute categorylisting * @type Node * @default null */ categorylisting: { value: null }, /** * The course listing container node. * @attribute courselisting * @type Node * @default null */ courselisting: { value: null }, /** * The course details container node. * @attribute coursedetails * @type Node|null * @default null */ coursedetails: { value: null }, /** * The id of the currently active category. * @attribute activecategoryid * @type Number * @default null */ activecategoryid: { value: null }, /** * The id of the currently active course. * @attribute activecourseid * @type Number * @default Null */ activecourseid: { value: null }, /** * The categories that are currently available through the management interface. * @attribute categories * @type Array * @default [] */ categories: { setter: function(item, name) { if (Y.Lang.isArray(item)) { return item; } var items = this.get(name); items.push(item); return items; }, value: [] }, /** * The courses that are currently available through the management interface. * @attribute courses * @type Course[] * @default Array */ courses: { validator: function(val) { return Y.Lang.isArray(val); }, value: [] }, /** * The currently displayed page of courses. * @attribute page * @type Number * @default null */ page: { getter: function(value, name) { if (value === null) { value = this.get('element').getData(name); this.set(name, value); } return value; }, value: null }, /** * The total pages of courses that can be shown for this category. * @attribute totalpages * @type Number * @default null */ totalpages: { getter: function(value, name) { if (value === null) { value = this.get('element').getData(name); this.set(name, value); } return value; }, value: null }, /** * The total number of courses belonging to this category. * @attribute totalcourses * @type Number * @default null */ totalcourses: { getter: function(value, name) { if (value === null) { value = this.get('element').getData(name); this.set(name, value); } return value; }, value: null }, /** * The URL to use for AJAX actions/requests. * @attribute ajaxurl * @type String * @default /course/ajax/management.php */ ajaxurl: { getter: function(value) { if (value === null) { value = M.cfg.wwwroot + '/course/ajax/management.php'; } return value; }, value: null }, /** * The drag drop handler * @attribute dragdrop * @type DragDrop * @default null */ dragdrop: { value: null } }; Console.prototype = { /** * Gets set to true once the first categories have been initialised. * @property categoriesinit * @private * @type {boolean} */ categoriesinit: false, /** * Initialises a new instance of the Console. * @method initializer */ initializer: function() { this.set('element', 'coursecat-management'); var element = this.get('element'), categorylisting = element.one('#category-listing'), courselisting = element.one('#course-listing'), selectedcategory = null, selectedcourse = null; if (categorylisting) { selectedcategory = categorylisting.one('.listitem[data-selected="1"]'); } if (courselisting) { selectedcourse = courselisting.one('.listitem[data-selected="1"]'); } this.set('categorylisting', categorylisting); this.set('courselisting', courselisting); this.set('coursedetails', element.one('#course-detail')); if (selectedcategory) { this.set('activecategoryid', selectedcategory.getData('id')); } if (selectedcourse) { this.set('activecourseid', selectedcourse.getData('id')); } this.initialiseCategories(categorylisting); this.initialiseCourses(); if (courselisting) { // No need for dragdrop if we don't have a course listing. this.set('dragdrop', new DragDrop({console: this})); } }, /** * Initialises all the categories being shown. * @method initialiseCategories * @private * @return {boolean} */ initialiseCategories: function(listing) { var count = 0; if (!listing) { return false; } // Disable category bulk actions as nothing will be selected on initialise. var menumovecatto = listing.one('#menumovecategoriesto'); if (menumovecatto) { menumovecatto.setAttribute('disabled', true); } var menuresortcategoriesby = listing.one('#menuresortcategoriesby'); if (menuresortcategoriesby) { menuresortcategoriesby.setAttribute('disabled', true); } var menuresortcoursesby = listing.one('#menuresortcoursesby'); if (menuresortcoursesby) { menuresortcoursesby.setAttribute('disabled', true); } listing.all('.listitem[data-id]').each(function(node) { this.set('categories', new Category({ node: node, console: this })); count++; }, this); if (!this.categoriesinit) { this.get('categorylisting').delegate('click', this.handleCategoryDelegation, 'a[data-action]', this); this.get('categorylisting').delegate('click', this.handleCategoryDelegation, 'input[name="bcat[]"]', this); this.get('categorylisting').delegate('change', this.handleBulkSortByaction, '#menuselectsortby', this); this.categoriesinit = true; } else { } }, /** * Initialises all the categories being shown. * @method initialiseCourses * @private * @return {boolean} */ initialiseCourses: function() { var category = this.getCategoryById(this.get('activecategoryid')), listing = this.get('courselisting'), count = 0; if (!listing) { return false; } // Disable course move to bulk action as nothing will be selected on initialise. var menumovecoursesto = listing.one('#menumovecoursesto'); if (menumovecoursesto) { menumovecoursesto.setAttribute('disabled', true); } listing.all('.listitem[data-id]').each(function(node) { this.registerCourse(new Course({ node: node, console: this, category: category })); count++; }, this); listing.delegate('click', this.handleCourseDelegation, 'a[data-action]', this); listing.delegate('click', this.handleCourseDelegation, 'input[name="bc[]"]', this); }, /** * Registers a course within the management display. * @method registerCourse * @param {Course} course */ registerCourse: function(course) { var courses = this.get('courses'); courses.push(course); this.set('courses', courses); }, /** * Handles the event fired by a delegated course listener. * * @method handleCourseDelegation * @protected * @param {EventFacade} e */ handleCourseDelegation: function(e) { var target = e.currentTarget, action = target.getData('action'), courseid = target.ancestor('.listitem').getData('id'), course = this.getCourseById(courseid); if (course) { course.handle(action, e); } else { } }, /** * Handles the event fired by a delegated course listener. * * @method handleCategoryDelegation * @protected * @param {EventFacade} e */ handleCategoryDelegation: function(e) { var target = e.currentTarget, action = target.getData('action'), categoryid = target.ancestor('.listitem').getData('id'), category = this.getCategoryById(categoryid); if (category) { category.handle(action, e); } else { } }, /** * Check if any course is selected. * * @method isCourseSelected * @param {Node} checkboxnode Checkbox node on which action happened. * @return bool */ isCourseSelected: function(checkboxnode) { var selected = false; // If any course selected then show move to category select box. if (checkboxnode && checkboxnode.get('checked')) { selected = true; } else { var i, course, courses = this.get('courses'), length = courses.length; for (i = 0; i < length; i++) { if (courses.hasOwnProperty(i)) { course = courses[i]; if (course.get('node').one('input[name="bc[]"]').get('checked')) { selected = true; break; } } } } return selected; }, /** * Check if any category is selected. * * @method isCategorySelected * @param {Node} checkboxnode Checkbox node on which action happened. * @return bool */ isCategorySelected: function(checkboxnode) { var selected = false; // If any category selected then show move to category select box. if (checkboxnode && checkboxnode.get('checked')) { selected = true; } else { var i, category, categories = this.get('categories'), length = categories.length; for (i = 0; i < length; i++) { if (categories.hasOwnProperty(i)) { category = categories[i]; if (category.get('node').one('input[name="bcat[]"]').get('checked')) { selected = true; break; } } } } return selected; }, /** * Handle bulk sort action. * * @method handleBulkSortByaction * @protected * @param {EventFacade} e */ handleBulkSortByaction: function(e) { var sortcategoryby = this.get('categorylisting').one('#menuresortcategoriesby'), sortcourseby = this.get('categorylisting').one('#menuresortcoursesby'), sortbybutton = this.get('categorylisting').one('input[name="bulksort"]'), sortby = e; if (!sortby) { sortby = this.get('categorylisting').one('#menuselectsortby'); } else { if (e && e.currentTarget) { sortby = e.currentTarget; } } // If no sortby select found then return as we can't do anything. if (!sortby) { return; } if ((this.get('categories').length <= 1) || (!this.isCategorySelected() && (sortby.get("options").item(sortby.get('selectedIndex')).getAttribute('value') === 'selectedcategories'))) { if (sortcategoryby) { sortcategoryby.setAttribute('disabled', true); } if (sortcourseby) { sortcourseby.setAttribute('disabled', true); } if (sortbybutton) { sortbybutton.setAttribute('disabled', true); } } else { if (sortcategoryby) { sortcategoryby.removeAttribute('disabled'); } if (sortcourseby) { sortcourseby.removeAttribute('disabled'); } if (sortbybutton) { sortbybutton.removeAttribute('disabled'); } } }, /** * Returns the category with the given ID. * @method getCategoryById * @param {Number} id * @return {Category|Boolean} The category or false if it can't be found. */ getCategoryById: function(id) { var i, category, categories = this.get('categories'), length = categories.length; for (i = 0; i < length; i++) { if (categories.hasOwnProperty(i)) { category = categories[i]; if (category.get('categoryid') === id) { return category; } } } return false; }, /** * Returns the course with the given id. * @method getCourseById * @param {Number} id * @return {Course|Boolean} The course or false if not found/ */ getCourseById: function(id) { var i, course, courses = this.get('courses'), length = courses.length; for (i = 0; i < length; i++) { if (courses.hasOwnProperty(i)) { course = courses[i]; if (course.get('courseid') === id) { return course; } } } return false; }, /** * Removes the course with the given ID. * @method removeCourseById * @param {Number} id */ removeCourseById: function(id) { var courses = this.get('courses'), length = courses.length, course, i; for (i = 0; i < length; i++) { course = courses[i]; if (course.get('courseid') === id) { courses.splice(i, 1); break; } } }, /** * Performs an AJAX action. * * @method performAjaxAction * @param {String} action The action to perform. * @param {Object} args The arguments to pass through with teh request. * @param {Function} callback The function to call when all is done. * @param {Object} context The object to use as the context for the callback. */ performAjaxAction: function(action, args, callback, context) { var io = new Y.IO(); args.action = action; args.ajax = '1'; args.sesskey = M.cfg.sesskey; if (callback === null) { callback = function() { }; } io.send(this.get('ajaxurl'), { method: 'POST', on: { complete: callback }, context: context, data: args, 'arguments': args }); } }; Y.extend(Console, Y.Base, Console.prototype); M.course = M.course || {}; M.course.management = M.course.management || {}; M.course.management.console = null; /** * Initalises the course management console. * * @method M.course.management.init * @static * @param {Object} config */ M.course.management.init = function(config) { M.course.management.console = new Console(config); }; /* global Console */ /** * Drag and Drop handler * * @namespace M.course.management * @class DragDrop * @constructor * @extends Base */ function DragDrop(config) { Console.superclass.constructor.apply(this, [config]); } DragDrop.NAME = 'moodle-course-management-dd'; DragDrop.CSS_PREFIX = 'management-dd'; DragDrop.ATTRS = { /** * The management console this drag and drop has been set up for. * @attribute console * @type Console * @writeOnce */ console: { writeOnce: 'initOnly' } }; DragDrop.prototype = { /** * True if the user is dragging a course upwards. * @property goingup * @protected * @default false */ goingup: false, /** * The last Y position of the course being dragged * @property lasty * @protected * @default null */ lasty: null, /** * The sibling above the course being dragged currently (tracking its original position). * * @property previoussibling * @protected * @default false */ previoussibling: null, /** * Initialises the DragDrop instance. * @method initializer */ initializer: function() { var managementconsole = this.get('console'), container = managementconsole.get('element'), categorylisting = container.one('#category-listing'), courselisting = container.one('#course-listing > .course-listing'), categoryul = (categorylisting) ? categorylisting.one('ul.ml') : null, courseul = (courselisting) ? courselisting.one('ul.ml') : null, canmoveoutof = (courselisting) ? courselisting.getData('canmoveoutof') : false, contstraint = (canmoveoutof) ? container : courseul; if (!courseul) { // No course listings found. return false; } while (contstraint.get('scrollHeight') === 0 && !contstraint.compareTo(window.document.body)) { contstraint = contstraint.get('parentNode'); } courseul.all('> li').each(function(li) { this.initCourseListing(li, contstraint); }, this); courseul.setData('dd', new Y.DD.Drop({ node: courseul })); if (canmoveoutof && categoryul) { // Category UL may not be there if viewmode is just courses. categoryul.all('li > div').each(function(div) { this.initCategoryListitem(div); }, this); } Y.DD.DDM.on('drag:start', this.dragStart, this); Y.DD.DDM.on('drag:end', this.dragEnd, this); Y.DD.DDM.on('drag:drag', this.dragDrag, this); Y.DD.DDM.on('drop:over', this.dropOver, this); Y.DD.DDM.on('drop:enter', this.dropEnter, this); Y.DD.DDM.on('drop:exit', this.dropExit, this); Y.DD.DDM.on('drop:hit', this.dropHit, this); }, /** * Initialises a course listing. * @method initCourseListing * @param Node */ initCourseListing: function(node, contstraint) { node.setData('dd', new Y.DD.Drag({ node: node, target: { padding: '0 0 0 20' } }).addHandle( '.drag-handle' ).plug(Y.Plugin.DDProxy, { moveOnEnd: false, borderStyle: false }).plug(Y.Plugin.DDConstrained, { constrain2node: contstraint })); }, /** * Initialises a category listing. * @method initCategoryListitem * @param Node */ initCategoryListitem: function(node) { node.setData('dd', new Y.DD.Drop({ node: node })); }, /** * Dragging has started. * @method dragStart * @private * @param {EventFacade} e */ dragStart: function(e) { var drag = e.target, node = drag.get('node'), dragnode = drag.get('dragNode'); node.addClass('course-being-dragged'); dragnode.addClass('course-being-dragged-proxy').set('innerHTML', node.one('a.coursename').get('innerHTML')); this.previoussibling = node.get('previousSibling'); }, /** * Dragging has ended. * @method dragEnd * @private * @param {EventFacade} e */ dragEnd: function(e) { var drag = e.target, node = drag.get('node'); node.removeClass('course-being-dragged'); this.get('console').get('element').all('#category-listing li.highlight').removeClass('highlight'); }, /** * Dragging in progress. * @method dragDrag * @private * @param {EventFacade} e */ dragDrag: function(e) { var y = e.target.lastXY[1]; if (y < this.lasty) { this.goingup = true; } else { this.goingup = false; } this.lasty = y; }, /** * The course has been dragged over a drop target. * @method dropOver * @private * @param {EventFacade} e */ dropOver: function(e) { // Get a reference to our drag and drop nodes var drag = e.drag.get('node'), drop = e.drop.get('node'), tag = drop.get('tagName').toLowerCase(); if (tag === 'li' && drop.hasClass('listitem-course')) { if (!this.goingup) { drop = drop.get('nextSibling'); if (!drop) { drop = e.drop.get('node'); drop.get('parentNode').append(drag); return false; } } drop.get('parentNode').insertBefore(drag, drop); e.drop.sizeShim(); } }, /** * The course has been dragged over a drop target. * @method dropEnter * @private * @param {EventFacade} e */ dropEnter: function(e) { var drop = e.drop.get('node'), tag = drop.get('tagName').toLowerCase(); if (tag === 'div') { drop.ancestor('li.listitem-category').addClass('highlight'); } }, /** * The course has been dragged off a drop target. * @method dropExit * @private * @param {EventFacade} e */ dropExit: function(e) { var drop = e.drop.get('node'), tag = drop.get('tagName').toLowerCase(); if (tag === 'div') { drop.ancestor('li.listitem-category').removeClass('highlight'); } }, /** * The course has been dropped on a target. * @method dropHit * @private * @param {EventFacade} e */ dropHit: function(e) { var drag = e.drag.get('node'), drop = e.drop.get('node'), iscategory = (drop.ancestor('.listitem-category') !== null), iscourse = !iscategory && (drop.test('.listitem-course')), managementconsole = this.get('console'), categoryid, category, courseid, course, aftercourseid, previoussibling, previousid; if (!drag.test('.listitem-course')) { return false; } courseid = drag.getData('id'); if (iscategory) { categoryid = drop.ancestor('.listitem-category').getData('id'); category = managementconsole.getCategoryById(categoryid); if (category) { course = managementconsole.getCourseById(courseid); if (course) { category.moveCourseTo(course); } } } else if (iscourse || drop.ancestor('#course-listing')) { course = managementconsole.getCourseById(courseid); previoussibling = drag.get('previousSibling'); aftercourseid = (previoussibling) ? previoussibling.getData('id') || 0 : 0; previousid = (this.previoussibling) ? this.previoussibling.getData('id') : 0; if (aftercourseid !== previousid) { course.moveAfter(aftercourseid, previousid); } } else { } } }; Y.extend(DragDrop, Y.Base, DragDrop.prototype); /** * A managed course. * * @namespace M.course.management * @class Item * @constructor * @extends Base */ function Item() { Item.superclass.constructor.apply(this, arguments); } Item.NAME = 'moodle-course-management-item'; Item.CSS_PREFIX = 'management-item'; Item.ATTRS = { /** * The node for this item. * @attribute node * @type Node */ node: {}, /** * The management console. * @attribute console * @type Console */ console: {}, /** * Describes the type of this item. Should be set by the extending class. * @attribute itemname * @type {String} * @default item */ itemname: { value: 'item' } }; Item.prototype = { /** * The highlight timeout for this item if there is one. * @property highlighttimeout * @protected * @type Timeout * @default null */ highlighttimeout: null, /** * Checks and parses an AJAX response for an item. * * @method checkAjaxResponse * @protected * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Object|Boolean} */ checkAjaxResponse: function(transactionid, response, args) { if (response.status !== 200) { return false; } if (transactionid === null || args === null) { return false; } var outcome = Y.JSON.parse(response.responseText); if (outcome.error !== false) { new M.core.exception(outcome); } if (outcome.outcome === false) { return false; } return outcome; }, /** * Moves an item up by one. * * @method moveup * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ moveup: function(transactionid, response, args) { var node, nodeup, nodedown, previous, previousup, previousdown, tmpnode, outcome = this.checkAjaxResponse(transactionid, response, args); if (outcome === false) { return false; } node = this.get('node'); previous = node.previous('.listitem'); if (previous) { previous.insert(node, 'before'); previousup = previous.one(' > div a.action-moveup'); nodedown = node.one(' > div a.action-movedown'); if (!previousup || !nodedown) { // We can have two situations here: // 1. previousup is not set and nodedown is not set. This happens when there are only two courses. // 2. nodedown is not set. This happens when they are moving the bottom course up. // node up and previous down should always be there. They would be required to trigger the action. nodeup = node.one(' > div a.action-moveup'); previousdown = previous.one(' > div a.action-movedown'); if (!previousup && !nodedown) { // Ok, must be two courses. We need to switch the up and down icons. tmpnode = Y.Node.create('
'); previousdown.replace(tmpnode); nodeup.replace(previousdown); tmpnode.replace(nodeup); tmpnode.destroy(); } else if (!nodedown) { // previous down needs to be given to node. nodeup.insert(previousdown, 'after'); } } nodeup = node.one(' > div a.action-moveup'); if (nodeup) { // Try to re-focus on up. nodeup.focus(); } else { // If we can't focus up we're at the bottom, try to focus on up. nodedown = node.one(' > div a.action-movedown'); if (nodedown) { nodedown.focus(); } } this.updated(true); } else { // Aha it succeeded but this is the top item in the list. Pagination is in play! // Refresh to update the state of things. window.location.reload(); } }, /** * Moves an item down by one. * * @method movedown * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ movedown: function(transactionid, response, args) { var node, next, nodeup, nodedown, nextup, nextdown, tmpnode, outcome = this.checkAjaxResponse(transactionid, response, args); if (outcome === false) { return false; } node = this.get('node'); next = node.next('.listitem'); if (next) { node.insert(next, 'before'); nextdown = next.one(' > div a.action-movedown'); nodeup = node.one(' > div a.action-moveup'); if (!nextdown || !nodeup) { // next up and node down should always be there. They would be required to trigger the action. nextup = next.one(' > div a.action-moveup'); nodedown = node.one(' > div a.action-movedown'); if (!nextdown && !nodeup) { // We can have two situations here: // 1. nextdown is not set and nodeup is not set. This happens when there are only two courses. // 2. nodeup is not set. This happens when we are moving the first course down. // Ok, must be two courses. We need to switch the up and down icons. tmpnode = Y.Node.create('
'); nextup.replace(tmpnode); nodedown.replace(nextup); tmpnode.replace(nodedown); tmpnode.destroy(); } else if (!nodeup) { // next up needs to be given to node. nodedown.insert(nextup, 'before'); } } nodedown = node.one(' > div a.action-movedown'); if (nodedown) { // Try to ensure the up is focused again. nodedown.focus(); } else { // If we can't focus up we're at the top, try to focus on down. nodeup = node.one(' > div a.action-moveup'); if (nodeup) { nodeup.focus(); } } this.updated(true); } else { // Aha it succeeded but this is the bottom item in the list. Pagination is in play! // Refresh to update the state of things. window.location.reload(); } }, /** * Makes an item visible. * * @method show * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ show: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), hidebtn; if (outcome === false) { return false; } this.markVisible(); hidebtn = this.get('node').one('a[data-action=hide]'); if (hidebtn) { hidebtn.focus(); } this.updated(); }, /** * Marks the item as visible * @method markVisible */ markVisible: function() { this.get('node').setAttribute('data-visible', '1'); return true; }, /** * Hides an item. * * @method hide * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ hide: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), showbtn; if (outcome === false) { return false; } this.markHidden(); showbtn = this.get('node').one('a[data-action=show]'); if (showbtn) { showbtn.focus(); } this.updated(); }, /** * Marks the item as hidden. * @method makeHidden */ markHidden: function() { this.get('node').setAttribute('data-visible', '0'); return true; }, /** * Called when ever a node is updated. * * @method updated * @param {Boolean} moved True if this item was moved. */ updated: function(moved) { if (moved) { this.highlight(); } }, /** * Highlights this option for a breif time. * * @method highlight */ highlight: function() { var node = this.get('node'); node.siblings('.highlight').removeClass('highlight'); node.addClass('highlight'); if (this.highlighttimeout) { window.clearTimeout(this.highlighttimeout); } this.highlighttimeout = window.setTimeout(function() { node.removeClass('highlight'); }, 2500); } }; Y.extend(Item, Y.Base, Item.prototype); /* global Item */ /** * A managed category. * * @namespace M.course.management * @class Category * @constructor * @extends Item */ function Category() { Category.superclass.constructor.apply(this, arguments); } Category.NAME = 'moodle-course-management-category'; Category.CSS_PREFIX = 'management-category'; Category.ATTRS = { /** * The category ID relating to this category. * @attribute categoryid * @type Number * @writeOnce * @default null */ categoryid: { getter: function(value, name) { if (value === null) { value = this.get('node').getData('id'); this.set(name, value); } return value; }, value: null, writeOnce: true }, /** * True if this category is the currently selected category. * @attribute selected * @type Boolean * @default null */ selected: { getter: function(value, name) { if (value === null) { value = this.get('node').getData(name); if (value === null) { value = false; } this.set(name, value); } return value; }, value: null }, /** * An array of courses belonging to this category. * @attribute courses * @type Course[] * @default Array */ courses: { validator: function(val) { return Y.Lang.isArray(val); }, value: [] } }; Category.prototype = { /** * Initialises an instance of a Category. * @method initializer */ initializer: function() { this.set('itemname', 'category'); }, /** * Returns the name of the category. * @method getName * @return {String} */ getName: function() { return this.get('node').one('a.categoryname').get('innerHTML'); }, /** * Registers a course as belonging to this category. * @method registerCourse * @param {Course} course */ registerCourse: function(course) { var courses = this.get('courses'); courses.push(course); this.set('courses', courses); }, /** * Handles a category related event. * * @method handle * @param {String} action * @param {EventFacade} e * @return {Boolean} */ handle: function(action, e) { var catarg = {categoryid: this.get('categoryid')}, selected = this.get('console').get('activecategoryid'); if (selected && selected !== catarg.categoryid) { catarg.selectedcategory = selected; } switch (action) { case 'moveup': e.preventDefault(); this.get('console').performAjaxAction('movecategoryup', catarg, this.moveup, this); break; case 'movedown': e.preventDefault(); this.get('console').performAjaxAction('movecategorydown', catarg, this.movedown, this); break; case 'show': e.preventDefault(); this.get('console').performAjaxAction('showcategory', catarg, this.show, this); break; case 'hide': e.preventDefault(); this.get('console').performAjaxAction('hidecategory', catarg, this.hide, this); break; case 'expand': e.preventDefault(); if (this.get('node').getData('expanded') === '0') { this.get('node').setAttribute('data-expanded', '1').setData('expanded', 'true'); this.get('console').performAjaxAction('getsubcategorieshtml', catarg, this.loadSubcategories, this); } this.expand(); break; case 'collapse': e.preventDefault(); this.collapse(); break; case 'select': var c = this.get('console'), movecategoryto = c.get('categorylisting').one('#menumovecategoriesto'); // If any category is selected and there are more then one categories. if (movecategoryto) { if (c.isCategorySelected(e.currentTarget) && c.get('categories').length > 1) { movecategoryto.removeAttribute('disabled'); } else { movecategoryto.setAttribute('disabled', true); } c.handleBulkSortByaction(); } break; default: return false; } }, /** * Expands the category making its sub categories visible. * @method expand */ expand: function() { var node = this.get('node'), action = node.one('a[data-action=expand]'), ul = node.one('ul[role=group]'); node.removeClass('collapsed').setAttribute('aria-expanded', 'true'); action.setAttribute('data-action', 'collapse').setAttrs({ title: M.util.get_string('collapsecategory', 'moodle', this.getName()) }); require(['core/str', 'core/templates', 'core/notification'], function(Str, Templates, Notification) { Str.get_string('collapse', 'core') .then(function(string) { return Templates.renderPix('t/switch_minus', 'core', string); }) .then(function(html) { html = Y.Node.create(html).addClass('tree-icon').getDOMNode().outerHTML; return action.set('innerHTML', html); }).fail(Notification.exception); }); if (ul) { ul.setAttribute('aria-hidden', 'false'); } this.get('console').performAjaxAction('expandcategory', {categoryid: this.get('categoryid')}, null, this); }, /** * Collapses the category making its sub categories hidden. * @method collapse */ collapse: function() { var node = this.get('node'), action = node.one('a[data-action=collapse]'), ul = node.one('ul[role=group]'); node.addClass('collapsed').setAttribute('aria-expanded', 'false'); action.setAttribute('data-action', 'expand').setAttrs({ title: M.util.get_string('expandcategory', 'moodle', this.getName()) }); require(['core/str', 'core/templates', 'core/notification'], function(Str, Templates, Notification) { Str.get_string('expand', 'core') .then(function(string) { return Templates.renderPix('t/switch_plus', 'core', string); }) .then(function(html) { html = Y.Node.create(html).addClass('tree-icon').getDOMNode().outerHTML; return action.set('innerHTML', html); }).fail(Notification.exception); }); if (ul) { ul.setAttribute('aria-hidden', 'true'); } this.get('console').performAjaxAction('collapsecategory', {categoryid: this.get('categoryid')}, null, this); }, /** * Loads sub categories provided by an AJAX request.. * * @method loadSubcategories * @protected * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} Returns true on success - false otherwise. */ loadSubcategories: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), node = this.get('node'), managementconsole = this.get('console'), ul, actionnode; if (outcome === false) { return false; } node.append(outcome.html); managementconsole.initialiseCategories(node); if (M.core && M.core.actionmenu && M.core.actionmenu.newDOMNode) { M.core.actionmenu.newDOMNode(node); } ul = node.one('ul[role=group]'); actionnode = node.one('a[data-action=collapse]'); if (ul && actionnode) { actionnode.setAttribute('aria-controls', ul.generateID()); } return true; }, /** * Moves the course to this category. * * @method moveCourseTo * @param {Course} course */ moveCourseTo: function(course) { var self = this; Y.use('moodle-core-notification-confirm', function() { var confirm = new M.core.confirm({ title: M.util.get_string('confirm', 'moodle'), question: M.util.get_string('confirmcoursemove', 'moodle', { course: course.getName(), category: self.getName() }), yesLabel: M.util.get_string('move', 'moodle'), noLabel: M.util.get_string('cancel', 'moodle') }); confirm.on('complete-yes', function() { confirm.hide(); confirm.destroy(); this.get('console').performAjaxAction('movecourseintocategory', { categoryid: this.get('categoryid'), courseid: course.get('courseid') }, this.completeMoveCourse, this); }, self); confirm.show(); }); }, /** * Completes moving a course to this category. * @method completeMoveCourse * @protected * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ completeMoveCourse: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), managementconsole = this.get('console'), category, course, totals; if (outcome === false) { return false; } course = managementconsole.getCourseById(args.courseid); if (!course) { return false; } this.highlight(); if (course) { if (outcome.paginationtotals) { totals = managementconsole.get('courselisting').one('.listing-pagination-totals'); if (totals) { totals.set('innerHTML', outcome.paginationtotals); } } if (outcome.totalcatcourses !== 'undefined') { totals = this.get('node').one('.course-count span'); if (totals) { totals.set('innerHTML', totals.get('innerHTML').replace(/^\d+/, outcome.totalcatcourses)); } } if (typeof outcome.fromcatcoursecount !== 'undefined') { category = managementconsole.get('activecategoryid'); category = managementconsole.getCategoryById(category); if (category) { totals = category.get('node').one('.course-count span'); if (totals) { totals.set('innerHTML', totals.get('innerHTML').replace(/^\d+/, outcome.fromcatcoursecount)); } } } course.remove(); } return true; }, /** * Makes an item visible. * * @method show * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ show: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), hidebtn; if (outcome === false) { return false; } this.markVisible(); hidebtn = this.get('node').one('a[data-action=hide]'); if (hidebtn) { hidebtn.focus(); } if (outcome.categoryvisibility) { this.updateChildVisibility(outcome.categoryvisibility); } if (outcome.coursevisibility) { this.updateCourseVisiblity(outcome.coursevisibility); } this.updated(); }, /** * Hides an item. * * @method hide * @param {Number} transactionid The transaction ID of the AJAX request (unique) * @param {Object} response The response from the AJAX request. * @param {Object} args The arguments given to the request. * @return {Boolean} */ hide: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), showbtn; if (outcome === false) { return false; } this.markHidden(); showbtn = this.get('node').one('a[data-action=show]'); if (showbtn) { showbtn.focus(); } if (outcome.categoryvisibility) { this.updateChildVisibility(outcome.categoryvisibility); } if (outcome.coursevisibility) { this.updateCourseVisiblity(outcome.coursevisibility); } this.updated(); }, /** * Updates the visibility of child courses if required. * @method updateCourseVisiblity * @chainable * @param courses */ updateCourseVisiblity: function(courses) { var managementconsole = this.get('console'), key, course; try { for (key in courses) { if (typeof courses[key] === 'object') { course = managementconsole.getCourseById(courses[key].id); if (course) { if (courses[key].visible === "1") { course.markVisible(); } else { course.markHidden(); } } } } } catch (err) { } return this; }, /** * Updates the visibility of subcategories if required. * @method updateChildVisibility * @chainable * @param categories */ updateChildVisibility: function(categories) { var managementconsole = this.get('console'), key, category; try { for (key in categories) { if (typeof categories[key] === 'object') { category = managementconsole.getCategoryById(categories[key].id); if (category) { if (categories[key].visible === "1") { category.markVisible(); } else { category.markHidden(); } } } } } catch (err) { } return this; } }; Y.extend(Category, Item, Category.prototype); /* global Item */ /** * A managed course. * * @namespace M.course.management * @class Course * @constructor * @extends Item */ function Course() { Course.superclass.constructor.apply(this, arguments); } Course.NAME = 'moodle-course-management-course'; Course.CSS_PREFIX = 'management-course'; Course.ATTRS = { /** * The course ID of this course. * @attribute courseid * @type Number */ courseid: {}, /** * True if this is the selected course. * @attribute selected * @type Boolean * @default null */ selected: { getter: function(value, name) { if (value === null) { value = this.get('node').getData(name); this.set(name, value); } return value; }, value: null }, node: { }, /** * The management console tracking this course. * @attribute console * @type Console * @writeOnce */ console: { writeOnce: 'initOnly' }, /** * The category this course belongs to. * @attribute category * @type Category * @writeOnce */ category: { writeOnce: 'initOnly' } }; Course.prototype = { /** * Initialises the new course instance. * @method initializer */ initializer: function() { var node = this.get('node'), category = this.get('category'); this.set('courseid', node.getData('id')); if (category && category.registerCourse) { category.registerCourse(this); } this.set('itemname', 'course'); }, /** * Returns the name of the course. * @method getName * @return {String} */ getName: function() { return this.get('node').one('a.coursename').get('innerHTML'); }, /** * Handles an event relating to this course. * @method handle * @param {String} action * @param {EventFacade} e * @return {Boolean} */ handle: function(action, e) { var managementconsole = this.get('console'), args = {courseid: this.get('courseid')}; switch (action) { case 'moveup': e.halt(); managementconsole.performAjaxAction('movecourseup', args, this.moveup, this); break; case 'movedown': e.halt(); managementconsole.performAjaxAction('movecoursedown', args, this.movedown, this); break; case 'show': e.halt(); managementconsole.performAjaxAction('showcourse', args, this.show, this); break; case 'hide': e.halt(); managementconsole.performAjaxAction('hidecourse', args, this.hide, this); break; case 'select': var c = this.get('console'), movetonode = c.get('courselisting').one('#menumovecoursesto'); if (movetonode) { if (c.isCourseSelected(e.currentTarget)) { movetonode.removeAttribute('disabled'); } else { movetonode.setAttribute('disabled', true); } } break; default: return false; } }, /** * Removes this course. * @method remove */ remove: function() { this.get('console').removeCourseById(this.get('courseid')); this.get('node').remove(); }, /** * Moves this course after another course. * * @method moveAfter * @param {Number} moveaftercourse The course to move after or 0 to put it at the top. * @param {Number} previousid the course it was previously after in case we need to revert. */ moveAfter: function(moveaftercourse, previousid) { var managementconsole = this.get('console'), args = { courseid: this.get('courseid'), moveafter: moveaftercourse, previous: previousid }; managementconsole.performAjaxAction('movecourseafter', args, this.moveAfterResponse, this); }, /** * Performs the actual move. * * @method moveAfterResponse * @protected * @param {Number} transactionid The transaction ID for the request. * @param {Object} response The response to the request. * @param {Objects} args The arguments that were given with the request. * @return {Boolean} */ moveAfterResponse: function(transactionid, response, args) { var outcome = this.checkAjaxResponse(transactionid, response, args), node = this.get('node'), previous; if (outcome === false) { previous = node.ancestor('ul').one('li[data-id=' + args.previous + ']'); if (previous) { // After the last previous. previous.insertAfter(node, 'after'); } else { // Start of the list. node.ancestor('ul').one('li').insert(node, 'before'); } return false; } this.highlight(); } }; Y.extend(Course, Item, Course.prototype); }, '@VERSION@', { "requires": [ "base", "node", "io-base", "moodle-core-notification-exception", "json-parse", "dd-constrain", "dd-proxy", "dd-drop", "dd-delegate", "node-event-delegate" ] });