Commit d3ca5212 by Dennis Jen

Added hooks for engagement, enrollment, overview, and performance pages

  * refactored original pages into modular templates and partials
  * added urls to link to new views
  * updated bootstrap to .min version
  * added hooks for placeholder images

AN-1296 # resolve

Change-Id: I3c0a8f035e7dabee09b2988c9c61e9310d01a3b0
parent 1419673e
{% extends "base.html" %}
{% load staticfiles %}
{% block view-name %}view-placeholder{% endblock view-name %}
{% block content %}
<div id="analytics-init-data" class="container" data-analytics-init='{{ page_data | safe }}'>
<div class="row">
<div class="col-xs-12 col-md-8">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras at nisi vestibulum, interdum elit in, pellentesque velit. Curabitur lacinia sollicitudin commodo. Nam enim velit, semper et lacinia at, imperdiet sit amet arcu. Praesent dictum porta tortor, sed congue massa euismod id. Mauris dignissim turpis eu risus volutpat, vel imperdiet nunc aliquet. Morbi est ipsum, mollis eleifend condimentum quis, porttitor ut ligula. Aliquam diam risus, bibendum in justo eget, lobortis ullamcorper lorem. Vivamus elit turpis, fringilla nec magna in, condimentum lobortis nunc. Maecenas nec arcu consequat, auctor ipsum ac, malesuada orci. Sed bibendum nulla enim, quis scelerisque quam mattis vitae. In eleifend, sem eu pulvinar dictum, dui ante faucibus eros, placerat dictum orci nibh eget justo. Morbi quis adipiscing arcu. Vestibulum semper metus ac aliquam dapibus. Sed feugiat vulputate massa, ac ultricies arcu congue vel. Ut eget egestas erat. Donec molestie sem eu leo consequat, nec posuere mauris lobortis.</p>
</div>
<div class="col-xs-6 col-md-4">
<p>
Nunc in eleifend dolor, vel ornare orci. Nullam venenatis iaculis urna, vel feugiat est rutrum at. Nullam lacinia elementum nibh at condimentum. In adipiscing vel neque a mattis. Aliquam lobortis at odio et eleifend. Etiam suscipit vitae ante nec aliquet. Donec egestas velit at commodo sagittis. Ut imperdiet, turpis mattis rutrum accumsan, libero justo euismod tellus, at pulvinar orci felis sed lectus. Nullam ut sapien nec velit faucibus gravida ac ac orci. Nam feugiat massa nec bibendum tincidunt. In lobortis feugiat leo, ut laoreet lorem rutrum sit amet.
</p>
</div>
<div class="col-xs-6 col-md-4">
<p>Aliquam lacinia, felis at cursus dictum, justo augue placerat erat, sed lacinia leo quam id mauris. Maecenas venenatis ligula facilisis, vulputate purus sed, condimentum odio. Maecenas nisi nulla, pellentesque ac mollis non, aliquam in sem. Integer euismod, ipsum id cursus posuere, risus libero tristique nulla, sit amet blandit leo diam in arcu. Sed a libero interdum, suscipit dui eget, tincidunt orci. Vestibulum cursus tellus eget enim tempus, in commodo tortor fermentum. Phasellus ut dapibus eros, non condimentum purus. Proin tincidunt sem sit amet felis accumsan, sed vehicula ligula consectetur. Cras in odio urna. Aliquam ut leo aliquet, sollicitudin sem eget, pellentesque risus. Mauris at rhoncus arcu, vitae imperdiet dolor. In hac habitasse platea dictumst. Curabitur id magna leo. Maecenas aliquet vel augue et aliquam. In vitae est quis quam suscipit tempus eget sit amet lectus. Curabitur a porta lacus.</p>
</div>
<div class="col-xs-6 col-md-4">
<p>Duis quis sodales ipsum, laoreet auctor ipsum. Pellentesque consequat volutpat felis ac dictum. Maecenas sodales malesuada magna, ac laoreet urna consequat ut. Nunc eget ligula eleifend, ornare diam non, vulputate nunc. In sit amet commodo mauris. Vivamus pharetra arcu gravida tincidunt interdum. Suspendisse potenti. Fusce non tellus a metus interdum bibendum. Quisque id molestie ante, vel pellentesque magna. Sed gravida eleifend erat pharetra consectetur. Suspendisse cursus justo et faucibus porttitor. Nam feugiat purus in neque sodales, sed volutpat nunc hendrerit. Etiam venenatis pretium lectus in lacinia. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam viverra turpis eu ligula condimentum placerat.</p>
</div>
<div class="col-xs-6 col-md-4">
<p>Praesent sed augue et urna bibendum fringilla. Nam nisi risus, ornare in pellentesque non, volutpat eu lacus. Etiam et ultricies magna, non facilisis augue. Aliquam eleifend eget sem in pretium. Praesent enim purus, posuere at orci ac, bibendum laoreet diam. Phasellus pharetra ullamcorper aliquet. Phasellus pellentesque, purus sit amet sollicitudin semper, turpis risus viverra dui, ut consectetur dolor neque in lectus. Etiam at mi turpis.</p>
</div>
</div>
</div>
{% endblock content %}
{% block javascript %}
<script data-main="{% static 'js/course-analytics.js' %}" src="{% static 'vendor/require.js' %}"></script>
{% endblock javascript %}
\ No newline at end of file
{% extends "base.html" %}
{% comment %}
Individual course centric overview view
{% endcomment %}
{% block view-name %}view-course-overview view-dashboard{% endblock view-name %}
{% block intro-text %}
[Intro summary area for Overview if needed] Curabitur blandit tempus porttitor. Etiam porta sem malesuada magna mollis euismod. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.
{% endblock intro-text %}
from django.conf.urls import patterns, url
from django.conf.urls import patterns, include, url
from courses import views
urlpatterns = patterns('',
urlpatterns = [
url(r'^(?P<course_id>\d+)/',
include([
url(r'^enrollment/$', views.enrollment),
url(r'^engagement/$', views.engagement),
url(r'^performance/$', views.performance),
url(r'^overview/$', views.overview),
])
)
# , views.analytics, name='analytics'),
# url(r'^(?P<course_id>\d+\[^/]+)(/)?enrollment/$', views.enrollment, name='enrollment'),
# ex: /courses/5/
url(r'^(?P<course_id>\d+)/$', views.analytics, name='analytics'),
)
\ No newline at end of file
# url(r'^(?P<course_id>\d+)/$', views.analytics, name='analytics'),
# url(r'^(?P<course_id>\d+\[^/]+)(/)?enrollment/$', views.enrollment, name='enrollment'),
]
\ No newline at end of file
......@@ -5,15 +5,36 @@ import json
from models import Course
def analytics(request, course_id):
# TODO: we would ideally get this from the DB, but for now lets stub some data
def get_default_data(course_id):
page_data = {
'name': 'Dennis',
'courseId': str(course_id),
}
# we would ideally get this from the DB, but for now lets stub some data
context = {'user_name': 'Ed Xavier',
'course_number': 'MITx 7.3423',
'course_title': 'Introduction to Awesomeness',
'page_data': json.dumps(page_data)
return {
'user_name': 'Ed Xavier',
'course_number': 'MITx 7.3423',
'course_title': 'Introduction to Awesomeness',
'page_data': json.dumps(page_data)
}
return render(request, 'courses/analytics.html', context)
def enrollment(request, course_id):
context = get_default_data(course_id)
context['page_title'] = 'Enrollment'
return render(request, 'courses/enrollment.html', context)
def overview(request, course_id):
context = get_default_data(course_id)
context['page_title'] = 'Overview'
return render(request, 'courses/overview.html', context)
def engagement(request, course_id):
context = get_default_data(course_id)
context['page_title'] = 'Engagement'
return render(request, 'courses/engagement.html', context)
def performance(request, course_id):
context = get_default_data(course_id)
context['page_title'] = 'Performance'
return render(request, 'courses/performance.html', context)
......@@ -8,16 +8,14 @@ require.config({
jquery: 'vendor/jquery-1.11.1.min',
underscore: 'vendor/underscore-min',
backbone: 'vendor/backbone-min',
bootstrap: 'vendor/bootstrap/javascripts/bootstrap',
bootstrap: 'vendor/bootstrap/javascripts/bootstrap.min',
models: 'js/models',
views: 'js/views'
views: 'js/views',
holder: 'vendor/holder'
},
shim: {
bootstrap: {
deps: ['jquery'],
// http://stackoverflow.com/questions/13377373/shim-twitter-bootstrap-for-requirejs
// for making sure that bootstrap is loaded correctly
exports: '$.fn.popover'
deps: ['jquery']
},
underscore: {
exports: '_'
......@@ -32,8 +30,8 @@ require.config({
});
require(['jquery', 'underscore', 'backbone',
'models/course-model', 'views/lens-navigation-view', 'bootstrap'],
function ($, _, Backbone, CourseModel, LensNavigationView) {
'models/course-model', 'views/lens-navigation-view', 'bootstrap', 'holder'],
function ($, _, Backbone, CourseModel, LensNavigationView, bootstrap, holder) {
'use strict';
$(document).ready(function () {
// ok, we've loaded all the libraries and the page is loaded, so
......@@ -43,9 +41,13 @@ require(['jquery', 'underscore', 'backbone',
onLoad: function() {
var model,
view,
jsonData = JSON.parse( $('#analytics-init-data')
jsonData = JSON.parse( $('#content')
.attr('data-analytics-init') );
// TODO: remove when we don't need the stub images anymore.
// holder is used to render visual placeholders
holder.run();
// this data will be set by something else eventually
model = new CourseModel();
// lets assume that django is passing us the data in the correct format for now
......@@ -53,6 +55,7 @@ require(['jquery', 'underscore', 'backbone',
view = new LensNavigationView({model: model});
view.render();
}
};
......
......@@ -4,15 +4,11 @@ define(['jquery', 'backbone', 'models/course-model'],
var LensNavigationView = Backbone.View.extend({
el: '#lens-navigation',
el: '#sidebar',
// Renders the view's template to the UI
render: function() {
var self = this;
self.$el.append('<h2>Navigation Section for ' +
self.model.get('courseId') + '</h2>');
// Maintains chainability
return this;
}
......
/* ========================================================================
* Bootstrap: affix.js v3.1.1
* http://getbootstrap.com/javascript/#affix
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// AFFIX CLASS DEFINITION
// ======================
var Affix = function (element, options) {
this.options = $.extend({}, Affix.DEFAULTS, options)
this.$window = $(window)
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
this.$element = $(element)
this.affixed =
this.unpin =
this.pinnedOffset = null
this.checkPosition()
}
Affix.RESET = 'affix affix-top affix-bottom'
Affix.DEFAULTS = {
offset: 0
}
Affix.prototype.getPinnedOffset = function () {
if (this.pinnedOffset) return this.pinnedOffset
this.$element.removeClass(Affix.RESET).addClass('affix')
var scrollTop = this.$window.scrollTop()
var position = this.$element.offset()
return (this.pinnedOffset = position.top - scrollTop)
}
Affix.prototype.checkPositionWithEventLoop = function () {
setTimeout($.proxy(this.checkPosition, this), 1)
}
Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return
var scrollHeight = $(document).height()
var scrollTop = this.$window.scrollTop()
var position = this.$element.offset()
var offset = this.options.offset
var offsetTop = offset.top
var offsetBottom = offset.bottom
if (this.affixed == 'top') position.top += scrollTop
if (typeof offset != 'object') offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
if (this.affixed === affix) return
if (this.unpin) this.$element.css('top', '')
var affixType = 'affix' + (affix ? '-' + affix : '')
var e = $.Event(affixType + '.bs.affix')
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
this.affixed = affix
this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
this.$element
.removeClass(Affix.RESET)
.addClass(affixType)
.trigger($.Event(affixType.replace('affix', 'affixed')))
if (affix == 'bottom') {
this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() })
}
}
// AFFIX PLUGIN DEFINITION
// =======================
var old = $.fn.affix
$.fn.affix = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.affix')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.affix.Constructor = Affix
// AFFIX NO CONFLICT
// =================
$.fn.affix.noConflict = function () {
$.fn.affix = old
return this
}
// AFFIX DATA-API
// ==============
$(window).on('load', function () {
$('[data-spy="affix"]').each(function () {
var $spy = $(this)
var data = $spy.data()
data.offset = data.offset || {}
if (data.offsetBottom) data.offset.bottom = data.offsetBottom
if (data.offsetTop) data.offset.top = data.offsetTop
$spy.affix(data)
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: alert.js v3.1.1
* http://getbootstrap.com/javascript/#alerts
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// ALERT CLASS DEFINITION
// ======================
var dismiss = '[data-dismiss="alert"]'
var Alert = function (el) {
$(el).on('click', dismiss, this.close)
}
Alert.prototype.close = function (e) {
var $this = $(this)
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = $(selector)
if (e) e.preventDefault()
if (!$parent.length) {
$parent = $this.hasClass('alert') ? $this : $this.parent()
}
$parent.trigger(e = $.Event('close.bs.alert'))
if (e.isDefaultPrevented()) return
$parent.removeClass('in')
function removeElement() {
$parent.trigger('closed.bs.alert').remove()
}
$.support.transition && $parent.hasClass('fade') ?
$parent
.one($.support.transition.end, removeElement)
.emulateTransitionEnd(150) :
removeElement()
}
// ALERT PLUGIN DEFINITION
// =======================
var old = $.fn.alert
$.fn.alert = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.alert')
if (!data) $this.data('bs.alert', (data = new Alert(this)))
if (typeof option == 'string') data[option].call($this)
})
}
$.fn.alert.Constructor = Alert
// ALERT NO CONFLICT
// =================
$.fn.alert.noConflict = function () {
$.fn.alert = old
return this
}
// ALERT DATA-API
// ==============
$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
}(jQuery);
/* ========================================================================
* Bootstrap: button.js v3.1.1
* http://getbootstrap.com/javascript/#buttons
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// BUTTON PUBLIC CLASS DEFINITION
// ==============================
var Button = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Button.DEFAULTS, options)
this.isLoading = false
}
Button.DEFAULTS = {
loadingText: 'loading...'
}
Button.prototype.setState = function (state) {
var d = 'disabled'
var $el = this.$element
var val = $el.is('input') ? 'val' : 'html'
var data = $el.data()
state = state + 'Text'
if (!data.resetText) $el.data('resetText', $el[val]())
$el[val](data[state] || this.options[state])
// push to event loop to allow forms to submit
setTimeout($.proxy(function () {
if (state == 'loadingText') {
this.isLoading = true
$el.addClass(d).attr(d, d)
} else if (this.isLoading) {
this.isLoading = false
$el.removeClass(d).removeAttr(d)
}
}, this), 0)
}
Button.prototype.toggle = function () {
var changed = true
var $parent = this.$element.closest('[data-toggle="buttons"]')
if ($parent.length) {
var $input = this.$element.find('input')
if ($input.prop('type') == 'radio') {
if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
else $parent.find('.active').removeClass('active')
}
if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
}
if (changed) this.$element.toggleClass('active')
}
// BUTTON PLUGIN DEFINITION
// ========================
var old = $.fn.button
$.fn.button = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.button')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.button', (data = new Button(this, options)))
if (option == 'toggle') data.toggle()
else if (option) data.setState(option)
})
}
$.fn.button.Constructor = Button
// BUTTON NO CONFLICT
// ==================
$.fn.button.noConflict = function () {
$.fn.button = old
return this
}
// BUTTON DATA-API
// ===============
$(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
var $btn = $(e.target)
if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
$btn.button('toggle')
e.preventDefault()
})
}(jQuery);
/* ========================================================================
* Bootstrap: carousel.js v3.1.1
* http://getbootstrap.com/javascript/#carousel
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CAROUSEL CLASS DEFINITION
// =========================
var Carousel = function (element, options) {
this.$element = $(element)
this.$indicators = this.$element.find('.carousel-indicators')
this.options = options
this.paused =
this.sliding =
this.interval =
this.$active =
this.$items = null
this.options.pause == 'hover' && this.$element
.on('mouseenter', $.proxy(this.pause, this))
.on('mouseleave', $.proxy(this.cycle, this))
}
Carousel.DEFAULTS = {
interval: 5000,
pause: 'hover',
wrap: true
}
Carousel.prototype.cycle = function (e) {
e || (this.paused = false)
this.interval && clearInterval(this.interval)
this.options.interval
&& !this.paused
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
return this
}
Carousel.prototype.getActiveIndex = function () {
this.$active = this.$element.find('.item.active')
this.$items = this.$active.parent().children()
return this.$items.index(this.$active)
}
Carousel.prototype.to = function (pos) {
var that = this
var activeIndex = this.getActiveIndex()
if (pos > (this.$items.length - 1) || pos < 0) return
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) })
if (activeIndex == pos) return this.pause().cycle()
return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
}
Carousel.prototype.pause = function (e) {
e || (this.paused = true)
if (this.$element.find('.next, .prev').length && $.support.transition) {
this.$element.trigger($.support.transition.end)
this.cycle(true)
}
this.interval = clearInterval(this.interval)
return this
}
Carousel.prototype.next = function () {
if (this.sliding) return
return this.slide('next')
}
Carousel.prototype.prev = function () {
if (this.sliding) return
return this.slide('prev')
}
Carousel.prototype.slide = function (type, next) {
var $active = this.$element.find('.item.active')
var $next = next || $active[type]()
var isCycling = this.interval
var direction = type == 'next' ? 'left' : 'right'
var fallback = type == 'next' ? 'first' : 'last'
var that = this
if (!$next.length) {
if (!this.options.wrap) return
$next = this.$element.find('.item')[fallback]()
}
if ($next.hasClass('active')) return this.sliding = false
var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
this.sliding = true
isCycling && this.pause()
if (this.$indicators.length) {
this.$indicators.find('.active').removeClass('active')
this.$element.one('slid.bs.carousel', function () {
var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
$nextIndicator && $nextIndicator.addClass('active')
})
}
if ($.support.transition && this.$element.hasClass('slide')) {
$next.addClass(type)
$next[0].offsetWidth // force reflow
$active.addClass(direction)
$next.addClass(direction)
$active
.one($.support.transition.end, function () {
$next.removeClass([type, direction].join(' ')).addClass('active')
$active.removeClass(['active', direction].join(' '))
that.sliding = false
setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0)
})
.emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
} else {
$active.removeClass('active')
$next.addClass('active')
this.sliding = false
this.$element.trigger('slid.bs.carousel')
}
isCycling && this.cycle()
return this
}
// CAROUSEL PLUGIN DEFINITION
// ==========================
var old = $.fn.carousel
$.fn.carousel = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.carousel')
var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
var action = typeof option == 'string' ? option : options.slide
if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
if (typeof option == 'number') data.to(option)
else if (action) data[action]()
else if (options.interval) data.pause().cycle()
})
}
$.fn.carousel.Constructor = Carousel
// CAROUSEL NO CONFLICT
// ====================
$.fn.carousel.noConflict = function () {
$.fn.carousel = old
return this
}
// CAROUSEL DATA-API
// =================
$(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
var $this = $(this), href
var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
var options = $.extend({}, $target.data(), $this.data())
var slideIndex = $this.attr('data-slide-to')
if (slideIndex) options.interval = false
$target.carousel(options)
if (slideIndex = $this.attr('data-slide-to')) {
$target.data('bs.carousel').to(slideIndex)
}
e.preventDefault()
})
$(window).on('load', function () {
$('[data-ride="carousel"]').each(function () {
var $carousel = $(this)
$carousel.carousel($carousel.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: collapse.js v3.1.1
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// COLLAPSE PUBLIC CLASS DEFINITION
// ================================
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
this.transitioning = null
if (this.options.parent) this.$parent = $(this.options.parent)
if (this.options.toggle) this.toggle()
}
Collapse.DEFAULTS = {
toggle: true
}
Collapse.prototype.dimension = function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
Collapse.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('in')) return
var startEvent = $.Event('show.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var actives = this.$parent && this.$parent.find('> .panel > .in')
if (actives && actives.length) {
var hasData = actives.data('bs.collapse')
if (hasData && hasData.transitioning) return
actives.collapse('hide')
hasData || actives.data('bs.collapse', null)
}
var dimension = this.dimension()
this.$element
.removeClass('collapse')
.addClass('collapsing')
[dimension](0)
this.transitioning = 1
var complete = function () {
this.$element
.removeClass('collapsing')
.addClass('collapse in')
[dimension]('auto')
this.transitioning = 0
this.$element.trigger('shown.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
var scrollSize = $.camelCase(['scroll', dimension].join('-'))
this.$element
.one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(350)
[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
if (this.transitioning || !this.$element.hasClass('in')) return
var startEvent = $.Event('hide.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var dimension = this.dimension()
this.$element
[dimension](this.$element[dimension]())
[0].offsetHeight
this.$element
.addClass('collapsing')
.removeClass('collapse')
.removeClass('in')
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
.trigger('hidden.bs.collapse')
.removeClass('collapsing')
.addClass('collapse')
}
if (!$.support.transition) return complete.call(this)
this.$element
[dimension](0)
.one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(350)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
// COLLAPSE PLUGIN DEFINITION
// ==========================
var old = $.fn.collapse
$.fn.collapse = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data && options.toggle && option == 'show') option = !option
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.collapse.Constructor = Collapse
// COLLAPSE NO CONFLICT
// ====================
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
// COLLAPSE DATA-API
// =================
$(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
var $this = $(this), href
var target = $this.attr('data-target')
|| e.preventDefault()
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
var $target = $(target)
var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $this.data()
var parent = $this.attr('data-parent')
var $parent = parent && $(parent)
if (!data || !data.transitioning) {
if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
}
$target.collapse(option)
})
}(jQuery);
/* ========================================================================
* Bootstrap: dropdown.js v3.1.1
* http://getbootstrap.com/javascript/#dropdowns
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// DROPDOWN CLASS DEFINITION
// =========================
var backdrop = '.dropdown-backdrop'
var toggle = '[data-toggle=dropdown]'
var Dropdown = function (element) {
$(element).on('click.bs.dropdown', this.toggle)
}
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
clearMenus()
if (!isActive) {
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
// if mobile we use a backdrop because click events don't delegate
$('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
}
var relatedTarget = { relatedTarget: this }
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$parent
.toggleClass('open')
.trigger('shown.bs.dropdown', relatedTarget)
$this.focus()
}
return false
}
Dropdown.prototype.keydown = function (e) {
if (!/(38|40|27)/.test(e.keyCode)) return
var $this = $(this)
e.preventDefault()
e.stopPropagation()
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
if (!isActive || (isActive && e.keyCode == 27)) {
if (e.which == 27) $parent.find(toggle).focus()
return $this.click()
}
var desc = ' li:not(.divider):visible a'
var $items = $parent.find('[role=menu]' + desc + ', [role=listbox]' + desc)
if (!$items.length) return
var index = $items.index($items.filter(':focus'))
if (e.keyCode == 38 && index > 0) index-- // up
if (e.keyCode == 40 && index < $items.length - 1) index++ // down
if (!~index) index = 0
$items.eq(index).focus()
}
function clearMenus(e) {
$(backdrop).remove()
$(toggle).each(function () {
var $parent = getParent($(this))
var relatedTarget = { relatedTarget: this }
if (!$parent.hasClass('open')) return
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
})
}
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
}
var $parent = selector && $(selector)
return $parent && $parent.length ? $parent : $this.parent()
}
// DROPDOWN PLUGIN DEFINITION
// ==========================
var old = $.fn.dropdown
$.fn.dropdown = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.dropdown')
if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
if (typeof option == 'string') data[option].call($this)
})
}
$.fn.dropdown.Constructor = Dropdown
// DROPDOWN NO CONFLICT
// ====================
$.fn.dropdown.noConflict = function () {
$.fn.dropdown = old
return this
}
// APPLY TO STANDARD DROPDOWN ELEMENTS
// ===================================
$(document)
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown)
}(jQuery);
/* ========================================================================
* Bootstrap: modal.js v3.1.1
* http://getbootstrap.com/javascript/#modals
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// MODAL CLASS DEFINITION
// ======================
var Modal = function (element, options) {
this.options = options
this.$element = $(element)
this.$backdrop =
this.isShown = null
if (this.options.remote) {
this.$element
.find('.modal-content')
.load(this.options.remote, $.proxy(function () {
this.$element.trigger('loaded.bs.modal')
}, this))
}
}
Modal.DEFAULTS = {
backdrop: true,
keyboard: true,
show: true
}
Modal.prototype.toggle = function (_relatedTarget) {
return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
}
Modal.prototype.show = function (_relatedTarget) {
var that = this
var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
this.$element.trigger(e)
if (this.isShown || e.isDefaultPrevented()) return
this.isShown = true
this.escape()
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade')
if (!that.$element.parent().length) {
that.$element.appendTo(document.body) // don't move modals dom position
}
that.$element
.show()
.scrollTop(0)
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element
.addClass('in')
.attr('aria-hidden', false)
that.enforceFocus()
var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
transition ?
that.$element.find('.modal-dialog') // wait for modal to slide in
.one($.support.transition.end, function () {
that.$element.focus().trigger(e)
})
.emulateTransitionEnd(300) :
that.$element.focus().trigger(e)
})
}
Modal.prototype.hide = function (e) {
if (e) e.preventDefault()
e = $.Event('hide.bs.modal')
this.$element.trigger(e)
if (!this.isShown || e.isDefaultPrevented()) return
this.isShown = false
this.escape()
$(document).off('focusin.bs.modal')
this.$element
.removeClass('in')
.attr('aria-hidden', true)
.off('click.dismiss.bs.modal')
$.support.transition && this.$element.hasClass('fade') ?
this.$element
.one($.support.transition.end, $.proxy(this.hideModal, this))
.emulateTransitionEnd(300) :
this.hideModal()
}
Modal.prototype.enforceFocus = function () {
$(document)
.off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) {
if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
this.$element.focus()
}
}, this))
}
Modal.prototype.escape = function () {
if (this.isShown && this.options.keyboard) {
this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
e.which == 27 && this.hide()
}, this))
} else if (!this.isShown) {
this.$element.off('keyup.dismiss.bs.modal')
}
}
Modal.prototype.hideModal = function () {
var that = this
this.$element.hide()
this.backdrop(function () {
that.removeBackdrop()
that.$element.trigger('hidden.bs.modal')
})
}
Modal.prototype.removeBackdrop = function () {
this.$backdrop && this.$backdrop.remove()
this.$backdrop = null
}
Modal.prototype.backdrop = function (callback) {
var animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
.appendTo(document.body)
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (e.target !== e.currentTarget) return
this.options.backdrop == 'static'
? this.$element[0].focus.call(this.$element[0])
: this.hide.call(this)
}, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
if (!callback) return
doAnimate ?
this.$backdrop
.one($.support.transition.end, callback)
.emulateTransitionEnd(150) :
callback()
} else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in')
$.support.transition && this.$element.hasClass('fade') ?
this.$backdrop
.one($.support.transition.end, callback)
.emulateTransitionEnd(150) :
callback()
} else if (callback) {
callback()
}
}
// MODAL PLUGIN DEFINITION
// =======================
var old = $.fn.modal
$.fn.modal = function (option, _relatedTarget) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.modal')
var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
if (typeof option == 'string') data[option](_relatedTarget)
else if (options.show) data.show(_relatedTarget)
})
}
$.fn.modal.Constructor = Modal
// MODAL NO CONFLICT
// =================
$.fn.modal.noConflict = function () {
$.fn.modal = old
return this
}
// MODAL DATA-API
// ==============
$(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
var $this = $(this)
var href = $this.attr('href')
var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
if ($this.is('a')) e.preventDefault()
$target
.modal(option, this)
.one('hide', function () {
$this.is(':visible') && $this.focus()
})
})
$(document)
.on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
.on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
}(jQuery);
/* ========================================================================
* Bootstrap: popover.js v3.1.1
* http://getbootstrap.com/javascript/#popovers
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// POPOVER PUBLIC CLASS DEFINITION
// ===============================
var Popover = function (element, options) {
this.init('popover', element, options)
}
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right',
trigger: 'click',
content: '',
template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
})
// NOTE: POPOVER EXTENDS tooltip.js
// ================================
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
Popover.prototype.constructor = Popover
Popover.prototype.getDefaults = function () {
return Popover.DEFAULTS
}
Popover.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
var content = this.getContent()
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
$tip.find('.popover-content')[ // we use append for html objects to maintain js events
this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
](content)
$tip.removeClass('fade top bottom left right in')
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
// this manually by checking the contents.
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
}
Popover.prototype.hasContent = function () {
return this.getTitle() || this.getContent()
}
Popover.prototype.getContent = function () {
var $e = this.$element
var o = this.options
return $e.attr('data-content')
|| (typeof o.content == 'function' ?
o.content.call($e[0]) :
o.content)
}
Popover.prototype.arrow = function () {
return this.$arrow = this.$arrow || this.tip().find('.arrow')
}
Popover.prototype.tip = function () {
if (!this.$tip) this.$tip = $(this.options.template)
return this.$tip
}
// POPOVER PLUGIN DEFINITION
// =========================
var old = $.fn.popover
$.fn.popover = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.popover')
var options = typeof option == 'object' && option
if (!data && option == 'destroy') return
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.popover.Constructor = Popover
// POPOVER NO CONFLICT
// ===================
$.fn.popover.noConflict = function () {
$.fn.popover = old
return this
}
}(jQuery);
/* ========================================================================
* Bootstrap: scrollspy.js v3.1.1
* http://getbootstrap.com/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// SCROLLSPY CLASS DEFINITION
// ==========================
function ScrollSpy(element, options) {
var href
var process = $.proxy(this.process, this)
this.$element = $(element).is('body') ? $(window) : $(element)
this.$body = $('body')
this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
this.selector = (this.options.target
|| ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|| '') + ' .nav li > a'
this.offsets = $([])
this.targets = $([])
this.activeTarget = null
this.refresh()
this.process()
}
ScrollSpy.DEFAULTS = {
offset: 10
}
ScrollSpy.prototype.refresh = function () {
var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
this.offsets = $([])
this.targets = $([])
var self = this
var $targets = this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
var href = $el.data('target') || $el.attr('href')
var $href = /^#./.test(href) && $(href)
return ($href
&& $href.length
&& $href.is(':visible')
&& [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
self.offsets.push(this[0])
self.targets.push(this[1])
})
}
ScrollSpy.prototype.process = function () {
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
var maxScroll = scrollHeight - this.$scrollElement.height()
var offsets = this.offsets
var targets = this.targets
var activeTarget = this.activeTarget
var i
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets.last()[0]) && this.activate(i)
}
if (activeTarget && scrollTop <= offsets[0]) {
return activeTarget != (i = targets[0]) && this.activate(i)
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
&& this.activate( targets[i] )
}
}
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
$(this.selector)
.parentsUntil(this.options.target, '.active')
.removeClass('active')
var selector = this.selector +
'[data-target="' + target + '"],' +
this.selector + '[href="' + target + '"]'
var active = $(selector)
.parents('li')
.addClass('active')
if (active.parent('.dropdown-menu').length) {
active = active
.closest('li.dropdown')
.addClass('active')
}
active.trigger('activate.bs.scrollspy')
}
// SCROLLSPY PLUGIN DEFINITION
// ===========================
var old = $.fn.scrollspy
$.fn.scrollspy = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.scrollspy.Constructor = ScrollSpy
// SCROLLSPY NO CONFLICT
// =====================
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
// SCROLLSPY DATA-API
// ==================
$(window).on('load', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
$spy.scrollspy($spy.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: tab.js v3.1.1
* http://getbootstrap.com/javascript/#tabs
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// TAB CLASS DEFINITION
// ====================
var Tab = function (element) {
this.element = $(element)
}
Tab.prototype.show = function () {
var $this = this.element
var $ul = $this.closest('ul:not(.dropdown-menu)')
var selector = $this.data('target')
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
}
if ($this.parent('li').hasClass('active')) return
var previous = $ul.find('.active:last a')[0]
var e = $.Event('show.bs.tab', {
relatedTarget: previous
})
$this.trigger(e)
if (e.isDefaultPrevented()) return
var $target = $(selector)
this.activate($this.parent('li'), $ul)
this.activate($target, $target.parent(), function () {
$this.trigger({
type: 'shown.bs.tab',
relatedTarget: previous
})
})
}
Tab.prototype.activate = function (element, container, callback) {
var $active = container.find('> .active')
var transition = callback
&& $.support.transition
&& $active.hasClass('fade')
function next() {
$active
.removeClass('active')
.find('> .dropdown-menu > .active')
.removeClass('active')
element.addClass('active')
if (transition) {
element[0].offsetWidth // reflow for transition
element.addClass('in')
} else {
element.removeClass('fade')
}
if (element.parent('.dropdown-menu')) {
element.closest('li.dropdown').addClass('active')
}
callback && callback()
}
transition ?
$active
.one($.support.transition.end, next)
.emulateTransitionEnd(150) :
next()
$active.removeClass('in')
}
// TAB PLUGIN DEFINITION
// =====================
var old = $.fn.tab
$.fn.tab = function ( option ) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tab')
if (!data) $this.data('bs.tab', (data = new Tab(this)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tab.Constructor = Tab
// TAB NO CONFLICT
// ===============
$.fn.tab.noConflict = function () {
$.fn.tab = old
return this
}
// TAB DATA-API
// ============
$(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
e.preventDefault()
$(this).tab('show')
})
}(jQuery);
/* ========================================================================
* Bootstrap: transition.js v3.1.1
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd otransitionend',
'transition' : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false, $el = this
$(this).one($.support.transition.end, function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
$(function () {
$.support.transition = transitionEnd()
})
}(jQuery);
......@@ -9,11 +9,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}edX Analytics Dashboard{% endblock title %}</title>
<title>{% block title %}{{ page_title }} - {{ course_number }} {{ course_title }}| edX Analytics{% endblock title %}</title>
<meta name="description" content="">
<meta name="author" content="">
{% comment %}
The stylesheets can be either overriden or augmented here. Make sure to use the block.super if you're
adding additional stylesheets in your page when extending the base.
......@@ -32,15 +32,31 @@
</head>
<body class="{% block view-name %}{% endblock view-name %}">
<body class="{% block view-name %}{% endblock view-name %}" >
{% block header %}
{% include "header.html" %}
{% endblock header %}
<div id='lens-navigation'></div>
{% block lens_navigation %}
{% include "lens-navigation.html" %}
{% endblock lens_navigation %}
<div class="row">
<main class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main" id="content" data-analytics-init='{{ page_data | safe }}'>
<div class="view-head">
<h1>{{ page_title }}</h1>
</div>
{% block content %}
{% endblock content %}
<div class="view-intro">
<p class="lead text-muted">
{% block intro-text %}{% endblock intro-text %}
</p>
</div>
{% block content %}
{% endblock content %}
</main>
</div>
{% block footer %}
{% include "footer.html" %}
......@@ -53,7 +69,8 @@
{% endcomment %}
{% compress js %}
{% block javascript %}
{% endblock %}
<script data-main="{% static 'js/course-analytics.js' %}" src="{% static 'vendor/require.js' %}"></script>
{% endblock javascript %}
{% endcompress %}
</body>
</html>
\ No newline at end of file
{% comment %}
Partial: Individual course centric navigation
{% endcomment %}
<!-- TODO: abstract course-based navigation to here -->
{% extends "base.html" %}
{% comment %}
Individual course centric overview view
Partial: App-wide header element
{% endcomment %}
{% block view-name %}view-course-overview view-dashboard{% endblock view-name %}
{% block title %}{{ course_number }} {{ course_title }}| edX Analytics{% endblock title %}
{% block nav-skip %}
<div class="sr-only">
<h2>Skip to Parts of this Page</h2>
<ul>
<li><a href="#nav">Main Navigation</a></li>
<li><a href="#content">Main Content</a></li>
<li><a href="#sidebar">Side Content + Navigation</a></li>
</ul>
</div>
{% endblock nav-skip %}
{% block content %}
<div class="row">
<aside id="sidebar" class="col-sm-3 col-md-2 sidebar">
<div class="sidebar-group">
<!-- TODO: abstract this out into one view with .active logic -->
<ul class="nav nav-stacked">
<li class="active">
<a href="#">
<li
{% if page_title == "Overview" %}
class = "active">
{% endif %}
>
<a href="../overview">
<span class="link-label"><i class="ico fa fa-tachometer"></i> Overview</span>
<i class="link-ico fa fa-angle-right hidden-xs"></i>
</a>
</li>
<li>
<a href="#">
<li
{% if page_title == "Enrollment" %}
class = "active">
{% endif %}
>
<a href="../enrollment">
<span class="link-label"><i class="ico fa fa-child"></i> Enrollment</span>
<i class="link-ico fa fa-angle-right hidden-xs"></i>
</a>
</li>
<li>
<a href="#">
<li
{% if page_title == "Engagement" %}
class = "active">
{% endif %}
>
<a href="../engagement">
<span class="link-label"><i class="ico fa fa-tasks"></i> Engagement</span>
<i class="link-ico fa fa-angle-right hidden-xs"></i>
</a>
</li>
<li>
<a href="#">
<li
{% if page_title == "Performance" %}
class = "active">
{% endif %}
>
<a href="../performance">
<span class="link-label"><i class="ico fa fa-bar-chart-o"></i> Performance</span>
<i class="link-ico fa fa-angle-right hidden-xs"></i>
</a>
......@@ -63,20 +62,4 @@ Individual course centric overview view
</ul>
</div>
</aside>
<!-- / col -->
<main class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main" id="content">
<div class="view-head">
<h1>Overview</h1>
</div>
<div class="view-intro">
<p class="lead text-muted">
[Intro summary area for Overview if needed] Curabitur blandit tempus porttitor. Etiam porta sem malesuada magna mollis euismod. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.
</p>
</div>
</main>
<!-- / col -->
</div>
<!-- / row -->
{% endblock content %}
</div>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment