Merge branch 'master' of github.com:MITx/mitx into merge
@@ -90,6 +90,16 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
################################# Jasmine ###################################
|
||||
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
|
||||
|
||||
|
||||
#################### CAPA External Code Evaluation #############################
|
||||
XQUEUE_INTERFACE = {
|
||||
'url': 'http://localhost:8888',
|
||||
'django_auth': {'username': 'local',
|
||||
'password': 'local'},
|
||||
'basic_auth': None,
|
||||
}
|
||||
|
||||
|
||||
################################# Middleware ###################################
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
|
||||
@@ -7,13 +7,10 @@ import logging
|
||||
import requests
|
||||
import time
|
||||
|
||||
# TODO: Collection of parameters to be hooked into rest of edX system
|
||||
XQUEUE_LMS_AUTH = { 'username': 'LMS',
|
||||
'password': 'PaloAltoCA' }
|
||||
XQUEUE_URL = 'http://xqueue.edx.org'
|
||||
|
||||
log = logging.getLogger('mitx.' + __name__)
|
||||
|
||||
|
||||
def make_hashkey(seed=None):
|
||||
'''
|
||||
Generate a string key by hashing
|
||||
@@ -58,15 +55,15 @@ def parse_xreply(xreply):
|
||||
return (return_code, content)
|
||||
|
||||
|
||||
class XqueueInterface:
|
||||
class XQueueInterface(object):
|
||||
'''
|
||||
Interface to the external grading system
|
||||
'''
|
||||
|
||||
def __init__(self, url=XQUEUE_URL, auth=XQUEUE_LMS_AUTH):
|
||||
def __init__(self, url, django_auth, requests_auth=None):
|
||||
self.url = url
|
||||
self.auth = auth
|
||||
self.session = requests.session()
|
||||
self.auth = django_auth
|
||||
self.session = requests.session(auth=requests_auth)
|
||||
|
||||
def send_to_queue(self, header, body, file_to_upload=None):
|
||||
'''
|
||||
@@ -117,5 +114,3 @@ class XqueueInterface:
|
||||
return (1, 'unexpected HTTP status code [%d]' % r.status_code)
|
||||
|
||||
return parse_xreply(r.text)
|
||||
|
||||
qinterface = XqueueInterface()
|
||||
|
||||
BIN
lms/askbot/skins/mitx/media/images/email-sharing.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
lms/askbot/skins/mitx/media/images/facebook-sharing.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
lms/askbot/skins/mitx/media/images/google-plus-sharing.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
lms/askbot/skins/mitx/media/images/lrg/email-sharing.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
lms/askbot/skins/mitx/media/images/lrg/facebook-sharing.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
lms/askbot/skins/mitx/media/images/lrg/facebook.png
Normal file
|
After Width: | Height: | Size: 205 B |
BIN
lms/askbot/skins/mitx/media/images/lrg/google-plus-sharing.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
lms/askbot/skins/mitx/media/images/lrg/linkedin.png
Normal file
|
After Width: | Height: | Size: 229 B |
BIN
lms/askbot/skins/mitx/media/images/lrg/twitter-sharing.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
lms/askbot/skins/mitx/media/images/lrg/twitter.png
Normal file
|
After Width: | Height: | Size: 235 B |
BIN
lms/askbot/skins/mitx/media/images/lrg/youtube-sharing.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
lms/askbot/skins/mitx/media/images/social/email-sharing.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
lms/askbot/skins/mitx/media/images/social/facebook-sharing.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
BIN
lms/askbot/skins/mitx/media/images/social/twitter-sharing.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
lms/askbot/skins/mitx/media/images/social/youtube-sharing.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
lms/askbot/skins/mitx/media/images/twitter-sharing.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
lms/askbot/skins/mitx/media/images/youtube-sharing.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@@ -3,7 +3,7 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
{% spaceless %}
|
||||
<head>
|
||||
<title>{% block title %}{% endblock %} - MITX 6.002</title>
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
{% include "meta/html_head_meta.html" %}
|
||||
<link rel="shortcut icon" href="{{ settings.SITE_FAVICON|media }}" />
|
||||
{% include "meta/html_head_stylesheets.html" %}
|
||||
|
||||
@@ -33,8 +33,14 @@
|
||||
<!-- Quick fix -- we should reference askbot jquery properly -->
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ settings.STATIC_URL }}/js/askbot_jquery.min.js"
|
||||
src="{{'/js/jquery-1.4.3.js'|media}}"
|
||||
></script>
|
||||
{#
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ settings.STATIC_ROOT }}/js/askbot_jquery.min.js"
|
||||
></script>
|
||||
#}
|
||||
<!-- History.js -->
|
||||
<script type='text/javascript' src="{{"/js/jquery.history.js"|media }}"></script>
|
||||
<script type='text/javascript' src="{{"/js/utils.js"|media }}"></script>
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
<header class="global" aria-label="Global Navigation">
|
||||
<nav>
|
||||
<h1 class="logo"><a href="${reverse('root')}"></a></h1>
|
||||
<h1 class="logo"><a href="{% url root %}"></a></h1>
|
||||
<ol class="left">
|
||||
<li class="primary">
|
||||
<a href="${reverse('courses')}">Find Courses</a>
|
||||
<a href="{% url courses %}">Find Courses</a>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<ol class="user">
|
||||
<li class="primary">
|
||||
<a href="${reverse('dashboard')}" class="user-link">
|
||||
<a href="{% url dashboard %}" class="user-link">
|
||||
<span class="avatar"></span>
|
||||
${user.username}
|
||||
{{user.username}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="primary">
|
||||
<a href="#" class="dropdown">▾</a>
|
||||
<ul class="dropdown-menu">
|
||||
## <li><a href="#">Account Settings</a></li>
|
||||
<li><a href="${reverse('help_edx')}">Help</a></li>
|
||||
<li><a href="${reverse('logout')}">Log Out</a></li>
|
||||
{# <li><a href="#">Account Settings</a></li> #}
|
||||
<li><a href="{% url help_edx %}">Help</a></li>
|
||||
<li><a href="{% url logout %}">Log Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
<nav>
|
||||
<section class="top">
|
||||
<section class="primary">
|
||||
<a href="${reverse('root')}" class="logo"></a>
|
||||
<a href="${reverse('courses')}">Find Courses</a>
|
||||
<a href="${reverse('about_edx')}">About</a>
|
||||
<a href="{% url root %}" class="logo"></a>
|
||||
<a href="{% url courses %}">Find Courses</a>
|
||||
<a href="{% url about_edx %}">About</a>
|
||||
<a href="http://edxonline.tumblr.com/">Blog</a>
|
||||
<a href="${reverse('jobs')}">Jobs</a>
|
||||
<a href="${reverse('contact')}">Contact</a>
|
||||
<a href="{% url jobs %}">Jobs</a>
|
||||
<a href="{% url contact %}">Contact</a>
|
||||
</section>
|
||||
|
||||
<section class="social">
|
||||
<a href="http://youtube.com/user/edxonline"><img src="${static.url('images/social/youtube-sharing.png')}" /></a>
|
||||
<a href="https://plus.google.com/108235383044095082735"><img src="${static.url('images/social/google-plus-sharing.png')}" /></a>
|
||||
<a href="http://www.facebook.com/EdxOnline"><img src="${static.url('images/social/facebook-sharing.png')}" /></a>
|
||||
<a href="https://twitter.com/edXOnline"><img src="${static.url('images/social/twitter-sharing.png')}" /></a>
|
||||
<a href="http://youtube.com/user/edxonline"><img src='{{"images/social/youtube-sharing.png"|media}}' /></a>
|
||||
<a href="https://plus.google.com/108235383044095082735"><img src="{{('images/social/google-plus-sharing.png'|media)}}" /></a>
|
||||
<a href="http://www.facebook.com/EdxOnline"><img src="{{'images/social/facebook-sharing.png'|media}}" /></a>
|
||||
<a href="https://twitter.com/edXOnline"><img src="{{'images/social/twitter-sharing.png'|media}}" /></a>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
</section>
|
||||
|
||||
<section class="secondary">
|
||||
<a href="${reverse('tos')}">Terms of Service</a>
|
||||
<a href="${reverse('privacy_edx')}">Privacy Policy</a>
|
||||
<a href="${reverse('honor')}">Honor Code</a>
|
||||
<a href="${reverse('help_edx')}">Help</a>
|
||||
<a href="{% url tos %}">Terms of Service</a>
|
||||
<a href="{% url privacy_edx %}">Privacy Policy</a>
|
||||
<a href="{% url honor %}">Honor Code</a>
|
||||
<a href="{% url help_edx %}">Help</a>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ from django.http import Http404
|
||||
from django.http import HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from capa.xqueue_interface import XQueueInterface
|
||||
from django.contrib.auth.models import User
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from capa.xqueue_interface import qinterface
|
||||
from mitxmako.shortcuts import render_to_string
|
||||
from models import StudentModule, StudentModuleCache
|
||||
from static_replace import replace_urls
|
||||
@@ -19,10 +19,23 @@ from xmodule_modifiers import replace_static_urls, add_histogram, wrap_xmodule
|
||||
|
||||
from courseware.courses import (has_staff_access_to_course,
|
||||
has_staff_access_to_location)
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
|
||||
if settings.XQUEUE_INTERFACE['basic_auth'] is not None:
|
||||
requests_auth = HTTPBasicAuth(*settings.XQUEUE_INTERFACE['basic_auth'])
|
||||
else:
|
||||
requests_auth = None
|
||||
|
||||
xqueue_interface = XQueueInterface(
|
||||
settings.XQUEUE_INTERFACE['url'],
|
||||
settings.XQUEUE_INTERFACE['django_auth'],
|
||||
requests_auth,
|
||||
)
|
||||
|
||||
|
||||
def make_track_function(request):
|
||||
'''
|
||||
Make a tracking function that logs what happened.
|
||||
@@ -172,9 +185,9 @@ def get_module(user, request, location, student_module_cache, position=None):
|
||||
# TODO: Queuename should be derived from 'course_settings.json' of each course
|
||||
xqueue_default_queuename = descriptor.location.org + '-' + descriptor.location.course
|
||||
|
||||
xqueue = { 'interface': qinterface,
|
||||
'callback_url': xqueue_callback_url,
|
||||
'default_queuename': xqueue_default_queuename.replace(' ','_') }
|
||||
xqueue = {'interface': xqueue_interface,
|
||||
'callback_url': xqueue_callback_url,
|
||||
'default_queuename': xqueue_default_queuename.replace(' ', '_')}
|
||||
|
||||
def _get_module(location):
|
||||
return get_module(user, request, location,
|
||||
|
||||
@@ -54,3 +54,5 @@ AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"]
|
||||
AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"]
|
||||
|
||||
DATABASES = AUTH_TOKENS['DATABASES']
|
||||
|
||||
XQUEUE_INTERFACE = AUTH_TOKENS['XQUEUE_INTERFACE']
|
||||
|
||||
@@ -225,8 +225,7 @@ STATIC_ROOT = ENV_ROOT / "staticfiles"
|
||||
STATICFILES_DIRS = [
|
||||
COMMON_ROOT / "static",
|
||||
PROJECT_ROOT / "static",
|
||||
ASKBOT_ROOT / "askbot" / "skins",
|
||||
|
||||
PROJECT_ROOT / "askbot" / "skins",
|
||||
]
|
||||
if os.path.isdir(DATA_DIR):
|
||||
STATICFILES_DIRS += [
|
||||
|
||||
@@ -53,6 +53,15 @@ CACHES = {
|
||||
}
|
||||
}
|
||||
|
||||
XQUEUE_INTERFACE = {
|
||||
"url": "http://xqueue.sandbox.edx.org",
|
||||
"django_auth": {
|
||||
"username": "lms",
|
||||
"password": "***REMOVED***"
|
||||
},
|
||||
"basic_auth": ('anant', 'agarwal'),
|
||||
}
|
||||
|
||||
# Make the keyedcache startup warnings go away
|
||||
CACHE_TIMEOUT = 0
|
||||
|
||||
|
||||
@@ -41,3 +41,6 @@ def course_db_for(course_id):
|
||||
}
|
||||
}
|
||||
|
||||
def askbot_url_for(course_id):
|
||||
return "courses/{0}/discussions/".format(course_id)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from .courses import *
|
||||
|
||||
DATABASES = course_db_for('HarvardX/CS50x/2012')
|
||||
DATABASES = course_db_for('HarvardX/CS50x/2012')
|
||||
ASKBOT_URL = askbot_url_for("HarvardX/CS50x/2012")
|
||||
@@ -1,3 +1,4 @@
|
||||
from .courses import *
|
||||
|
||||
DATABASES = course_db_for('MITx/6.002x/2012_Fall')
|
||||
DATABASES = course_db_for('MITx/6.002x/2012_Fall')
|
||||
ASKBOT_URL = askbot_url_for("MITx/6.002x/2012_Fall")
|
||||
|
||||
@@ -50,6 +50,16 @@ COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
|
||||
GITHUB_REPO_ROOT = ENV_ROOT / "data"
|
||||
|
||||
|
||||
XQUEUE_INTERFACE = {
|
||||
"url": "http://xqueue.sandbox.edx.org",
|
||||
"django_auth": {
|
||||
"username": "lms",
|
||||
"password": "***REMOVED***"
|
||||
},
|
||||
"basic_auth": ('anant', 'agarwal'),
|
||||
}
|
||||
|
||||
|
||||
# TODO (cpennington): We need to figure out how envs/test.py can inject things
|
||||
# into common.py so that we don't have to repeat this sort of thing
|
||||
STATICFILES_DIRS = [
|
||||
|
||||
BIN
lms/static/images/search-icon.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
76
lms/static/js/jquery.gradebook.js
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
|
||||
|
||||
var Gradebook = function($element) {
|
||||
var _this = this;
|
||||
var $element = $element;
|
||||
var $grades = $element.find('.grades');
|
||||
var $gradeTable = $element.find('.grade-table');
|
||||
var $leftShadow = $('<div class="left-shadow"></div>');
|
||||
var $rightShadow = $('<div class="right-shadow"></div>');
|
||||
var tableHeight = $gradeTable.height();
|
||||
var maxScroll = $gradeTable.width() - $grades.width();
|
||||
var $body = $('body');
|
||||
var mouseOrigin;
|
||||
var tableOrigin;
|
||||
|
||||
var startDrag = function(e) {
|
||||
mouseOrigin = e.pageX;
|
||||
tableOrigin = $gradeTable.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(tableOrigin + offset, -maxScroll, 0);
|
||||
|
||||
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 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 = $gradeTable.width() - $grades.width();
|
||||
var targetLeft = clamp($gradeTable.position().left, -maxScroll, 0);
|
||||
updateHorizontalPosition(targetLeft);
|
||||
setShadows(targetLeft);
|
||||
}
|
||||
|
||||
var updateHorizontalPosition = function(left) {
|
||||
$gradeTable.css({
|
||||
'left': left + 'px'
|
||||
});
|
||||
}
|
||||
|
||||
$leftShadow.css('height', tableHeight + 'px');
|
||||
$rightShadow.css('height', tableHeight + 'px');
|
||||
$grades.append($leftShadow).append($rightShadow);
|
||||
setShadows(0);
|
||||
$grades.css('height', tableHeight);
|
||||
$gradeTable.bind('mousedown', startDrag);
|
||||
$(window).bind('resize', updateWidths);
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
@import 'shared/tooltips';
|
||||
|
||||
// Course base / layout styles
|
||||
@import 'course/layout/courseware_subnav';
|
||||
@import 'course/layout/courseware_header';
|
||||
@import 'course/base/base';
|
||||
@import 'course/base/extends';
|
||||
@import 'module/module-styles.scss';
|
||||
|
||||
@@ -1,11 +1,203 @@
|
||||
$cell-border-color: #e1e1e1;
|
||||
$table-border-color: #c8c8c8;
|
||||
|
||||
div.gradebook-wrapper {
|
||||
@extend .table-wrapper;
|
||||
|
||||
section.gradebook-content {
|
||||
@extend .content;
|
||||
|
||||
.student-search {
|
||||
padding: 0 20px 0 15px;
|
||||
}
|
||||
|
||||
.student-search-field {
|
||||
width: 100%;
|
||||
height: 27px;
|
||||
padding: 0 15px 0 35px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 13px;
|
||||
border: 1px solid $table-border-color;
|
||||
background: url(../images/search-icon.png) no-repeat 9px center #f6f6f6;
|
||||
font-family: $sans-serif;
|
||||
font-size: 11px;
|
||||
@include box-shadow(0 1px 4px rgba(0, 0, 0, .12) inset);
|
||||
outline: none;
|
||||
@include transition(border-color .15s);
|
||||
|
||||
&::-webkit-input-placeholder,
|
||||
&::-moz-input-placeholder {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: #1d9dd9;
|
||||
}
|
||||
}
|
||||
|
||||
.student-table {
|
||||
float: left;
|
||||
// width: 264px;
|
||||
width: 24%;
|
||||
border-radius: 3px 0 0 3px;
|
||||
color: #3c3c3c;
|
||||
|
||||
th {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
tr:first-child td {
|
||||
border-top: 1px solid $table-border-color;
|
||||
border-radius: 5px 0 0 0;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: 1px solid $table-border-color;
|
||||
border-radius: 0 0 0 5px;
|
||||
}
|
||||
|
||||
td {
|
||||
height: 50px;
|
||||
padding-left: 20px;
|
||||
border-bottom: 1px solid $cell-border-color;
|
||||
border-left: 1px solid $table-border-color;
|
||||
background: #f3f3f3;
|
||||
font-size: 13px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
tr:nth-child(odd) td {
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
}
|
||||
|
||||
.grades {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 76%;
|
||||
overflow: hidden;
|
||||
|
||||
.left-shadow,
|
||||
.right-shadow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 9999;
|
||||
width: 20px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.left-shadow {
|
||||
left: 0;
|
||||
background: -webkit-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -webkit-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
.right-shadow {
|
||||
right: 0;
|
||||
background: -webkit-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -webkit-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
.grade-table {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1000px;
|
||||
cursor: move;
|
||||
-webkit-transition: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
td,
|
||||
th {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
thead th {
|
||||
position: relative;
|
||||
height: 50px;
|
||||
background: -webkit-linear-gradient(top, $cell-border-color, #ddd);
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 0 $table-border-color inset, 0 2px 0 rgba(255, 255, 255, .7) inset;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 9999;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, .15));
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-radius: 5px 0 0 0;
|
||||
box-shadow: 1px 1px 0 $table-border-color inset, 1px 2px 0 rgba(255, 255, 255, .7) inset;
|
||||
|
||||
&:before {
|
||||
display: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 3px 0 0;
|
||||
box-shadow: -1px 1px 0 $table-border-color inset, -1px 2px 0 rgba(255, 255, 255, .7) inset;
|
||||
}
|
||||
|
||||
.assignment {
|
||||
margin: 9px 0;
|
||||
}
|
||||
|
||||
.type,
|
||||
.number,
|
||||
.max {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.max {
|
||||
height: 12px;
|
||||
background: -webkit-linear-gradient(top, #c6c6c6, #bababa);
|
||||
font-size: 9px;
|
||||
line-height: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
border-right: 1px solid $table-border-color;
|
||||
}
|
||||
|
||||
tr:first-child td {
|
||||
border-top: 1px solid $table-border-color;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: 1px solid $table-border-color;
|
||||
}
|
||||
|
||||
td {
|
||||
height: 50px;
|
||||
border-bottom: 1px solid $cell-border-color;
|
||||
background: #f3f3f3;
|
||||
font-size: 13px;
|
||||
line-height: 50px;
|
||||
border-left: 1px solid $cell-border-color;
|
||||
}
|
||||
|
||||
tr:nth-child(odd) td {
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
@extend .top-header;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -173,29 +173,3 @@ h1.top-header {
|
||||
@include transition( all, .2s, $ease-in-out-quad);
|
||||
}
|
||||
|
||||
.global {
|
||||
.find-courses-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
line-height: 40px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
text-transform: none;
|
||||
white-space: nowrap;
|
||||
width: 700px;
|
||||
|
||||
.provider {
|
||||
font: inherit;
|
||||
font-weight: bold;
|
||||
color: #6d6d6d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
85
lms/static/sass/course/layout/_courseware_header.scss
Normal file
@@ -0,0 +1,85 @@
|
||||
nav.course-material {
|
||||
@include clearfix;
|
||||
@include box-sizing(border-box);
|
||||
background: #f6f6f6;
|
||||
border-bottom: 1px solid rgb(200,200,200);
|
||||
margin: 0px auto 0px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
|
||||
.inner-wrapper {
|
||||
margin: 0 auto;
|
||||
max-width: 1200px;
|
||||
width: flex-grid(12);
|
||||
}
|
||||
|
||||
ol.course-tabs {
|
||||
@include border-top-radius(4px);
|
||||
@include clearfix;
|
||||
padding: 10px 0 0 0;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
list-style: none;
|
||||
|
||||
a {
|
||||
color: darken($lighter-base-font-color, 20%);
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: 8px 13px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px rgb(255,255,255);
|
||||
|
||||
&:hover {
|
||||
color: $base-font-color;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgb(255,255,255);
|
||||
border: 1px solid rgb(200,200,200);
|
||||
border-bottom: 0px;
|
||||
@include border-top-radius(4px);
|
||||
@include box-shadow(0 2px 0 0 rgba(255,255,255, 1));
|
||||
color: $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.course-content {
|
||||
margin-top: 30px;
|
||||
|
||||
.courseware {
|
||||
min-height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.global {
|
||||
.find-courses-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
display: block;
|
||||
width: 700px;
|
||||
float: left;
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
line-height: 40px;
|
||||
letter-spacing: 0;
|
||||
text-transform: none;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
.provider {
|
||||
font: inherit;
|
||||
font-weight: bold;
|
||||
color: #6d6d6d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script>
|
||||
<script type="text/javascript" src="${static.url('js/jquery.gradebook.js')}"></script>
|
||||
</%block>
|
||||
|
||||
<%block name="headextra">
|
||||
@@ -19,6 +20,12 @@
|
||||
.grade_None {color:LightGray;}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var gradebook = new Gradebook($('.gradebook-content'));
|
||||
});
|
||||
</script>
|
||||
|
||||
</%block>
|
||||
|
||||
<%include file="course_navigation.html" args="active_page=''" />
|
||||
@@ -28,50 +35,75 @@
|
||||
<section class="gradebook-content">
|
||||
<h1>Gradebook</h1>
|
||||
|
||||
%if len(students) > 0:
|
||||
<table>
|
||||
<%
|
||||
templateSummary = students[0]['grade_summary']
|
||||
%>
|
||||
|
||||
|
||||
<tr> <!-- Header Row -->
|
||||
<th>Student</th>
|
||||
%for section in templateSummary['section_breakdown']:
|
||||
<th>${section['label']}</th>
|
||||
<table class="student-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<form class="student-search">
|
||||
<input type="search" class="student-search-field" placeholder="Search students" />
|
||||
</form>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
%for student in students:
|
||||
<tr>
|
||||
<td>
|
||||
<a href="${reverse('student_profile', kwargs=dict(course_id=course_id, student_id=student['id']))}">${student['username']}</a>
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
|
||||
<%def name="percent_data(fraction)">
|
||||
<%
|
||||
letter_grade = 'None'
|
||||
if fraction > 0:
|
||||
letter_grade = 'F'
|
||||
for grade in ['A', 'B', 'C']:
|
||||
if fraction >= course.grade_cutoffs[grade]:
|
||||
letter_grade = grade
|
||||
break
|
||||
|
||||
data_class = "grade_" + letter_grade
|
||||
%>
|
||||
<td class="${data_class}" data-percent="${fraction}">${ "{0:.0f}".format( 100 * fraction ) }</td>
|
||||
</%def>
|
||||
|
||||
%for student in students:
|
||||
<tr>
|
||||
<td><a href="${reverse('student_profile',
|
||||
kwargs=dict(course_id=course_id,
|
||||
student_id=student['id']))}">
|
||||
${student['username']}</a></td>
|
||||
%for section in student['grade_summary']['section_breakdown']:
|
||||
${percent_data( section['percent'] )}
|
||||
%endfor
|
||||
<th>${percent_data( student['grade_summary']['percent'])}</th>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
%if len(students) > 0:
|
||||
<div class="grades">
|
||||
<table class="grade-table">
|
||||
<%
|
||||
templateSummary = students[0]['grade_summary']
|
||||
%>
|
||||
<thead>
|
||||
<tr> <!-- Header Row -->
|
||||
%for section in templateSummary['section_breakdown']:
|
||||
<th>${section['label']}</th>
|
||||
%endfor
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<%def name="percent_data(fraction)">
|
||||
<%
|
||||
letter_grade = 'None'
|
||||
if fraction > 0:
|
||||
letter_grade = 'F'
|
||||
for grade in ['A', 'B', 'C']:
|
||||
if fraction >= course.grade_cutoffs[grade]:
|
||||
letter_grade = grade
|
||||
break
|
||||
|
||||
data_class = "grade_" + letter_grade
|
||||
%>
|
||||
<td class="${data_class}" data-percent="${fraction}">${ "{0:.0f}".format( 100 * fraction ) }</td>
|
||||
</%def>
|
||||
|
||||
<tbody>
|
||||
%for student in students:
|
||||
<tr>
|
||||
%for section in student['grade_summary']['section_breakdown']:
|
||||
${percent_data( section['percent'] )}
|
||||
%endfor
|
||||
<td>${percent_data( student['grade_summary']['percent'])}</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
%endif
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||