first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
define("core_contentbank/search",["exports","jquery","core_contentbank/selectors","core/str","core/pending","core/utils"],(function(_exports,_jquery,_selectors,_str,_pending,_utils){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Search methods for finding contents in the content bank.
*
* @module core_contentbank/search
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=_interopRequireDefault(_jquery),_selectors=_interopRequireDefault(_selectors),_pending=_interopRequireDefault(_pending);_exports.init=()=>{const pendingPromise=new _pending.default,root=(0,_jquery.default)(_selectors.default.regions.contentbank);registerListenerEvents(root),pendingPromise.resolve()};const registerListenerEvents=root=>{const searchInput=root.find(_selectors.default.elements.searchinput)[0];root.on("click",_selectors.default.actions.search,(function(e){e.preventDefault(),toggleSearchResultsView(root,searchInput.value)})),root.on("click",_selectors.default.actions.clearSearch,(function(e){e.preventDefault(),searchInput.value="",searchInput.focus(),toggleSearchResultsView(root,searchInput.value)})),searchInput.addEventListener("input",(0,_utils.debounce)((()=>{toggleSearchResultsView(root,searchInput.value)}),300))},toggleSearchResultsView=async(body,searchQuery)=>{const clearSearchButton=body.find(_selectors.default.actions.clearSearch)[0],navbarBreadcrumb=body.find(_selectors.default.elements.cbnavbarbreadcrumb)[0],navbarTotal=body.find(_selectors.default.elements.cbnavbartotalsearch)[0],filteredContents=filterContents(body,searchQuery);searchQuery.length>0?(clearSearchButton.classList.remove("d-none"),navbarBreadcrumb.classList.add("d-none"),navbarTotal.innerHTML=await(0,_str.getString)("itemsfound","core_contentbank",filteredContents.length),navbarTotal.classList.remove("d-none")):(clearSearchButton.classList.add("d-none"),navbarBreadcrumb.classList.remove("d-none"),navbarTotal.classList.add("d-none"))},filterContents=(body,searchTerm)=>{const contents=Array.from(body.find(_selectors.default.elements.listitem)),searchResults=[];return contents.forEach((content=>{const contentName=content.getAttribute("data-name");if(""===searchTerm||contentName.toLowerCase().includes(searchTerm.toLowerCase())){searchResults.push(content);content.querySelector(_selectors.default.regions.cbcontentname).innerHTML=highlight(contentName,searchTerm),content.classList.remove("d-none")}else content.classList.add("d-none")})),searchResults},highlight=(text,highlightText)=>{let result=text;if(""!==highlightText){const pos=text.toLowerCase().indexOf(highlightText.toLowerCase());pos>-1&&(result=text.substr(0,pos)+'<span class="matchtext">'+text.substr(pos,highlightText.length)+"</span>"+text.substr(pos+highlightText.length))}return result}}));
//# sourceMappingURL=search.min.js.map
File diff suppressed because one or more lines are too long
+11
View File
@@ -0,0 +1,11 @@
define("core_contentbank/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;
/**
* Define all of the selectors we will be using on the contentbank interface.
*
* @module core_contentbank/selectors
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const getDataSelector=(name,value)=>"[data-".concat(name,'="').concat(value,'"]');var _default={regions:{cbcontentname:getDataSelector("region","cb-content-name"),contentbank:getDataSelector("region","contentbank"),filearea:getDataSelector("region","filearea")},actions:{search:getDataSelector("action","searchcontent"),clearSearch:getDataSelector("action","clearsearch"),viewgrid:getDataSelector("action","viewgrid"),viewlist:getDataSelector("action","viewlist"),sortname:getDataSelector("action","sortname"),sortuses:getDataSelector("action","sortuses"),sortdate:getDataSelector("action","sortdate"),sortsize:getDataSelector("action","sortsize"),sorttype:getDataSelector("action","sorttype"),sortauthor:getDataSelector("action","sortauthor")},elements:{listitem:".cb-listitem",heading:".cb-heading",cell:".cb-column",cbnavbarbreadcrumb:".cb-navbar-breadbrumb",cbnavbartotalsearch:".cb-navbar-totalsearch",searchinput:'[data-action="search"]',sortbutton:".cb-btnsort"}};return _exports.default=_default,_exports.default}));
//# sourceMappingURL=selectors.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the contentbank interface.\n *\n * @module core_contentbank/selectors\n * @copyright 2020 Sara Arjona <sara@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n *\n * @method getDataSelector\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n regions: {\n cbcontentname: getDataSelector('region', 'cb-content-name'),\n contentbank: getDataSelector('region', 'contentbank'),\n filearea: getDataSelector('region', 'filearea')\n },\n actions: {\n search: getDataSelector('action', 'searchcontent'),\n clearSearch: getDataSelector('action', 'clearsearch'),\n viewgrid: getDataSelector('action', 'viewgrid'),\n viewlist: getDataSelector('action', 'viewlist'),\n sortname: getDataSelector('action', 'sortname'),\n sortuses: getDataSelector('action', 'sortuses'),\n sortdate: getDataSelector('action', 'sortdate'),\n sortsize: getDataSelector('action', 'sortsize'),\n sorttype: getDataSelector('action', 'sorttype'),\n sortauthor: getDataSelector('action', 'sortauthor'),\n },\n elements: {\n listitem: '.cb-listitem',\n heading: '.cb-heading',\n cell: '.cb-column',\n cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',\n cbnavbartotalsearch: '.cb-navbar-totalsearch',\n searchinput: '[data-action=\"search\"]',\n sortbutton: '.cb-btnsort'\n },\n};\n"],"names":["getDataSelector","name","value","regions","cbcontentname","contentbank","filearea","actions","search","clearSearch","viewgrid","viewlist","sortname","sortuses","sortdate","sortsize","sorttype","sortauthor","elements","listitem","heading","cell","cbnavbarbreadcrumb","cbnavbartotalsearch","searchinput","sortbutton"],"mappings":";;;;;;;;MA+BMA,gBAAkB,CAACC,KAAMC,wBACXD,kBAASC,yBAGd,CACXC,QAAS,CACLC,cAAeJ,gBAAgB,SAAU,mBACzCK,YAAaL,gBAAgB,SAAU,eACvCM,SAAUN,gBAAgB,SAAU,aAExCO,QAAS,CACLC,OAAQR,gBAAgB,SAAU,iBAClCS,YAAaT,gBAAgB,SAAU,eACvCU,SAAUV,gBAAgB,SAAU,YACpCW,SAAUX,gBAAgB,SAAU,YACpCY,SAAUZ,gBAAgB,SAAU,YACpCa,SAAUb,gBAAgB,SAAU,YACpCc,SAAUd,gBAAgB,SAAU,YACpCe,SAAUf,gBAAgB,SAAU,YACpCgB,SAAUhB,gBAAgB,SAAU,YACpCiB,WAAYjB,gBAAgB,SAAU,eAE1CkB,SAAU,CACNC,SAAU,eACVC,QAAS,cACTC,KAAM,aACNC,mBAAoB,wBACpBC,oBAAqB,yBACrBC,YAAa,yBACbC,WAAY"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
define("core_contentbank/upload",["exports","core_form/modalform","core/str"],(function(_exports,_modalform,_str){var obj;
/**
* Module to handle AJAX interactions with content bank upload files.
*
* @module core_contentbank/upload
* @copyright 2021 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.initModal=void 0,_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};_exports.initModal=(elementSelector,formClass,contextId,contentId)=>{document.querySelector(elementSelector).addEventListener("click",(function(e){e.preventDefault();const form=new _modalform.default({formClass:formClass,args:{contextid:contextId,id:contentId},modalConfig:{title:(0,_str.getString)("upload","contentbank")},returnFocus:e.target});form.addEventListener(form.events.FORM_SUBMITTED,(event=>{document.location=event.detail.returnurl})),form.show()}))}}));
//# sourceMappingURL=upload.min.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"upload.min.js","sources":["../src/upload.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to handle AJAX interactions with content bank upload files.\n *\n * @module core_contentbank/upload\n * @copyright 2021 Sara Arjona <sara@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport ModalForm from 'core_form/modalform';\nimport {getString} from 'core/str';\n\n/**\n * Initialize upload files to the content bank form as Modal form.\n *\n * @param {String} elementSelector\n * @param {String} formClass\n * @param {Integer} contextId\n * @param {Integer} contentId\n */\nexport const initModal = (elementSelector, formClass, contextId, contentId) => {\n const element = document.querySelector(elementSelector);\n element.addEventListener('click', function(e) {\n e.preventDefault();\n const form = new ModalForm({\n formClass,\n args: {\n contextid: contextId,\n id: contentId,\n },\n modalConfig: {title: getString('upload', 'contentbank')},\n returnFocus: e.target,\n });\n form.addEventListener(form.events.FORM_SUBMITTED, (event) => {\n document.location = event.detail.returnurl;\n });\n form.show();\n });\n};\n"],"names":["elementSelector","formClass","contextId","contentId","document","querySelector","addEventListener","e","preventDefault","form","ModalForm","args","contextid","id","modalConfig","title","returnFocus","target","events","FORM_SUBMITTED","event","location","detail","returnurl","show"],"mappings":";;;;;;;wKAiCyB,CAACA,gBAAiBC,UAAWC,UAAWC,aAC7CC,SAASC,cAAcL,iBAC/BM,iBAAiB,SAAS,SAASC,GACvCA,EAAEC,uBACIC,KAAO,IAAIC,mBAAU,CACvBT,UAAAA,UACAU,KAAM,CACFC,UAAWV,UACXW,GAAIV,WAERW,YAAa,CAACC,OAAO,kBAAU,SAAU,gBACzCC,YAAaT,EAAEU,SAEnBR,KAAKH,iBAAiBG,KAAKS,OAAOC,gBAAiBC,QAC/ChB,SAASiB,SAAWD,MAAME,OAAOC,aAErCd,KAAKe"}
+401
View File
@@ -0,0 +1,401 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Module to manage content bank actions, such as delete or rename.
*
* @module core_contentbank/actions
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/templates',
'core/url',
'core/modal_save_cancel',
'core/modal_events'],
function($, Ajax, Notification, Str, Templates, Url, ModalSaveCancel, ModalEvents) {
/**
* List of action selectors.
*
* @type {{DELETE_CONTENT: string}}
*/
var ACTIONS = {
DELETE_CONTENT: '[data-action="deletecontent"]',
RENAME_CONTENT: '[data-action="renamecontent"]',
SET_CONTENT_VISIBILITY: '[data-action="setcontentvisibility"]',
COPY_CONTENT: '[data-action="copycontent"]',
};
/**
* Actions class.
*/
var Actions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
Actions.prototype.registerEvents = function() {
$(ACTIONS.DELETE_CONTENT).click(function(e) {
e.preventDefault();
var contentname = $(this).data('contentname');
var contentuses = $(this).data('uses');
var contentid = $(this).data('contentid');
var contextid = $(this).data('contextid');
var strings = [
{
key: 'deletecontent',
component: 'core_contentbank'
},
{
key: 'deletecontentconfirm',
component: 'core_contentbank',
param: {
name: contentname,
}
},
{
key: 'deletecontentconfirmlinked',
component: 'core_contentbank',
},
{
key: 'delete',
component: 'core'
},
];
var deleteButtonText = '';
Str.get_strings(strings).then(function(langStrings) {
var modalTitle = langStrings[0];
var modalContent = langStrings[1];
if (contentuses > 0) {
modalContent += ' ' + langStrings[2];
}
deleteButtonText = langStrings[3];
return ModalSaveCancel.create({
title: modalTitle,
body: modalContent,
large: true,
removeOnClose: true,
show: true,
buttons: {
save: deleteButtonText,
},
});
}).then(function(modal) {
modal.getRoot().on(ModalEvents.save, function() {
// The action is now confirmed, sending an action for it.
return deleteContent(contentid, contextid);
});
return;
}).catch(Notification.exception);
});
$(ACTIONS.RENAME_CONTENT).click(function(e) {
e.preventDefault();
var contentname = $(this).data('contentname');
var contentid = $(this).data('contentid');
var strings = [
{
key: 'renamecontent',
component: 'core_contentbank'
},
{
key: 'rename',
component: 'core_contentbank'
},
];
var saveButtonText = '';
Str.get_strings(strings).then(function(langStrings) {
var modalTitle = langStrings[0];
saveButtonText = langStrings[1];
return ModalSaveCancel.create({
title: modalTitle,
body: Templates.render('core_contentbank/renamecontent', {'contentid': contentid, 'name': contentname}),
removeOnClose: true,
show: true,
buttons: {
save: saveButtonText,
},
});
}).then(function(modal) {
modal.getRoot().on(ModalEvents.save, function(e) {
// The action is now confirmed, sending an action for it.
var newname = $("#newname").val().trim();
if (newname) {
renameContent(contentid, newname);
} else {
var errorStrings = [
{
key: 'error',
},
{
key: 'emptynamenotallowed',
component: 'core_contentbank',
},
];
Str.get_strings(errorStrings).then(function(langStrings) {
Notification.alert(langStrings[0], langStrings[1]);
}).catch(Notification.exception);
e.preventDefault();
}
});
return;
}).catch(Notification.exception);
});
$(ACTIONS.COPY_CONTENT).click(function(e) {
e.preventDefault();
var contentname = $(this).data('contentname');
var contentid = $(this).data('contentid');
var strings = [
{
key: 'copycontent',
component: 'core_contentbank'
},
{
key: 'error',
},
{
key: 'emptynamenotallowed',
component: 'core_contentbank',
},
];
let errorTitle, errorMessage;
Str.get_strings(strings).then(function(langStrings) {
var modalTitle = langStrings[0];
errorTitle = langStrings[1];
errorMessage = langStrings[2];
return ModalSaveCancel.create({
title: modalTitle,
body: Templates.render('core_contentbank/copycontent', {'contentid': contentid, 'name': contentname}),
removeOnClose: true,
show: true,
});
}).then(function(modal) {
modal.getRoot().on(ModalEvents.save, function() {
// The action is now confirmed, sending an action for it.
var newname = $("#newname").val().trim();
if (newname) {
copyContent(contentid, newname);
} else {
Notification.alert(errorTitle, errorMessage);
return false;
}
});
return;
}).catch(Notification.exception);
});
$(ACTIONS.SET_CONTENT_VISIBILITY).click(function(e) {
e.preventDefault();
var contentid = $(this).data('contentid');
var visibility = $(this).data('visibility');
setContentVisibility(contentid, visibility);
});
};
/**
* Delete content from the content bank.
*
* @param {int} contentid The content to delete.
* @param {int} contextid The contextid where the content belongs.
*/
function deleteContent(contentid, contextid) {
var request = {
methodname: 'core_contentbank_delete_content',
args: {
contentids: {contentid}
}
};
var requestType = 'success';
Ajax.call([request])[0].then(function(data) {
if (data.result) {
return 'contentdeleted';
}
requestType = 'error';
return 'contentnotdeleted';
}).done(function(message) {
var params = {
contextid: contextid
};
if (requestType == 'success') {
params.statusmsg = message;
} else {
params.errormsg = message;
}
// Redirect to the main content bank page and display the message as a notification.
window.location.href = Url.relativeUrl('contentbank/index.php', params, false);
}).fail(Notification.exception);
}
/**
* Rename content in the content bank.
*
* @param {int} contentid The content to rename.
* @param {string} name The new name for the content.
*/
function renameContent(contentid, name) {
var request = {
methodname: 'core_contentbank_rename_content',
args: {
contentid: contentid,
name: name
}
};
var requestType = 'success';
Ajax.call([request])[0].then(function(data) {
if (data.result) {
return 'contentrenamed';
}
requestType = 'error';
return data.warnings[0].message;
}).then(function(message) {
var params = null;
if (requestType == 'success') {
params = {
id: contentid,
statusmsg: message
};
// Redirect to the content view page and display the message as a notification.
window.location.href = Url.relativeUrl('contentbank/view.php', params, false);
} else {
// Fetch error notifications.
Notification.addNotification({
message: message,
type: 'error'
});
Notification.fetchNotifications();
}
return;
}).catch(Notification.exception);
}
/**
* Copy content in the content bank.
*
* @param {int} contentid The content to copy.
* @param {string} name The name for the new content.
*/
function copyContent(contentid, name) {
var request = {
methodname: 'core_contentbank_copy_content',
args: {
contentid: contentid,
name: name
}
};
Ajax.call([request])[0].then(function(data) {
if (data.id == 0) {
// Fetch error notifications.
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
Notification.fetchNotifications();
return data.warnings[0].message;
} else {
let params = {
id: data.id,
statusmsg: 'contentcopied'
};
// Redirect to the content view page and display the message as a notification.
window.location.href = Url.relativeUrl('contentbank/view.php', params, false);
}
return '';
}).catch(Notification.exception);
}
/**
* Set content visibility in the content bank.
*
* @param {int} contentid The content to modify
* @param {int} visibility The new visibility value
*/
function setContentVisibility(contentid, visibility) {
var request = {
methodname: 'core_contentbank_set_content_visibility',
args: {
contentid: contentid,
visibility: visibility
}
};
var requestType = 'success';
Ajax.call([request])[0].then(function(data) {
if (data.result) {
return 'contentvisibilitychanged';
}
requestType = 'error';
return data.warnings[0].message;
}).then(function(message) {
var params = null;
if (requestType == 'success') {
params = {
id: contentid,
statusmsg: message
};
// Redirect to the content view page and display the message as a notification.
window.location.href = Url.relativeUrl('contentbank/view.php', params, false);
} else {
// Fetch error notifications.
Notification.addNotification({
message: message,
type: 'error'
});
Notification.fetchNotifications();
}
return;
}).catch(Notification.exception);
}
return /** @alias module:core_contentbank/actions */ {
// Public variables and functions.
/**
* Initialise the contentbank actions.
*
* @method init
* @return {Actions}
*/
'init': function() {
return new Actions();
}
};
});
+156
View File
@@ -0,0 +1,156 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Search methods for finding contents in the content bank.
*
* @module core_contentbank/search
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import $ from 'jquery';
import selectors from 'core_contentbank/selectors';
import {getString} from 'core/str';
import Pending from 'core/pending';
import {debounce} from 'core/utils';
/**
* Set up the search.
*
* @method init
*/
export const init = () => {
const pendingPromise = new Pending();
const root = $(selectors.regions.contentbank);
registerListenerEvents(root);
pendingPromise.resolve();
};
/**
* Register contentbank search related event listeners.
*
* @method registerListenerEvents
* @param {Object} root The root element for the contentbank.
*/
const registerListenerEvents = (root) => {
const searchInput = root.find(selectors.elements.searchinput)[0];
root.on('click', selectors.actions.search, function(e) {
e.preventDefault();
toggleSearchResultsView(root, searchInput.value);
});
root.on('click', selectors.actions.clearSearch, function(e) {
e.preventDefault();
searchInput.value = "";
searchInput.focus();
toggleSearchResultsView(root, searchInput.value);
});
// The search input is also triggered.
searchInput.addEventListener('input', debounce(() => {
// Display the search results.
toggleSearchResultsView(root, searchInput.value);
}, 300));
};
/**
* Toggle (display/hide) the search results depending on the value of the search query.
*
* @method toggleSearchResultsView
* @param {HTMLElement} body The root element for the contentbank.
* @param {String} searchQuery The search query.
*/
const toggleSearchResultsView = async(body, searchQuery) => {
const clearSearchButton = body.find(selectors.actions.clearSearch)[0];
const navbarBreadcrumb = body.find(selectors.elements.cbnavbarbreadcrumb)[0];
const navbarTotal = body.find(selectors.elements.cbnavbartotalsearch)[0];
// Update the results.
const filteredContents = filterContents(body, searchQuery);
if (searchQuery.length > 0) {
// As the search query is present, search results should be displayed.
// Display the "clear" search button in the activity chooser search bar.
clearSearchButton.classList.remove('d-none');
// Change the cb-navbar to display total items found.
navbarBreadcrumb.classList.add('d-none');
navbarTotal.innerHTML = await getString('itemsfound', 'core_contentbank', filteredContents.length);
navbarTotal.classList.remove('d-none');
} else {
// As search query is not present, the search results should be removed.
// Hide the "clear" search button in the activity chooser search bar.
clearSearchButton.classList.add('d-none');
// Display again the breadcrumb in the navbar.
navbarBreadcrumb.classList.remove('d-none');
navbarTotal.classList.add('d-none');
}
};
/**
* Return the list of contents which have a name that matches the given search term.
*
* @method filterContents
* @param {HTMLElement} body The root element for the contentbank.
* @param {String} searchTerm The search term to match.
* @return {Array}
*/
const filterContents = (body, searchTerm) => {
const contents = Array.from(body.find(selectors.elements.listitem));
const searchResults = [];
contents.forEach((content) => {
const contentName = content.getAttribute('data-name');
if (searchTerm === '' || contentName.toLowerCase().includes(searchTerm.toLowerCase())) {
// The content matches the search criteria so it should be displayed and hightlighted.
searchResults.push(content);
const contentNameElement = content.querySelector(selectors.regions.cbcontentname);
contentNameElement.innerHTML = highlight(contentName, searchTerm);
content.classList.remove('d-none');
} else {
content.classList.add('d-none');
}
});
return searchResults;
};
/**
* Highlight a given string in a text.
*
* @method highlight
* @param {String} text The whole text.
* @param {String} highlightText The piece of text to highlight.
* @return {String}
*/
const highlight = (text, highlightText) => {
let result = text;
if (highlightText !== '') {
const pos = text.toLowerCase().indexOf(highlightText.toLowerCase());
if (pos > -1) {
result = text.substr(0, pos) + '<span class="matchtext">' + text.substr(pos, highlightText.length) + '</span>' +
text.substr(pos + highlightText.length);
}
}
return result;
};
+63
View File
@@ -0,0 +1,63 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Define all of the selectors we will be using on the contentbank interface.
*
* @module core_contentbank/selectors
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* A small helper function to build queryable data selectors.
*
* @method getDataSelector
* @param {String} name
* @param {String} value
* @return {string}
*/
const getDataSelector = (name, value) => {
return `[data-${name}="${value}"]`;
};
export default {
regions: {
cbcontentname: getDataSelector('region', 'cb-content-name'),
contentbank: getDataSelector('region', 'contentbank'),
filearea: getDataSelector('region', 'filearea')
},
actions: {
search: getDataSelector('action', 'searchcontent'),
clearSearch: getDataSelector('action', 'clearsearch'),
viewgrid: getDataSelector('action', 'viewgrid'),
viewlist: getDataSelector('action', 'viewlist'),
sortname: getDataSelector('action', 'sortname'),
sortuses: getDataSelector('action', 'sortuses'),
sortdate: getDataSelector('action', 'sortdate'),
sortsize: getDataSelector('action', 'sortsize'),
sorttype: getDataSelector('action', 'sorttype'),
sortauthor: getDataSelector('action', 'sortauthor'),
},
elements: {
listitem: '.cb-listitem',
heading: '.cb-heading',
cell: '.cb-column',
cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',
cbnavbartotalsearch: '.cb-navbar-totalsearch',
searchinput: '[data-action="search"]',
sortbutton: '.cb-btnsort'
},
};
+269
View File
@@ -0,0 +1,269 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Content bank UI actions.
*
* @module core_contentbank/sort
* @copyright 2020 Bas Brands <bas@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import selectors from './selectors';
import {getString} from 'core/str';
import Prefetch from 'core/prefetch';
import Notification from 'core/notification';
import {setUserPreference} from 'core_user/repository';
/**
* Set up the contentbank views.
*
* @method init
*/
export const init = () => {
const contentBank = document.querySelector(selectors.regions.contentbank);
Prefetch.prefetchStrings('contentbank', ['contentname', 'uses', 'lastmodified', 'size', 'type', 'author']);
Prefetch.prefetchStrings('moodle', ['sortbyx', 'sortbyxreverse']);
registerListenerEvents(contentBank);
};
/**
* Register contentbank related event listeners.
*
* @method registerListenerEvents
* @param {HTMLElement} contentBank The DOM node of the content bank
*/
const registerListenerEvents = (contentBank) => {
contentBank.addEventListener('click', e => {
const viewList = contentBank.querySelector(selectors.actions.viewlist);
const viewGrid = contentBank.querySelector(selectors.actions.viewgrid);
const fileArea = contentBank.querySelector(selectors.regions.filearea);
const shownItems = fileArea.querySelectorAll(selectors.elements.listitem);
// View as Grid button.
if (e.target.closest(selectors.actions.viewgrid)) {
contentBank.classList.remove('view-list');
contentBank.classList.add('view-grid');
if (fileArea && shownItems) {
fileArea.setAttribute('role', 'list');
shownItems.forEach(listItem => {
listItem.setAttribute('role', 'listitem');
listItem.querySelectorAll(selectors.elements.cell).forEach(cell => cell.removeAttribute('role'));
});
const heading = fileArea.querySelector(selectors.elements.heading);
if (heading) {
heading.removeAttribute('role');
heading.querySelectorAll(selectors.elements.cell).forEach(cell => cell.removeAttribute('role'));
}
}
viewGrid.classList.add('active');
viewList.classList.remove('active');
setViewListPreference(false);
return;
}
// View as List button.
if (e.target.closest(selectors.actions.viewlist)) {
contentBank.classList.remove('view-grid');
contentBank.classList.add('view-list');
if (fileArea && shownItems) {
fileArea.setAttribute('role', 'table');
shownItems.forEach(listItem => {
listItem.setAttribute('role', 'row');
listItem.querySelectorAll(selectors.elements.cell).forEach(cell => cell.setAttribute('role', 'cell'));
});
const heading = fileArea.querySelector(selectors.elements.heading);
if (heading) {
heading.setAttribute('role', 'row');
heading.querySelectorAll(selectors.elements.cell).forEach(cell => cell.setAttribute('role', 'columnheader'));
}
}
viewList.classList.add('active');
viewGrid.classList.remove('active');
setViewListPreference(true);
return;
}
if (fileArea && shownItems) {
// Sort by file name alphabetical
const sortByName = e.target.closest(selectors.actions.sortname);
if (sortByName) {
const ascending = updateSortButtons(contentBank, sortByName);
updateSortOrder(fileArea, shownItems, 'data-file', ascending);
return;
}
// Sort by uses.
const sortByUses = e.target.closest(selectors.actions.sortuses);
if (sortByUses) {
const ascending = updateSortButtons(contentBank, sortByUses);
updateSortOrder(fileArea, shownItems, 'data-uses', ascending);
return;
}
// Sort by date.
const sortByDate = e.target.closest(selectors.actions.sortdate);
if (sortByDate) {
const ascending = updateSortButtons(contentBank, sortByDate);
updateSortOrder(fileArea, shownItems, 'data-timemodified', ascending);
return;
}
// Sort by size.
const sortBySize = e.target.closest(selectors.actions.sortsize);
if (sortBySize) {
const ascending = updateSortButtons(contentBank, sortBySize);
updateSortOrder(fileArea, shownItems, 'data-bytes', ascending);
return;
}
// Sort by type.
const sortByType = e.target.closest(selectors.actions.sorttype);
if (sortByType) {
const ascending = updateSortButtons(contentBank, sortByType);
updateSortOrder(fileArea, shownItems, 'data-type', ascending);
return;
}
// Sort by author.
const sortByAuthor = e.target.closest(selectors.actions.sortauthor);
if (sortByAuthor) {
const ascending = updateSortButtons(contentBank, sortByAuthor);
updateSortOrder(fileArea, shownItems, 'data-author', ascending);
}
return;
}
});
};
/**
* Set the contentbank user preference in list view
*
* @param {Bool} viewList view ContentBank as list.
* @return {Promise} Repository promise.
*/
const setViewListPreference = function(viewList) {
// If the given status is not hidden, the preference has to be deleted with a null value.
if (viewList === false) {
viewList = null;
}
return setUserPreference('core_contentbank_view_list', viewList)
.catch(Notification.exception);
};
/**
* Update the sort button view.
*
* @method updateSortButtons
* @param {HTMLElement} contentBank The DOM node of the contentbank button
* @param {HTMLElement} sortButton The DOM node of the sort button
* @return {Bool} sort ascending
*/
const updateSortButtons = (contentBank, sortButton) => {
const sortButtons = contentBank.querySelectorAll(selectors.elements.sortbutton);
sortButtons.forEach((button) => {
if (button !== sortButton) {
button.classList.remove('dir-asc');
button.classList.remove('dir-desc');
button.classList.add('dir-none');
button.closest(selectors.elements.cell).setAttribute('aria-sort', 'none');
updateButtonTitle(button, false);
}
});
let ascending = true;
if (sortButton.classList.contains('dir-none')) {
sortButton.classList.remove('dir-none');
sortButton.classList.add('dir-asc');
sortButton.closest(selectors.elements.cell).setAttribute('aria-sort', 'ascending');
} else if (sortButton.classList.contains('dir-asc')) {
sortButton.classList.remove('dir-asc');
sortButton.classList.add('dir-desc');
sortButton.closest(selectors.elements.cell).setAttribute('aria-sort', 'descending');
ascending = false;
} else if (sortButton.classList.contains('dir-desc')) {
sortButton.classList.remove('dir-desc');
sortButton.classList.add('dir-asc');
sortButton.closest(selectors.elements.cell).setAttribute('aria-sort', 'ascending');
}
updateButtonTitle(sortButton, ascending);
return ascending;
};
/**
* Update the button title.
*
* @method updateButtonTitle
* @param {HTMLElement} button Button to update
* @param {Bool} ascending Sort direction
* @return {Promise} string promise
*/
const updateButtonTitle = (button, ascending) => {
const sortString = (ascending ? 'sortbyxreverse' : 'sortbyx');
return getString(button.dataset.string, 'contentbank')
.then(columnName => {
return getString(sortString, 'core', columnName);
})
.then(sortByString => {
button.setAttribute('title', sortByString);
return sortByString;
})
.catch();
};
/**
* Update the sort order of the itemlist and update the DOM
*
* @method updateSortOrder
* @param {HTMLElement} fileArea the Dom container for the itemlist
* @param {Array} itemList Nodelist of Dom elements
* @param {String} attribute the attribut to sort on
* @param {Bool} ascending Sort Ascending
*/
const updateSortOrder = (fileArea, itemList, attribute, ascending) => {
const sortList = [].slice.call(itemList).sort(function(a, b) {
let aa = a.getAttribute(attribute);
let bb = b.getAttribute(attribute);
if (!isNaN(aa)) {
aa = parseInt(aa);
bb = parseInt(bb);
}
if (ascending) {
return aa > bb ? 1 : -1;
} else {
return aa < bb ? 1 : -1;
}
});
sortList.forEach(listItem => fileArea.appendChild(listItem));
};
+52
View File
@@ -0,0 +1,52 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Module to handle AJAX interactions with content bank upload files.
*
* @module core_contentbank/upload
* @copyright 2021 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import ModalForm from 'core_form/modalform';
import {getString} from 'core/str';
/**
* Initialize upload files to the content bank form as Modal form.
*
* @param {String} elementSelector
* @param {String} formClass
* @param {Integer} contextId
* @param {Integer} contentId
*/
export const initModal = (elementSelector, formClass, contextId, contentId) => {
const element = document.querySelector(elementSelector);
element.addEventListener('click', function(e) {
e.preventDefault();
const form = new ModalForm({
formClass,
args: {
contextid: contextId,
id: contentId,
},
modalConfig: {title: getString('upload', 'contentbank')},
returnFocus: e.target,
});
form.addEventListener(form.events.FORM_SUBMITTED, (event) => {
document.location = event.detail.returnurl;
});
form.show();
});
};