export const init = () => {
const pendingPromise = new Pending();
- const root = $(selectors.elements.main);
+ const root = $(selectors.regions.contentbank);
registerListenerEvents(root);
pendingPromise.resolve();
* @return {Array}
*/
const filterContents = (body, searchTerm) => {
- const contents = Array.from(body.find(selectors.elements.cbfile));
+ const contents = Array.from(body.find(selectors.elements.listitem));
const searchResults = [];
contents.forEach((content) => {
- const contentName = content.getAttribute('data-file');
+ 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);
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', 'clearsearchcontent'),
+ viewgrid: getDataSelector('action', 'viewgrid'),
+ viewlist: getDataSelector('action', 'viewlist'),
+ sortname: getDataSelector('action', 'sortname'),
+ sortdate: getDataSelector('action', 'sortdate'),
+ sortsize: getDataSelector('action', 'sortsize'),
+ sorttype: getDataSelector('action', 'sorttype')
},
elements: {
- cbfile: '.cb-file',
+ listitem: '.cb-listitem',
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',
+ sortbutton: '.cb-btnsort'
},
};
--- /dev/null
+// 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
+ * @package core_contentbank
+ * @copyright 2020 Bas Brands <bas@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+import selectors from 'core_contentbank/selectors';
+import {get_string as getString} from 'core/str';
+import Prefetch from 'core/prefetch';
+
+
+/**
+ * Set up the contentbank views.
+ *
+ * @method init
+ */
+export const init = () => {
+ const contentBank = document.querySelector(selectors.regions.contentbank);
+ Prefetch.prefetchStrings('contentbank', ['sortbyx', 'sortbyxreverse', 'contentname',
+ 'lastmodified', 'size', 'type']);
+ registerListenerEvents(contentBank);
+};
+
+
+/**
+ * Register contentbank related event listeners.
+ *
+ * @method registerListenerEvents
+ * @param {HTMLElement} contentBank The DOM node of the content bank
+ */
+const registerListenerEvents = (contentBank) => {
+
+ // The search.
+ const fileArea = document.querySelector(selectors.regions.filearea);
+ const shownItems = fileArea.querySelectorAll(selectors.elements.listitem);
+
+ // The view buttons.
+ const viewGrid = contentBank.querySelector(selectors.actions.viewgrid);
+ const viewList = contentBank.querySelector(selectors.actions.viewlist);
+
+ viewGrid.addEventListener('click', () => {
+ contentBank.classList.remove('view-list');
+ contentBank.classList.add('view-grid');
+ viewGrid.classList.add('active');
+ viewList.classList.remove('active');
+ });
+
+ viewList.addEventListener('click', () => {
+ contentBank.classList.remove('view-grid');
+ contentBank.classList.add('view-list');
+ viewList.classList.add('active');
+ viewGrid.classList.remove('active');
+ });
+
+ // Sort by file name alphabetical
+ const sortByName = contentBank.querySelector(selectors.actions.sortname);
+ sortByName.addEventListener('click', () => {
+ const ascending = updateSortButtons(contentBank, sortByName);
+ updateSortOrder(fileArea, shownItems, 'data-file', ascending);
+ });
+
+ // Sort by date.
+ const sortByDate = contentBank.querySelector(selectors.actions.sortdate);
+ sortByDate.addEventListener('click', () => {
+ const ascending = updateSortButtons(contentBank, sortByDate);
+ updateSortOrder(fileArea, shownItems, 'data-timemodified', ascending);
+ });
+
+ // Sort by size.
+ const sortBySize = contentBank.querySelector(selectors.actions.sortsize);
+ sortBySize.addEventListener('click', () => {
+ const ascending = updateSortButtons(contentBank, sortBySize);
+ updateSortOrder(fileArea, shownItems, 'data-bytes', ascending);
+ });
+
+ // Sort by type
+ const sortByType = contentBank.querySelector(selectors.actions.sorttype);
+ sortByType.addEventListener('click', () => {
+ const ascending = updateSortButtons(contentBank, sortByType);
+ updateSortOrder(fileArea, shownItems, 'data-type', ascending);
+ });
+};
+
+/**
+ * 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');
+
+ updateButtonTitle(button, false);
+ }
+ });
+
+ let ascending = true;
+
+ if (sortButton.classList.contains('dir-none')) {
+ sortButton.classList.remove('dir-none');
+ sortButton.classList.add('dir-asc');
+ } else if (sortButton.classList.contains('dir-asc')) {
+ sortButton.classList.remove('dir-asc');
+ sortButton.classList.add('dir-desc');
+ ascending = false;
+ } else if (sortButton.classList.contains('dir-desc')) {
+ sortButton.classList.remove('dir-desc');
+ sortButton.classList.add('dir-asc');
+ }
+
+ 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(function (listItem) {
+ fileArea.appendChild(listItem);
+ });
+};
\ No newline at end of file
return $this->content->contenttype;
}
+
+ /**
+ * Returns $this->content->timemodified.
+ *
+ * @return int $this->content->timemodified.
+ */
+ public function get_timemodified(): int {
+ return $this->content->timemodified;
+ }
+
/**
* Updates content_bank table with information in $this->content.
*
global $PAGE;
$PAGE->requires->js_call_amd('core_contentbank/search', 'init');
+ $PAGE->requires->js_call_amd('core_contentbank/sort', 'init');
$data = new stdClass();
$contentdata = array();
foreach ($this->contents as $content) {
- $record = $content->get_content();
+ $file = $content->get_file();
+ $filesize = $file ? $file->get_filesize() : 0;
+ $mimetype = $file ? get_mimetype_description($file) : '';
$contenttypeclass = $content->get_content_type().'\\contenttype';
$contenttype = new $contenttypeclass($this->context);
$name = $content->get_name();
$contentdata[] = array(
'name' => $name,
+ 'title' => strtolower($name),
'link' => $contenttype->get_view_url($content),
- 'icon' => $contenttype->get_icon($content)
+ 'icon' => $contenttype->get_icon($content),
+ 'timemodified' => $content->get_timemodified(),
+ 'bytes' => $filesize,
+ 'size' => display_size($filesize),
+ 'type' => $mimetype
);
}
$data->contents = $contentdata;
{
"contents": [
{
- "name": "accordion.h5p",
+ "name": "Accordion.h5p",
+ "title": "accordion.h5p",
+ "timemodified": 1589792272,
+ "size": "699.3KB",
+ "bytes": 716126,
+ "type": "Archive (H5P)",
"link": "http://something/contentbank/contenttype/h5p/view.php?url=http://something/pluginfile.php/1/contentbank/public/accordion.h5p",
"icon" : "http://something/theme/image.php/boost/core/1581597850/f/h5p-64"
},
}
}}
-<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 class="content-bank-container view-grid" data-region="contentbank">
+ <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 d-flex">
+ {{>core_contentbank/bankcontent/toolbar}}
+ </div>
</div>
-</div>
-<div class="content-bank-container pb-3 border">
- <div class="content-bank">
- <div class="cb-navbar bg-light p-2 border-bottom">
- <div class="cb-navbar-breadbrumb">
- {{#pix}} i/folder {{/pix}}
- </div>
- <div class="cb-navbar-totalsearch d-none">
+ <div class="pb-3 border">
+ <div class="content-bank">
+ <div class="cb-navbar bg-light p-2 border-bottom">
+ <div class="cb-navbar-breadbrumb">
+ {{#pix}} i/folder {{/pix}}
+ </div>
+ <div class="cb-navbar-totalsearch d-none">
+ </div>
</div>
- </div>
- <div class="cb-content-wrapper d-flex flex-wrap p-2">
- {{#contents}}
- <div class="cb-file position-relative mb-2" data-file="{{{name}}}">
- <div class="p-2">
- <div class="cb-thumbnail mb-1 text-center">
- <img class="icon iconsize-big" alt="{{{name}}}" title="{{{name}}}" src="{{{ icon }}}">
+ <div class="cb-content-wrapper d-flex px-2" data-region="filearea">
+ <div class="cb-heading bg-white">
+ <div class="cb-file cb-column d-flex">
+ <div class="title">{{#str}} contentname, contentbank {{/str}}</div>
+ <button class="btn btn-sm cb-btnsort dir-none ml-auto" data-string="contentname" data-action="sortname"
+ title="{{#str}} sortbyx, core, {{#str}} contentname, contentbank {{/str}} {{/str}}">
+ <span class="default">{{#pix}} t/sort, core, {{#str}}sort, core {{/str}} {{/pix}}</span>
+ <span class="desc">{{#pix}} t/sort_desc, core, {{#str}}desc, core{{/str}} {{/pix}}</span>
+ <span class="asc">{{#pix}} t/sort_asc, core, {{#str}}asc, core{{/str}} {{/pix}}</span>
+ </button>
</div>
-
- {{#link}}
- <a href="{{{ link }}}" class="stretched-link" title="{{{name}}}">
- {{/link}}
- <span class="cb-name word-break-all clamp-2 text-center" data-region="cb-content-name">
+ <div class="cb-date cb-column d-flex">
+ <div class="title">{{#str}} lastmodified, contentbank {{/str}}</div>
+ <button class="btn btn-sm cb-btnsort dir-none ml-auto" data-string="lastmodified" data-action="sortdate"
+ title="{{#str}} sortbyx, core, {{#str}} lastmodified, contentbank {{/str}} {{/str}}">
+ <span class="default">{{#pix}} t/sort, core, {{#str}}sort, core {{/str}} {{/pix}}</span>
+ <span class="desc">{{#pix}} t/sort_desc, core, {{#str}}desc, core{{/str}} {{/pix}}</span>
+ <span class="asc">{{#pix}} t/sort_asc, core, {{#str}}asc, core{{/str}} {{/pix}}</span>
+ </button>
+ </div>
+ <div class="cb-size cb-column d-flex">
+ <div class="title">{{#str}} size, contentbank {{/str}}</div>
+ <button class="btn btn-sm cb-btnsort dir-none ml-auto" data-string="size" data-action="sortsize"
+ title="{{#str}} sortbyx, core, {{#str}} size, contentbank {{/str}} {{/str}}">
+ <span class="default">{{#pix}} t/sort, core, {{#str}}sort, core {{/str}} {{/pix}}</span>
+ <span class="desc">{{#pix}} t/sort_desc, core, {{#str}}desc, core{{/str}} {{/pix}}</span>
+ <span class="asc">{{#pix}} t/sort_asc, core, {{#str}}asc, core{{/str}} {{/pix}}</span>
+ </button>
+ </div>
+ <div class="cb-type cb-column d-flex last">
+ <div class="title">{{#str}} type, contentbank {{/str}}</div>
+ <button class="btn btn-sm cb-btnsort dir-none ml-auto" data-string="type" data-action="sorttype"
+ title="{{#str}} sortbyx, core, {{#str}} size, contentbank {{/str}} {{/str}}">
+ <span class="default">{{#pix}} t/sort, core, {{#str}}sort, core {{/str}} {{/pix}}</span>
+ <span class="desc">{{#pix}} t/sort_desc, core, {{#str}}desc, core{{/str}} {{/pix}}</span>
+ <span class="asc">{{#pix}} t/sort_asc, core, {{#str}}asc, core{{/str}} {{/pix}}</span>
+ </button>
+ </div>
+ </div>
+ {{#contents}}
+ <div class="cb-listitem"
+ data-file="{{{ title }}}"
+ data-name="{{{ name }}}"
+ data-bytes="{{ bytes }}"
+ data-timemodified="{{ timemodified }}"
+ data-type="{{{ type }}}">
+ <div class="cb-file cb-column position-relative">
+ <div class="cb-thumbnail" role="img" aria-label="{{{ name }}}"
+ style="background-image: url('{{{ icon }}}');">
+ </div>
+ <a href="{{{ link }}}" class="cb-link stretched-link">
+ <span class="cb-name word-break-all clamp-2" data-region="cb-content-name">
{{{ name }}}
</span>
- {{#link}}
</a>
- {{/link}}
+ </div>
+ <div class="cb-date cb-column small">
+ {{#userdate}} {{ timemodified }}, {{#str}} strftimedatetimeshort, core_langconfig {{/str}} {{/userdate}}
+ </div>
+ <div class="cb-size cb-column small">
+ {{ size }}
+ </div>
+ <div class="cb-type cb-column last small">
+ {{{ type }}}
+ </div>
</div>
+ {{/contents}}
</div>
- {{/contents}}
</div>
</div>
</div>
}
}}
-<div class="content-bank-toolbar card border-0 mb-3">
- <div class="content-bank">
- <div class="cb-toolbar float-sm-right">
- {{#tools}}
- {{#link}}<a href="{{{ link }}}" title="{{{ name }}}">{{/link}}
- <div class="cb-tool icon-no-margin btn btn-secondary btn-lg">
- {{#pix}} {{{ icon }}} {{/pix}} <span class="sr-only">{{{ name }}}</span>
- </div>
- {{#link}}</a>{{/link}}
- {{/tools}}
- </div>
- </div>
-</div>
+
+{{#tools}}
+ <a href="{{{ link }}}" class="icon-no-margin btn btn-secondary" title="{{{ name }}}">
+ {{#pix}} {{{ icon }}} {{/pix}} {{{ name }}}
+ </a>
+{{/tools}}
+<button class="icon-no-margin btn btn-secondary active ml-2"
+title="{{#str}} displayicons, contentbank {{/str}}"
+data-action="viewgrid">
+ {{#pix}}a/view_icon_active, core, {{#str}} displayicons, contentbank {{/str}} {{/pix}}
+</button>
+<button class="icon-no-margin btn btn-secondary"
+title="{{#str}} displaydetails, contentbank {{/str}}"
+data-action="viewlist">
+ {{#pix}}t/viewdetails, core, {{#str}} displaydetails, contentbank {{/str}} {{/pix}}
+</button>
\ No newline at end of file
--- /dev/null
+@core @core_contentbank @contentbank_h5p @javascript
+Feature: Sort content in the content bank
+ In order to temporarily organise the content of the content bank
+ As an admin
+ I need to be able to sort the content bank in various ways
+
+ Background:
+ Given the following "contentbank content" exist:
+ | contextlevel | reference | contenttype | user | contentname |
+ | System | | contenttype_h5p | admin | Dragon_santjordi.h5p |
+ | System | | contenttype_h5p | admin | mathsbook.h5p |
+ | System | | contenttype_h5p | admin | historybook.h5p |
+ | System | | contenttype_h5p | admin | santjordi.h5p |
+ | System | | contenttype_h5p | admin | santjordi_rose.h5p |
+ | System | | contenttype_h5p | admin | SantJordi_book |
+
+ Scenario: Admins can order 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"
+ When I click on "Display contentbank with file details" "button"
+ And I click on "Sort by Content name ascending" "button"
+ And "Dragon_santjordi.h5p" "text" should appear before "historybook.h5p" "text"
+ And "historybook.h5p" "text" should appear before "mathsbook.h5p" "text"
+ And "SantJordi_book" "text" should appear before "santjordi_rose.h5p" "text"
+ And I click on "Sort by Content name descending" "button"
+ And "historybook.h5p" "text" should appear before "Dragon_santjordi.h5p" "text"
+ And "mathsbook.h5p" "text" should appear before "historybook.h5p" "text"
+ Then "santjordi_rose.h5p" "text" should appear before "SantJordi_book" "text"
$string['errordeletingcontentfromcategory'] = 'Error deleting content from category {$a}.';
$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['displaydetails'] = 'Display contentbank with file details';
+$string['displayicons'] = 'Display contentbank with icons';
$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['lastmodified'] = 'Last modified';
$string['name'] = 'Content';
$string['nopermissiontodelete'] = 'You do not have permission to delete content.';
$string['nopermissiontomanage'] = 'You do not have permission to manage content.';
$string['rename'] = 'Rename';
$string['renamecontent'] = 'Rename content';
$string['searchcontentbankbyname'] = 'Search for content by name';
+$string['size'] = 'Size';
$string['timecreated'] = 'Time created';
+$string['type'] = 'Type';
$string['unsupported'] = 'This content type is not supported.';
$string['upload'] = 'Upload';
-@include media-breakpoint-down(sm) {
- .content-bank-container .cb-file {
- flex-basis: 50%;
+.content-bank-container {
+ .cb-content-wrapper {
+ padding: 0.5rem;
+ min-height: 140px;
+ max-height: 500px;
+ overflow-x: auto;
+ flex-wrap: wrap;
+ }
+ .cb-thumbnail {
+ width: 24px;
+ height: 24px;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
}
-}
+ &.view-grid {
+ .cb-listitem {
+ margin-bottom: 0.5rem;
+ }
+
+ @include media-breakpoint-down(sm) {
+ .cb-listitem {
+ flex-basis: 50%;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ .cb-listitem {
+ max-width: 120px;
+ min-width: 120px;
+ }
+ }
-@include media-breakpoint-up(sm) {
- .content-bank-container .cb-file {
- max-width: 120px;
- min-width: 120px;
+ .cb-name {
+ text-align: center;
+ }
+ .cb-file {
+ padding: 0.5rem;
+ }
+ .cb-thumbnail {
+ width: 64px;
+ height: 64px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 0.5rem;
+ }
+ .cb-heading,
+ .cb-date,
+ .cb-size,
+ .cb-type {
+ display: none;
+ }
}
-}
-.content-bank-container {
- min-height: 140px;
+ &.view-list {
+ .cb-content-wrapper {
+ padding: 0 0.5rem;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ }
+
+ .cb-thumbnail {
+ margin-right: 0.5rem;
+ }
+
+ .cb-listitem,
+ .cb-heading {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+ border-bottom: $border-width solid $border-color;
+ }
+
+ .cb-column {
+ display: flex;
+ padding: 0.25rem;
+ }
+
+ .cb-column {
+ border-right: $border-width solid $border-color;
+ }
+
+ @include media-breakpoint-down(sm) {
+ .cb-column {
+ flex: 0 0 50%;
+ max-width: 50%;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ .cb-heading {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ }
+
+ .cb-file,
+ .cb-date {
+ flex: 0 0 35%;
+ max-width: 35%;
+ }
+ .cb-size,
+ .cb-type {
+ flex: 0 0 15%;
+ max-width: 15%;
+ }
+ .cb-column.last {
+ border-right: 0;
+ }
+ }
+
+ .cb-btnsort {
+ span {
+ display: none;
+ }
+ &.dir-none .default,
+ &.dir-asc .asc,
+ &.dir-desc .desc {
+ display: block;
+ }
+ }
+ }
}
\ No newline at end of file
.cal_courses_flt {
color: #868e96; }
+.content-bank-container .cb-content-wrapper {
+ padding: 0.5rem;
+ min-height: 140px;
+ max-height: 500px;
+ overflow-x: auto;
+ flex-wrap: wrap; }
+
+.content-bank-container .cb-thumbnail {
+ width: 24px;
+ height: 24px;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover; }
+
+.content-bank-container.view-grid .cb-listitem {
+ margin-bottom: 0.5rem; }
+
@media (max-width: 767.98px) {
- .content-bank-container .cb-file {
+ .content-bank-container.view-grid .cb-listitem {
flex-basis: 50%; } }
@media (min-width: 576px) {
- .content-bank-container .cb-file {
+ .content-bank-container.view-grid .cb-listitem {
max-width: 120px;
min-width: 120px; } }
-.content-bank-container {
- min-height: 140px; }
+.content-bank-container.view-grid .cb-name {
+ text-align: center; }
+
+.content-bank-container.view-grid .cb-file {
+ padding: 0.5rem; }
+
+.content-bank-container.view-grid .cb-thumbnail {
+ width: 64px;
+ height: 64px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 0.5rem; }
+
+.content-bank-container.view-grid .cb-heading,
+.content-bank-container.view-grid .cb-date,
+.content-bank-container.view-grid .cb-size,
+.content-bank-container.view-grid .cb-type {
+ display: none; }
+
+.content-bank-container.view-list .cb-content-wrapper {
+ padding: 0 0.5rem;
+ flex-direction: column;
+ flex-wrap: nowrap; }
+
+.content-bank-container.view-list .cb-thumbnail {
+ margin-right: 0.5rem; }
+
+.content-bank-container.view-list .cb-listitem,
+.content-bank-container.view-list .cb-heading {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+ border-bottom: 1px solid #dee2e6; }
+
+.content-bank-container.view-list .cb-column {
+ display: flex;
+ padding: 0.25rem; }
+
+.content-bank-container.view-list .cb-column {
+ border-right: 1px solid #dee2e6; }
+
+@media (max-width: 767.98px) {
+ .content-bank-container.view-list .cb-column {
+ flex: 0 0 50%;
+ max-width: 50%; } }
+
+@media (min-width: 576px) {
+ .content-bank-container.view-list .cb-heading {
+ position: sticky;
+ top: 0;
+ z-index: 1; }
+ .content-bank-container.view-list .cb-file,
+ .content-bank-container.view-list .cb-date {
+ flex: 0 0 35%;
+ max-width: 35%; }
+ .content-bank-container.view-list .cb-size,
+ .content-bank-container.view-list .cb-type {
+ flex: 0 0 15%;
+ max-width: 15%; }
+ .content-bank-container.view-list .cb-column.last {
+ border-right: 0; } }
+
+.content-bank-container.view-list .cb-btnsort span {
+ display: none; }
+
+.content-bank-container.view-list .cb-btnsort.dir-none .default,
+.content-bank-container.view-list .cb-btnsort.dir-asc .asc,
+.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
+ display: block; }
/* course.less */
/* COURSE CONTENT */
.cal_courses_flt {
color: #868e96; }
+.content-bank-container .cb-content-wrapper {
+ padding: 0.5rem;
+ min-height: 140px;
+ max-height: 500px;
+ overflow-x: auto;
+ flex-wrap: wrap; }
+
+.content-bank-container .cb-thumbnail {
+ width: 24px;
+ height: 24px;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover; }
+
+.content-bank-container.view-grid .cb-listitem {
+ margin-bottom: 0.5rem; }
+
@media (max-width: 767.98px) {
- .content-bank-container .cb-file {
+ .content-bank-container.view-grid .cb-listitem {
flex-basis: 50%; } }
@media (min-width: 576px) {
- .content-bank-container .cb-file {
+ .content-bank-container.view-grid .cb-listitem {
max-width: 120px;
min-width: 120px; } }
-.content-bank-container {
- min-height: 140px; }
+.content-bank-container.view-grid .cb-name {
+ text-align: center; }
+
+.content-bank-container.view-grid .cb-file {
+ padding: 0.5rem; }
+
+.content-bank-container.view-grid .cb-thumbnail {
+ width: 64px;
+ height: 64px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 0.5rem; }
+
+.content-bank-container.view-grid .cb-heading,
+.content-bank-container.view-grid .cb-date,
+.content-bank-container.view-grid .cb-size,
+.content-bank-container.view-grid .cb-type {
+ display: none; }
+
+.content-bank-container.view-list .cb-content-wrapper {
+ padding: 0 0.5rem;
+ flex-direction: column;
+ flex-wrap: nowrap; }
+
+.content-bank-container.view-list .cb-thumbnail {
+ margin-right: 0.5rem; }
+
+.content-bank-container.view-list .cb-listitem,
+.content-bank-container.view-list .cb-heading {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+ border-bottom: 1px solid #dee2e6; }
+
+.content-bank-container.view-list .cb-column {
+ display: flex;
+ padding: 0.25rem; }
+
+.content-bank-container.view-list .cb-column {
+ border-right: 1px solid #dee2e6; }
+
+@media (max-width: 767.98px) {
+ .content-bank-container.view-list .cb-column {
+ flex: 0 0 50%;
+ max-width: 50%; } }
+
+@media (min-width: 576px) {
+ .content-bank-container.view-list .cb-heading {
+ position: sticky;
+ top: 0;
+ z-index: 1; }
+ .content-bank-container.view-list .cb-file,
+ .content-bank-container.view-list .cb-date {
+ flex: 0 0 35%;
+ max-width: 35%; }
+ .content-bank-container.view-list .cb-size,
+ .content-bank-container.view-list .cb-type {
+ flex: 0 0 15%;
+ max-width: 15%; }
+ .content-bank-container.view-list .cb-column.last {
+ border-right: 0; } }
+
+.content-bank-container.view-list .cb-btnsort span {
+ display: none; }
+
+.content-bank-container.view-list .cb-btnsort.dir-none .default,
+.content-bank-container.view-list .cb-btnsort.dir-asc .asc,
+.content-bank-container.view-list .cb-btnsort.dir-desc .desc {
+ display: block; }
/* course.less */
/* COURSE CONTENT */