MDL-68483 contentbank: filter contents by name
Credits to Bas and Rafa for helping us to improve the UX. Also to Amaia with her help with Behat tests.
This commit is contained in:
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
define ("core_contentbank/search",["exports","jquery","core_contentbank/selectors","core/str","core/pending","core/utils"],function(a,b,c,d,e,f){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=g(b);c=g(c);e=g(e);function g(a){return a&&a.__esModule?a:{default:a}}function h(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function i(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){h(i,d,e,f,g,"next",a)}function g(a){h(i,d,e,f,g,"throw",a)}f(void 0)})}}var j=function(){var a=new e.default,d=(0,b.default)(c.default.elements.main);k(d);a.resolve()};a.init=j;var k=function(a){var b=a.find(c.default.elements.searchinput)[0];a.on("click",c.default.actions.search,function(c){c.preventDefault();l(a,b.value)});a.on("click",c.default.actions.clearSearch,function(c){c.preventDefault();b.value="";b.focus();l(a,b.value)});b.addEventListener("input",(0,f.debounce)(function(){l(a,b.value)},300))},l=function(){var a=i(regeneratorRuntime.mark(function a(b,e){var f,g,h,i,j;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:f=b.find(c.default.elements.clearsearch)[0];g=b.find(c.default.elements.searchicon)[0];h=b.find(c.default.elements.cbnavbarbreadcrumb)[0];i=b.find(c.default.elements.cbnavbartotalsearch)[0];j=m(b,e);if(!(0<e.length)){a.next=15;break}g.classList.add("d-none");f.classList.remove("d-none");h.classList.add("d-none");a.next=11;return(0,d.get_string)("itemsfound","core_contentbank",j.length);case 11:i.innerHTML=a.sent;i.classList.remove("d-none");a.next=19;break;case 15:f.classList.add("d-none");g.classList.remove("d-none");h.classList.remove("d-none");i.classList.add("d-none");case 19:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),m=function(a,b){var d=Array.from(a.find(c.default.elements.cbfile)),e=[];d.forEach(function(a){var d=a.getAttribute("data-file");if(""===b||d.toLowerCase().includes(b.toLowerCase())){e.push(a);var f=a.querySelector(c.default.regions.cbcontentname);f.innerHTML=n(d,b);a.classList.remove("d-none")}else{a.classList.add("d-none")}});return e},n=function(a,b){var c=a;if(""!==b){var d=a.toLowerCase().indexOf(b.toLowerCase());if(-1<d){c=a.substr(0,d)+"<span class=\"matchtext\">"+a.substr(d,b.length)+"</span>"+a.substr(d+b.length)}}return c}});
|
||||
//# sourceMappingURL=search.min.js.map
|
||||
File diff suppressed because one or more lines are too long
+2
@@ -0,0 +1,2 @@
|
||||
define ("core_contentbank/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={regions:{cbcontentname:b("region","cb-content-name")},actions:{search:b("action","searchcontent"),clearSearch:b("action","clearsearchcontent")},elements:{cbfile:".cb-file",cbnavbarbreadcrumb:".cb-navbar-breadbrumb",cbnavbartotalsearch:".cb-navbar-totalsearch",clearsearch:".input-group-append .clear-icon",main:"#region-main",searchicon:".input-group-append .search-icon",searchinput:"#searchinput"}};a.default=c;return a.default});
|
||||
//# sourceMappingURL=selectors.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/selectors.js"],"names":["getDataSelector","name","value","regions","cbcontentname","actions","search","clearSearch","elements","cbfile","cbnavbarbreadcrumb","cbnavbartotalsearch","clearsearch","main","searchicon","searchinput"],"mappings":"+IAgCMA,CAAAA,CAAe,CAAG,SAACC,CAAD,CAAOC,CAAP,CAAiB,CACrC,sBAAgBD,CAAhB,eAAyBC,CAAzB,OACH,C,GAEc,CACXC,OAAO,CAAE,CACLC,aAAa,CAAEJ,CAAe,CAAC,QAAD,CAAW,iBAAX,CADzB,CADE,CAIXK,OAAO,CAAE,CACLC,MAAM,CAAEN,CAAe,CAAC,QAAD,CAAW,eAAX,CADlB,CAELO,WAAW,CAAEP,CAAe,CAAC,QAAD,CAAW,oBAAX,CAFvB,CAJE,CAQXQ,QAAQ,CAAE,CACNC,MAAM,CAAE,UADF,CAENC,kBAAkB,CAAE,uBAFd,CAGNC,mBAAmB,CAAE,wBAHf,CAINC,WAAW,CAAE,iCAJP,CAKNC,IAAI,CAAE,cALA,CAMNC,UAAU,CAAE,kCANN,CAONC,WAAW,CAAE,cAPP,CARC,C","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 * @package core_contentbank\n * @copyright 2020 Sara Arjona <[email protected]>\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 },\n actions: {\n search: getDataSelector('action', 'searchcontent'),\n clearSearch: getDataSelector('action', 'clearsearchcontent'),\n },\n elements: {\n cbfile: '.cb-file',\n cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',\n cbnavbartotalsearch: '.cb-navbar-totalsearch',\n clearsearch: '.input-group-append .clear-icon',\n main: '#region-main',\n searchicon: '.input-group-append .search-icon',\n searchinput: '#searchinput',\n },\n};\n"],"file":"selectors.min.js"}
|
||||
@@ -0,0 +1,160 @@
|
||||
// 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
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 Sara Arjona <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import selectors from 'core_contentbank/selectors';
|
||||
import {get_string as 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.elements.main);
|
||||
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.elements.clearsearch)[0];
|
||||
const searchIcon = body.find(selectors.elements.searchicon)[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.
|
||||
searchIcon.classList.add('d-none');
|
||||
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');
|
||||
searchIcon.classList.remove('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.cbfile));
|
||||
const searchResults = [];
|
||||
contents.forEach((content) => {
|
||||
const contentName = content.getAttribute('data-file');
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
// 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
|
||||
* @package core_contentbank
|
||||
* @copyright 2020 Sara Arjona <[email protected]>
|
||||
* @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'),
|
||||
},
|
||||
actions: {
|
||||
search: getDataSelector('action', 'searchcontent'),
|
||||
clearSearch: getDataSelector('action', 'clearsearchcontent'),
|
||||
},
|
||||
elements: {
|
||||
cbfile: '.cb-file',
|
||||
cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',
|
||||
cbnavbartotalsearch: '.cb-navbar-totalsearch',
|
||||
clearsearch: '.input-group-append .clear-icon',
|
||||
main: '#region-main',
|
||||
searchicon: '.input-group-append .search-icon',
|
||||
searchinput: '#searchinput',
|
||||
},
|
||||
};
|
||||
@@ -72,6 +72,10 @@ class bankcontent implements renderable, templatable {
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
global $PAGE;
|
||||
|
||||
$PAGE->requires->js_call_amd('core_contentbank/search', 'init');
|
||||
|
||||
$data = new stdClass();
|
||||
$contentdata = array();
|
||||
foreach ($this->contents as $content) {
|
||||
|
||||
@@ -43,15 +43,26 @@
|
||||
}
|
||||
|
||||
}}
|
||||
{{>core_contentbank/toolbar}}
|
||||
<div class="d-flex justify-content-between flex-column flex-sm-row">
|
||||
<div class="cb-search-container mb-2">
|
||||
{{>core_contentbank/bankcontent/search}}
|
||||
</div>
|
||||
<div class="cb-toolbar-container mb-2">
|
||||
{{>core_contentbank/bankcontent/toolbar}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-bank-container pb-3 border">
|
||||
<div class="content-bank">
|
||||
<div class="cb-navbar bg-light p-2 border-bottom">
|
||||
{{#pix}} i/folder {{/pix}}
|
||||
<div class="cb-navbar-breadbrumb">
|
||||
{{#pix}} i/folder {{/pix}}
|
||||
</div>
|
||||
<div class="cb-navbar-totalsearch d-none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="cb-content-wrapper d-flex flex-wrap p-2">
|
||||
{{#contents}}
|
||||
<div class="cb-file position-relative mb-2">
|
||||
<div class="cb-file position-relative mb-2" data-file="{{{name}}}">
|
||||
<div class="p-2">
|
||||
<div class="cb-thumbnail mb-1 text-center">
|
||||
{{{ icon }}}
|
||||
@@ -60,7 +71,7 @@
|
||||
{{#link}}
|
||||
<a href="{{{ link }}}" class="stretched-link" title="{{{name}}}">
|
||||
{{/link}}
|
||||
<span class="cb-name word-break-all clamp-2 text-center" >
|
||||
<span class="cb-name word-break-all clamp-2 text-center" data-region="cb-content-name">
|
||||
{{{ name }}}
|
||||
</span>
|
||||
{{#link}}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_contentbank/bankcontent/search
|
||||
|
||||
Example context (json):
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="searchbar input-group" role="search">
|
||||
<label for="searchinput">
|
||||
<span class="sr-only">{{#str}} searchcontentbankbyname, contentbank {{/str}}</span>
|
||||
</label>
|
||||
<input type="text"
|
||||
id="searchinput"
|
||||
class="form-control searchinput border-right-0"
|
||||
placeholder="{{#str}} search, core {{/str}}"
|
||||
name="search"
|
||||
autocomplete="off"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text bg-transparent">
|
||||
<div class="search-icon">
|
||||
<button class="btn p-0 align-baseline icon-no-margin" data-action="searchcontent"
|
||||
aria-label="{{#str}} search, core {{/str}}">
|
||||
<span class="d-flex" aria-hidden="true">{{#pix}} a/search, core {{/pix}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clear-icon d-none">
|
||||
<button class="btn p-0 align-baseline icon-no-margin" data-action="clearsearchcontent"
|
||||
aria-label="{{#str}} clearsearch, core {{/str}}">
|
||||
<span class="d-flex" aria-hidden="true">{{#pix}} e/cancel_solid_circle, core {{/pix}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_contentbank/toolbar
|
||||
@template core_contentbank/bankcontent/toolbar
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
@@ -38,7 +38,7 @@
|
||||
{{#tools}}
|
||||
{{#link}}<a href="{{{ link }}}" title="{{{ name }}}">{{/link}}
|
||||
<div class="cb-tool icon-no-margin btn btn-secondary btn-lg">
|
||||
{{#pix}} {{{ icon }}} {{/pix}}
|
||||
{{#pix}} {{{ icon }}} {{/pix}} <span class="sr-only">{{{ name }}}</span>
|
||||
</div>
|
||||
{{#link}}</a>{{/link}}
|
||||
{{/tools}}
|
||||
@@ -0,0 +1,51 @@
|
||||
@core @core_contentbank @contentbank_h5p @_file_upload @javascript
|
||||
Feature: Search content in the content bank
|
||||
In order to find easily content in the content bank
|
||||
As an admin
|
||||
I need to be able to search content in the content bank
|
||||
|
||||
Background:
|
||||
Given the following "contentbank content" exist:
|
||||
| contextid | contenttype | user | contentname |
|
||||
| 1 | contenttype_h5p | admin | santjordi.h5p |
|
||||
| 1 | contenttype_h5p | admin | santjordi_rose.h5p |
|
||||
| 1 | contenttype_h5p | admin | SantJordi_book |
|
||||
| 1 | contenttype_h5p | admin | Dragon_santjordi.h5p |
|
||||
| 1 | contenttype_h5p | admin | princess.h5p |
|
||||
| 1 | contenttype_h5p | admin | mathsbook.h5p |
|
||||
| 1 | contenttype_h5p | admin | historybook.h5p |
|
||||
| 1 | contenttype_h5p | admin | santvicenc.h5p |
|
||||
|
||||
Scenario: Admins can search content in the content bank
|
||||
Given I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And I add the "Navigation" block if not present
|
||||
And I expand "Site pages" node
|
||||
And I click on "Content bank" "link"
|
||||
And I should see "santjordi.h5p"
|
||||
And "Clear search input" "button" should not exist
|
||||
And I should not see "items found"
|
||||
When I set the field "Search" to "book"
|
||||
Then "Clear search input" "button" should exist
|
||||
And I should see "3 items found"
|
||||
And I should see "SantJordi_book"
|
||||
And I should see "mathsbook.h5p"
|
||||
And I should see "historybook.h5p"
|
||||
And I set the field "Search" to "sant"
|
||||
And "Clear search input" "button" should exist
|
||||
And I should see "5 items found"
|
||||
And I set the field "Search" to "santjordi"
|
||||
And I should see "4 items found"
|
||||
And I should see "santjordi.h5p"
|
||||
And I should see "santjordi_rose.h5p"
|
||||
And I should see "SantJordi_book"
|
||||
And I should see "Dragon_santjordi.h5p"
|
||||
And I click on "Clear search input" "button"
|
||||
And "Clear search input" "button" should not exist
|
||||
And I should not see "items found"
|
||||
And I set the field "Search" to ".h5p"
|
||||
And "Clear search input" "button" should exist
|
||||
And I should see "7 items found"
|
||||
And I set the field "Search" to "friend"
|
||||
And I should see "0 items found"
|
||||
@@ -37,6 +37,7 @@ $string['deletecontent'] = 'Delete content';
|
||||
$string['deletecontentconfirm'] = 'Are you sure you want to delete the content <em>\'{$a->name}\'</em> and all associated files? This action cannot be undone.';
|
||||
$string['file'] = 'Upload content';
|
||||
$string['file_help'] = 'Files may be stored in the content bank for use in courses. Only files used by content types enabled on the site may be uploaded.';
|
||||
$string['itemsfound'] = '{$a} items found';
|
||||
$string['name'] = 'Content';
|
||||
$string['nopermissiontodelete'] = 'You do not have permission to delete content.';
|
||||
$string['nopermissiontomanage'] = 'You do not have permission to manage content.';
|
||||
@@ -50,6 +51,7 @@ $string['privacy:metadata:contentbankcontent'] = 'Stores the content of the cont
|
||||
$string['privacy:metadata:userid'] = 'The ID of the user creating or modifying content bank content.';
|
||||
$string['rename'] = 'Rename';
|
||||
$string['renamecontent'] = 'Rename content';
|
||||
$string['searchcontentbankbyname'] = 'Search for content by name';
|
||||
$string['timecreated'] = 'Time created';
|
||||
$string['unsupported'] = 'This content type is not supported.';
|
||||
$string['upload'] = 'Upload';
|
||||
|
||||
@@ -2359,6 +2359,12 @@ body.h5p-embed {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.matchtext {
|
||||
background-color: lighten($primary, 40%);
|
||||
color: $body-color;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
// Emoji picker.
|
||||
$picker-width: 350px !default;
|
||||
$picker-width-xs: 320px !default;
|
||||
|
||||
@@ -477,12 +477,6 @@ $message-day-color: color-yiq($message-app-bg) !default;
|
||||
}
|
||||
}
|
||||
|
||||
.matchtext {
|
||||
background-color: lighten($primary, 40%);
|
||||
color: $body-color;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.contact-status {
|
||||
position: absolute;
|
||||
left: 39px;
|
||||
|
||||
@@ -11313,6 +11313,11 @@ body.h5p-embed .h5pmessages {
|
||||
.word-break-all {
|
||||
word-break: break-all; }
|
||||
|
||||
.matchtext {
|
||||
background-color: #b5d9f9;
|
||||
color: #343a40;
|
||||
height: 1.5rem; }
|
||||
|
||||
.emoji-picker {
|
||||
width: 350px;
|
||||
height: 400px; }
|
||||
@@ -14545,10 +14550,6 @@ a.ygtvspacer:hover {
|
||||
flex-shrink: 0; }
|
||||
.message-app .footer-container textarea {
|
||||
direction: ltr; }
|
||||
.message-app .matchtext {
|
||||
background-color: #b5d9f9;
|
||||
color: #343a40;
|
||||
height: 1.5rem; }
|
||||
.message-app .contact-status {
|
||||
position: absolute;
|
||||
left: 39px;
|
||||
|
||||
@@ -11525,6 +11525,11 @@ body.h5p-embed .h5pmessages {
|
||||
.word-break-all {
|
||||
word-break: break-all; }
|
||||
|
||||
.matchtext {
|
||||
background-color: #b5d9f9;
|
||||
color: #343a40;
|
||||
height: 1.5rem; }
|
||||
|
||||
.emoji-picker {
|
||||
width: 350px;
|
||||
height: 400px; }
|
||||
@@ -14761,10 +14766,6 @@ a.ygtvspacer:hover {
|
||||
flex-shrink: 0; }
|
||||
.message-app .footer-container textarea {
|
||||
direction: ltr; }
|
||||
.message-app .matchtext {
|
||||
background-color: #b5d9f9;
|
||||
color: #343a40;
|
||||
height: 1.5rem; }
|
||||
.message-app .contact-status {
|
||||
position: absolute;
|
||||
left: 39px;
|
||||
|
||||
Reference in New Issue
Block a user