feat: Use dropdown for units when more then 15
When dealing with subsections that have a lot of units, show a dropdown for unit selection to simplify navigation.
This commit is contained in:
committed by
Farhaan Bukhsh
parent
bbc0cc2baa
commit
0fbfc1cf54
@@ -4,6 +4,23 @@
|
||||
from django.conf import settings
|
||||
%>
|
||||
|
||||
<script type="text/template" id="dropdown-button-tpl">
|
||||
<li id="dropdown-container" class="h-100">
|
||||
<button
|
||||
id="dropdown-sequence-list-button"
|
||||
class="dropdown-toggle"
|
||||
type="button"
|
||||
>
|
||||
<span class="icon fa fa-chevron-down" aria-hidden="true"></span>
|
||||
</button>
|
||||
<div id="dropdown-sequence-list" style="display: none; position: absolute; width: 240px; right: 0;">
|
||||
<ol class="d-block dropdown-menu bg-white py-0 shadow-sm border"
|
||||
aria-labelledby="dropdown-sequence-list-button">
|
||||
</ol>
|
||||
</div>
|
||||
</li>
|
||||
</script>
|
||||
|
||||
<div id="sequence_${element_id}" class="sequence" data-id="${item_id}"
|
||||
data-position="${position}"
|
||||
data-next-url="${next_url}" data-prev-url="${prev_url}"
|
||||
@@ -46,7 +63,7 @@
|
||||
</li>
|
||||
% else:
|
||||
% for idx, item in enumerate(items):
|
||||
<li role="presentation">
|
||||
<li role="presentation" class="sequence-list-item">
|
||||
<button class="seq_${item['type']} inactive nav-item tab"
|
||||
role="tab"
|
||||
tabindex="-1"
|
||||
@@ -98,6 +115,9 @@
|
||||
</ul>
|
||||
</li>
|
||||
% endif
|
||||
% if show_dropdown:
|
||||
## <%include file='seq_dropdown.html' args="items=items[15:], start_index=15"/>
|
||||
% endif
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const { HtmlUtils } = window.edx;
|
||||
|
||||
this.Sequence = (function() {
|
||||
function Sequence(element, runtime) {
|
||||
var self = this;
|
||||
@@ -26,6 +28,9 @@
|
||||
this.goto = function(event) {
|
||||
return Sequence.prototype.goto.apply(self, [event]);
|
||||
};
|
||||
this.toggleDropdown = function(event) {
|
||||
return Sequence.prototype.toggleDropdown.apply(self, [event]);
|
||||
};
|
||||
this.toggleArrows = function() {
|
||||
return Sequence.prototype.toggleArrows.apply(self);
|
||||
};
|
||||
@@ -38,6 +43,12 @@
|
||||
this.displayTabTooltip = function(event) {
|
||||
return Sequence.prototype.displayTabTooltip.apply(self, [event]);
|
||||
};
|
||||
this.renderDropdown = function() {
|
||||
return Sequence.prototype.renderDropdown.apply(self);
|
||||
}
|
||||
this.handleClickOutsideDropdown = function(event) {
|
||||
return Sequence.prototype.handleClickOutsideDropdown.apply(self, [event]);
|
||||
}
|
||||
this.arrowKeys = {
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
@@ -62,23 +73,87 @@
|
||||
this.showCompletion = this.el.data('show-completion');
|
||||
this.keydownHandler($(element).find('#sequence-list .tab'));
|
||||
this.base_page_title = ($('title').data('base-title') || '').trim();
|
||||
this.dropdownButtonTpl = _.template($('#dropdown-button-tpl').text())({});
|
||||
this.renderDropdown();
|
||||
this.bind();
|
||||
this.render(parseInt(this.el.data('position'), 10));
|
||||
}
|
||||
|
||||
Sequence.prototype.renderDropdown = function() {
|
||||
// Renders the dropdown when there isn't enough space for all units in the bar
|
||||
// Hide the dropdown by default and only show if needed.
|
||||
this.$('#sequence-list > #dropdown-container').hide();
|
||||
this.$(`#sequence-list > li.sequence-list-item`).show();
|
||||
// Calculate the number of tabs that can fit comfortably and if the
|
||||
// number of units is greater we show the dropdown.
|
||||
const tabListWidth = this.$('#sequence-list').width();
|
||||
const singleTabWidth = this.$('#sequence-list > li:first').width();
|
||||
const tabCount = this.$('#sequence-list > li.sequence-list-item').length;
|
||||
const overFlowCount = Math.floor(tabListWidth / singleTabWidth);
|
||||
// Reduce 1 to offsets index and another one to accommodate the button
|
||||
const overFlowIdx = overFlowCount - 2;
|
||||
const showDropdown = overFlowCount < tabCount;
|
||||
if (!showDropdown) {
|
||||
return;
|
||||
}
|
||||
// If the dropdown button doesn't exist add it, otherwise move the
|
||||
// existing button to the correct place.
|
||||
if (this.$('#sequence-list > #dropdown-container').length === 0) {
|
||||
// xss-lint: disable=javascript-jquery-insertion
|
||||
this.$('#sequence-list > li.sequence-list-item').eq(overFlowIdx).after(this.dropdownButtonTpl);
|
||||
} else {
|
||||
this.$('#sequence-list > li.sequence-list-item').eq(overFlowIdx)
|
||||
// xss-lint: disable=javascript-jquery-insertion
|
||||
.after(this.$('#sequence-list > #dropdown-container'));
|
||||
}
|
||||
// Show the dropdown UX and hide all the overflowing unit buttons.
|
||||
this.$('#sequence-list > #dropdown-container').show();
|
||||
this.$(`#sequence-list > li.sequence-list-item:lt(${overFlowIdx + 1})`).show();
|
||||
this.$(`#sequence-list > li.sequence-list-item:gt(${overFlowIdx})`).hide();
|
||||
const dropdownList = this.$('#dropdown-sequence-list > ol');
|
||||
// The dropdown buttons are modified copies of the unit nav buttons.
|
||||
dropdownList.empty();
|
||||
this.$(`#sequence-list > li.sequence-list-item:gt(${overFlowIdx})`).each((idx, el) => {
|
||||
const cloneEl = $(el).clone();
|
||||
const navButton = cloneEl.find("button");
|
||||
const unitTitle = navButton.data('page-title');
|
||||
navButton.click(self.goto);
|
||||
navButton.find(".sequence-tooltip").remove();
|
||||
navButton.find("span.icon").after(
|
||||
HtmlUtils.joinHtml(HtmlUtils.HTML('<span class="unit-title">'), unitTitle, HtmlUtils.HTML('</span>')).toString()
|
||||
);
|
||||
//xss-lint: disable=javascript-jquery-insert-into-target
|
||||
cloneEl.show().appendTo(dropdownList);
|
||||
});
|
||||
}
|
||||
|
||||
Sequence.prototype.$ = function(selector) {
|
||||
return $(selector, this.el);
|
||||
};
|
||||
|
||||
Sequence.prototype.bind = function() {
|
||||
this.$('#sequence-list .nav-item').click(this.goto);
|
||||
$(document).click(this.handleClickOutsideDropdown);
|
||||
this.$('#dropdown-sequence-list .dropdown-item').click(this.goto);
|
||||
this.$('#dropdown-sequence-list-button').click(this.toggleDropdown);
|
||||
this.$('#sequence-list .nav-item').keypress(this.keyDownHandler);
|
||||
this.el.on('bookmark:add', this.addBookmarkIconToActiveNavItem);
|
||||
this.el.on('bookmark:remove', this.removeBookmarkIconFromActiveNavItem);
|
||||
this.$('#sequence-list .nav-item').on('focus mouseenter', this.displayTabTooltip);
|
||||
this.$('#sequence-list .nav-item').on('blur mouseleave', this.hideTabTooltip);
|
||||
$(window).on('resize', _.debounce(this.renderDropdown.bind(this), 200));
|
||||
};
|
||||
|
||||
Sequence.prototype.handleClickOutsideDropdown = function(event) {
|
||||
if(!this.$('#dropdown-container')?.[0]?.contains(event.target)) {
|
||||
this.$('#dropdown-sequence-list').hide();
|
||||
}
|
||||
}
|
||||
|
||||
Sequence.prototype.toggleDropdown = function() {
|
||||
$('#dropdown-sequence-list').toggle();
|
||||
}
|
||||
|
||||
Sequence.prototype.previousNav = function(focused, index) {
|
||||
var $navItemList,
|
||||
$sequenceList = $(focused).parent().parent();
|
||||
@@ -289,6 +364,7 @@
|
||||
Sequence.prototype.goto = function(event) {
|
||||
var alertTemplate, alertText, isBottomNav, newPosition, widgetPlacement;
|
||||
event.preventDefault();
|
||||
this.$('#dropdown-sequence-list').hide();
|
||||
|
||||
// Links from courseware <a class='seqnav' href='n'>...</a>, was .target_tab
|
||||
if ($(event.currentTarget).hasClass('seqnav')) {
|
||||
|
||||
@@ -78,6 +78,13 @@
|
||||
position: relative;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
max-width: calc(100% - 80px);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav .sequence-list-wrapper {
|
||||
max-width: calc(100% - 160px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
@@ -91,7 +98,7 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav ol li {
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav ol li, .dropdown-toggle {
|
||||
box-sizing: border-box;
|
||||
min-width: 40px;
|
||||
flex-grow: 1;
|
||||
@@ -104,7 +111,11 @@
|
||||
border-right-style: solid;
|
||||
}
|
||||
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav ol li button {
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav ol li .dropdown-toggle {
|
||||
height: 49px !important;
|
||||
}
|
||||
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav ol li button, .dropdown-toggle {
|
||||
width: 100%;
|
||||
height: 49px;
|
||||
position: relative;
|
||||
@@ -119,6 +130,22 @@
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav #dropdown-container ol li button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav #dropdown-container ol li button .unit-title {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
.xmodule_display.xmodule_SequenceBlock .sequence-nav ol li button .icon {
|
||||
display: inline-block;
|
||||
line-height: 100%;
|
||||
|
||||
Reference in New Issue
Block a user