new sequence nav functionality - accommodates an infinite number of items
This commit is contained in:
@@ -2,21 +2,52 @@ nav.sequence-nav {
|
||||
// TODO (cpennington): This doesn't work anymore. XModules aren't able to
|
||||
// import from external sources.
|
||||
@extend .topbar;
|
||||
border: 1px solid #ccc;
|
||||
height: 44px;
|
||||
@include linear-gradient(top, #eee, #ddd);
|
||||
@include border-radius(25px);
|
||||
margin: -4px -20px 30px;
|
||||
margin: -4px 0 30px;
|
||||
position: relative;
|
||||
@include box-shadow(0 1px 0 #fff inset);
|
||||
border-bottom: none;
|
||||
|
||||
.left-shadow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 20px;
|
||||
height: 46px;
|
||||
@include linear-gradient(left, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0));
|
||||
background-color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.right-shadow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 20px;
|
||||
height: 46px;
|
||||
@include linear-gradient(right, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0));
|
||||
background-color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sequence-list-wrapper {
|
||||
position: relative;
|
||||
z-index: 9999;
|
||||
border: 1px solid #ccc;
|
||||
height: 44px;
|
||||
margin: 0 30px;
|
||||
@include linear-gradient(top, #ddd, #eee);
|
||||
overflow: hidden;
|
||||
@include box-shadow(0 1px 3px rgba(0, 0, 0, .1) inset);
|
||||
}
|
||||
|
||||
ol {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@include box-sizing(border-box);
|
||||
display: table;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding-left: 3px;
|
||||
padding-right: 90px;
|
||||
padding: 0 10px;
|
||||
width: 100%;
|
||||
|
||||
a {
|
||||
@@ -48,7 +79,6 @@ nav.sequence-nav {
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: $blue;
|
||||
background-color: #fff;
|
||||
z-index: 9;
|
||||
|
||||
@@ -177,26 +207,26 @@ nav.sequence-nav {
|
||||
}
|
||||
|
||||
ul {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
list-style: none;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 81px;
|
||||
margin: 5px 5px 0 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-bottom: 0;
|
||||
@include border-radius(3px 3px 0 0);
|
||||
|
||||
li {
|
||||
float: left;
|
||||
position: absolute;
|
||||
margin-bottom: 0;
|
||||
height: 34px;
|
||||
width: 40px;
|
||||
height: 44px;
|
||||
width: 70px;
|
||||
border: 1px solid #ccc;
|
||||
@include linear-gradient(top, #eee, #ddd);
|
||||
@include box-shadow(0 1px 0 rgba(255, 255, 255, .7) inset);
|
||||
|
||||
&.prev, &.next {
|
||||
@include linear-gradient(top, #ccc, #888);
|
||||
@include box-shadow(0 -1px 0 rgba(0, 0, 0, .2) inset);
|
||||
|
||||
a {
|
||||
background-position: center;
|
||||
@@ -219,21 +249,23 @@ nav.sequence-nav {
|
||||
}
|
||||
|
||||
&.prev {
|
||||
left: -10px;
|
||||
border-radius: 35px 0 0 35px;
|
||||
|
||||
a {
|
||||
background-image: url('../images/sequence-nav/previous-icon.png');
|
||||
background-position: center 10px;
|
||||
background-position: center 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&.next {
|
||||
right: -10px;
|
||||
border-radius: 0 35px 35px 0;
|
||||
|
||||
a {
|
||||
border-left: 1px solid #888;
|
||||
margin-left: 30px;
|
||||
background-image: url('../images/sequence-nav/next-icon.png');
|
||||
background-position: center 10px;
|
||||
background-position: center 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104
lms/static/js/jquery.sequence.js
Normal file
104
lms/static/js/jquery.sequence.js
Normal file
@@ -0,0 +1,104 @@
|
||||
|
||||
|
||||
|
||||
var SequenceNav = function($element) {
|
||||
var _this = this;
|
||||
var $element = $element;
|
||||
var $wrapper = $element.find('.sequence-list-wrapper');
|
||||
var $list = $element.find('#sequence-list');
|
||||
var $arrows = $element.find('.sequence-nav-buttons');
|
||||
var maxScroll = $list.width() - $wrapper.width() + 20;
|
||||
var $leftShadow = $('<div class="left-shadow"></div>');
|
||||
var $rightShadow = $('<div class="right-shadow"></div>');
|
||||
var $body = $('body');
|
||||
var listOrigin;
|
||||
var mouseOrigin;
|
||||
|
||||
var startDrag = function(e) {
|
||||
updateWidths();
|
||||
mouseOrigin = e.pageX;
|
||||
listOrigin = $list.position().left;
|
||||
$body.css('-webkit-user-select', 'none');
|
||||
$body.bind('mousemove', moveDrag);
|
||||
$body.bind('mouseup', stopDrag);
|
||||
};
|
||||
|
||||
var moveDrag = function(e) {
|
||||
var offset = e.pageX - mouseOrigin;
|
||||
var targetLeft = clamp(listOrigin + offset, -maxScroll, 0);
|
||||
|
||||
console.log('---------------');
|
||||
console.log('offset: ' + offset);
|
||||
console.log('target left: ' + targetLeft);
|
||||
console.log('max: ' + maxScroll);
|
||||
|
||||
updateHorizontalPosition(targetLeft);
|
||||
|
||||
setShadows(targetLeft);
|
||||
};
|
||||
|
||||
var stopDrag = function(e) {
|
||||
$body.css('-webkit-user-select', 'auto');
|
||||
$body.unbind('mousemove', moveDrag);
|
||||
$body.unbind('mouseup', stopDrag);
|
||||
};
|
||||
|
||||
var setShadows = function(left) {
|
||||
var left = left || $list.position().left;
|
||||
var padding = 30;
|
||||
|
||||
var leftPercent = clamp(-left / padding, 0, 1);
|
||||
$leftShadow.css('opacity', leftPercent);
|
||||
|
||||
var rightPercent = clamp((maxScroll + left) / padding, 0, 1);
|
||||
$rightShadow.css('opacity', rightPercent);
|
||||
};
|
||||
|
||||
var clamp = function(val, min, max) {
|
||||
if(val > max) return max;
|
||||
if(val < min) return min;
|
||||
return val;
|
||||
};
|
||||
|
||||
var updateWidths = function(e) {
|
||||
maxScroll = $list.width() - $wrapper.width() + 20;
|
||||
var targetLeft = clamp($list.position().left, -maxScroll, 0);
|
||||
updateHorizontalPosition(targetLeft);
|
||||
setShadows(targetLeft);
|
||||
};
|
||||
|
||||
var updateHorizontalPosition = function(left) {
|
||||
$list.css({
|
||||
'left': left + 'px'
|
||||
});
|
||||
};
|
||||
|
||||
var checkPosition = function(e) {
|
||||
var $active = $element.find('.active');
|
||||
if(!$active[0]) {
|
||||
return;
|
||||
}
|
||||
if($active.position().left + $active.width() > $wrapper.width() - $list.position().left) {
|
||||
$list.animate({
|
||||
'left': (-$active.position().left + $wrapper.width() - $active.width() - 10) + 'px'
|
||||
}, {
|
||||
step: setShadows
|
||||
});
|
||||
} else if($active.position().left < -$list.position().left) {
|
||||
$list.animate({
|
||||
'left': (-$active.position().left + 10) + 'px'
|
||||
}, {
|
||||
step: setShadows
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$wrapper.append($leftShadow).append($rightShadow);
|
||||
setShadows(0);
|
||||
$wrapper.bind('mousedown', startDrag);
|
||||
$arrows.bind('click', checkPosition);
|
||||
$(window).bind('resize', updateWidths);
|
||||
setTimeout(function() {
|
||||
checkPosition();
|
||||
}, 200);
|
||||
}
|
||||
@@ -29,12 +29,13 @@ a {
|
||||
padding: 1.4em 0 0 0;
|
||||
|
||||
> div {
|
||||
display: table;
|
||||
width: 100%;
|
||||
@include box-sizing(border-box);
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
background: #fff;
|
||||
@include box-shadow(0 1px 10px rgba(0, 0, 0, 0.1));
|
||||
@include box-shadow(0 1px 2px rgba(0, 0, 0, 0.05));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,11 +58,11 @@ nav.course-material {
|
||||
header.global {
|
||||
border-bottom: 1px solid #bbb;
|
||||
@include box-shadow(0 1px 2px rgba(0, 0, 0, .1));
|
||||
height: 45px;
|
||||
height: 50px;
|
||||
@include linear-gradient(top, #fff, #eee);
|
||||
|
||||
nav {
|
||||
padding-top: 2px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
h1.logo {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<%block name="js_extra">
|
||||
<script type="text/javascript" src="${static.url('js/vendor/jquery.scrollTo-1.4.2-min.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.sequence.js')}"></script>
|
||||
|
||||
## codemirror
|
||||
<script type="text/javascript" src="${static.url('js/vendor/codemirror-compressed.js')}"></script>
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<div id="sequence_${element_id}" class="sequence" data-id="${item_id}" data-position="${position}" data-course_modx_root="/course/modx" >
|
||||
<nav aria-label="Section Navigation" class="sequence-nav">
|
||||
<ol id="sequence-list">
|
||||
% for idx, item in enumerate(items):
|
||||
## TODO (vshnayder): add item.progress_detail either to the title or somewhere else.
|
||||
## Make sure it gets updated after ajax calls.
|
||||
## implementation note: will need to figure out how to handle combining detail
|
||||
## statuses of multiple modules in js.
|
||||
<li>
|
||||
<a class="seq_${item['type']} inactive progress-${item['progress_status']}" data-element="${idx+1}">
|
||||
<p>${item['title']}</p>
|
||||
</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ol>
|
||||
<div class="sequence-list-wrapper">
|
||||
<ol id="sequence-list">
|
||||
% for idx, item in enumerate(items):
|
||||
## TODO (vshnayder): add item.progress_detail either to the title or somewhere else.
|
||||
## Make sure it gets updated after ajax calls.
|
||||
## implementation note: will need to figure out how to handle combining detail
|
||||
## statuses of multiple modules in js.
|
||||
<li>
|
||||
<a class="seq_${item['type']} inactive progress-${item['progress_status']}" data-element="${idx+1}">
|
||||
<p>${item['title']}</p>
|
||||
</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<ul class="sequence-nav-buttons">
|
||||
<li class="prev"><a href="#">Previous</a></li>
|
||||
@@ -32,3 +34,15 @@
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var sequenceNav;
|
||||
$(document).ready(function() {
|
||||
// console.log($('.sequence-nav'));
|
||||
|
||||
sequenceNav = new SequenceNav($('.sequence-nav'));
|
||||
console.log(sequenceNav);
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user