Commit 951fb063 by Rocky Duan

Merge branch 'master' of github.com:MITx/mitx into merge

Conflicts:
	lms/envs/dev.py
parents 9b26a209 8b8ee9f4
......@@ -157,7 +157,7 @@ def edXauth_signup(request, eamap=None):
log.debug('ExtAuth: doing signup for %s' % eamap.external_email)
return student_views.main_index(request, extra_context=context)
return student_views.index(request, extra_context=context)
#-----------------------------------------------------------------------------
# MIT SSL
......@@ -193,7 +193,7 @@ def edXauth_ssl_login(request):
The certificate provides user email and fullname; this populates the ExternalAuthMap.
The user is nevertheless still asked to complete the edX signup.
Else continues on with student.views.main_index, and no authentication.
Else continues on with student.views.index, and no authentication.
"""
certkey = "SSL_CLIENT_S_DN" # specify the request.META field to use
......@@ -207,7 +207,7 @@ def edXauth_ssl_login(request):
pass
if not cert:
# no certificate information - go onward to main index
return student_views.main_index(request)
return student_views.index(request)
(user, email, fullname) = ssl_dn_extract_info(cert)
......@@ -217,4 +217,4 @@ def edXauth_ssl_login(request):
credentials=cert,
email=email,
fullname=fullname,
retfun = functools.partial(student_views.main_index, request))
retfun = functools.partial(student_views.index, request))
......@@ -22,7 +22,6 @@ from django.db import IntegrityError
from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string
from django.core.urlresolvers import reverse
from bs4 import BeautifulSoup
from django.core.cache import cache
......@@ -30,7 +29,6 @@ from django_future.csrf import ensure_csrf_cookie
from student.models import (Registration, UserProfile,
PendingNameChange, PendingEmailChange,
CourseEnrollment)
from util.cache import cache_if_anonymous
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.django import modulestore
......@@ -54,23 +52,7 @@ def csrf_token(context):
' name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token))
@ensure_csrf_cookie
@cache_if_anonymous
def index(request):
''' Redirects to main page -- info page if user authenticated, or marketing if not
'''
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
return redirect(reverse('dashboard'))
if settings.MITX_FEATURES.get('AUTH_USE_MIT_CERTIFICATES'):
from external_auth.views import edXauth_ssl_login
return edXauth_ssl_login(request)
return main_index(request, user=request.user)
def main_index(request, extra_context={}, user=None):
def index(request, extra_context={}, user=None):
'''
Render the edX main page.
......
......@@ -9,6 +9,7 @@ from functools import wraps
from django.core import cache
# If we can't find a 'general' CACHE defined in settings.py, we simply fall back
# to returning the default cache. This will happen with dev machines.
try:
......@@ -41,7 +42,10 @@ def cache_if_anonymous(view_func):
def _decorated(request, *args, **kwargs):
if not request.user.is_authenticated():
#Use the cache
cache_key = "cache_if_anonymous." + request.path
# same view accessed through different domain names may
# return different things, so include the domain name in the key.
domain = str(request.META.get('HTTP_HOST')) + '.'
cache_key = domain + "cache_if_anonymous." + request.path
response = cache.get(cache_key)
if not response:
response = view_func(request, *args, **kwargs)
......
......@@ -557,7 +557,7 @@ class ChoiceResponse(LoncapaResponse):
return CorrectMap(self.answer_id, 'incorrect')
def get_answers(self):
return {self.answer_id: self.correct_choices}
return {self.answer_id: list(self.correct_choices)}
#-----------------------------------------------------------------------------
......
......@@ -390,9 +390,19 @@ class CapaModule(XModule):
raise NotFoundError('Answer is not available')
else:
answers = self.lcp.get_question_answers()
# answers (eg <solution>) may have embedded images
answers = dict( (k,self.system.replace_urls(answers[k], self.metadata['data_dir'])) for k in answers )
return {'answers': answers}
# but be careful, some problems are using non-string answer dicts
new_answers = dict()
for answer_id in answers:
try:
new_answer = {answer_id: self.system.replace_urls(answers[answer_id], self.metadata['data_dir'])}
except TypeError:
log.debug('Unable to perform URL substitution on answers[%s]: %s' % (answer_id, answers[answer_id]))
new_answer = {answer_id: answers[answer_id]}
new_answers.update(new_answer)
return {'answers': new_answers}
# Figure out if we should move these to capa_problem?
def get_problem(self, get):
......
......@@ -60,6 +60,8 @@ class CourseDescriptor(SequenceDescriptor):
def __init__(self, system, definition=None, **kwargs):
super(CourseDescriptor, self).__init__(system, definition, **kwargs)
self.textbooks = self.definition['data']['textbooks']
self.wiki_slug = self.definition['data']['wiki_slug'] or self.location.course
msg = None
if self.start is None:
......@@ -94,8 +96,19 @@ class CourseDescriptor(SequenceDescriptor):
for textbook in xml_object.findall("textbook"):
textbooks.append(cls.Textbook.from_xml_object(textbook))
xml_object.remove(textbook)
#Load the wiki tag if it exists
wiki_slug = None
wiki_tag = xml_object.find("wiki")
if wiki_tag is not None:
wiki_slug = wiki_tag.attrib.get("slug", default=None)
xml_object.remove(wiki_tag)
definition = super(CourseDescriptor, cls).definition_from_xml(xml_object, system)
definition.setdefault('data', {})['textbooks'] = textbooks
definition['data']['wiki_slug'] = wiki_slug
return definition
def has_started(self):
......@@ -197,6 +210,19 @@ class CourseDescriptor(SequenceDescriptor):
def start_date_text(self):
return time.strftime("%b %d, %Y", self.start)
# An extra property is used rather than the wiki_slug/number because
# there are courses that change the number for different runs. This allows
# courses to share the same css_class across runs even if they have
# different numbers.
#
# TODO get rid of this as soon as possible or potentially build in a robust
# way to add in course-specific styling. There needs to be a discussion
# about the right way to do this, but arjun will address this ASAP. Also
# note that the courseware template needs to change when this is removed.
@property
def css_class(self):
return self.metadata.get('css_class', '')
@property
def title(self):
return self.display_name
......@@ -206,10 +232,6 @@ class CourseDescriptor(SequenceDescriptor):
return self.location.course
@property
def wiki_slug(self):
return self.location.course
@property
def org(self):
return self.location.org
......@@ -2,18 +2,54 @@ nav.sequence-nav {
// TODO (cpennington): This doesn't work anymore. XModules aren't able to
// import from external sources.
@extend .topbar;
border-bottom: 1px solid $border-color;
@include border-top-right-radius(4px);
margin: 0 0 lh() (-(lh()));
margin: -4px 0 30px;
position: relative;
border-bottom: none;
.left-shadow {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
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;
z-index: 9999;
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: flex-grid(1, 9);
padding: 0 10px;
width: 100%;
a {
......@@ -25,42 +61,44 @@ nav.sequence-nav {
min-width: 20px;
a {
background-position: center;
width: 34px;
height: 34px;
margin: 4px auto;
background-position: center 10px;
background-repeat: no-repeat;
border: 1px solid transparent;
border-bottom: none;
@include border-radius(3px 3px 0 0);
@include border-radius(35px);
cursor: pointer;
display: block;
height: 10px;
padding: 15px 0 14px;
padding: 0;
position: relative;
@include transition();
width: 100%;
&:hover {
background-color: #fff;
background-repeat: no-repeat;
background-position: center;
background-color: #F3F3F3;
}
&.visited {
background-color: #F3F3F3;
&:hover {
background-position: center center;
}
background-position: center 10px;
}
&.active {
border-color: $border-color;
@include box-shadow(0 2px 0 #fff);
background-color: #fff;
z-index: 9;
// &:after {
// content: '▲';
// position: absolute;
// top: 28px;
// left: 50%;
// z-index: 9999;
// margin-left: -5px;
// font-size: 12px;
// color: #aaa;
// }
&:hover {
background-position: center;
background-color: #fff;
background-repeat: no-repeat;
background-position: center 10px;
}
}
......@@ -171,20 +209,24 @@ nav.sequence-nav {
}
ul {
position: absolute;
top: 0;
list-style: none;
height: 100%;
position: absolute;
right: 0;
top: 0;
width: flex-grid(1, 9);
border: 1px solid $border-color;
border-bottom: 0;
@include border-radius(3px 3px 0 0);
width: 100%;
margin: 0;
border: none;
li {
float: left;
position: absolute;
margin-bottom: 0;
width: 50%;
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 {
......@@ -192,14 +234,13 @@ nav.sequence-nav {
background-position: center;
background-repeat: no-repeat;
display: block;
height: 10px;
padding: 15px 0 14px;
height: 34px;
width: 40px;
text-indent: -9999px;
@include transition(all, .2s, $ease-in-out-quad);
&:hover {
opacity: .5;
background-color: #f4f4f4;
}
&.disabled {
......@@ -210,15 +251,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 15px;
}
}
&.next {
right: -10px;
border-radius: 0 35px 35px 0;
a {
border-left: 1px solid lighten($border-color, 10%);
margin-left: 30px;
background-image: url('../images/sequence-nav/next-icon.png');
background-position: center 15px;
}
}
}
......
div.video {
@include clearfix();
background: #f3f3f3;
border-bottom: 1px solid #e1e1e1;
border-top: 1px solid #e1e1e1;
display: block;
margin: 0 0 0 (-(lh()));
padding: 6px lh();
margin: 0 -12px;
padding: 12px;
border-radius: 5px;
article.video-wrapper {
float: left;
......@@ -401,6 +400,7 @@ div.video {
overflow: auto;
width: flex-grid(3, 9);
margin: 0;
font-size: 14px;
li {
border: 0;
......
......@@ -15,18 +15,39 @@ from xmodule.errortracker import exc_info_to_str
log = logging.getLogger(__name__)
# NOTE: This is not the most beautiful design in the world, but there's no good
# way to tell if the module is being used in a staff context or not. Errors that get discovered
# at course load time are turned into ErrorDescriptor objects, and automatically hidden from students.
# Unfortunately, we can also have errors when loading modules mid-request, and then we need to decide
# what to show, and the logic for that belongs in the LMS (e.g. in get_module), so the error handler
# decides whether to create a staff or not-staff module.
class ErrorModule(XModule):
def get_html(self):
'''Show an error.
'''Show an error to staff.
TODO (vshnayder): proper style, divs, etc.
'''
# staff get to see all the details
return self.system.render_template('module-error.html', {
'staff_access' : True,
'data' : self.definition['data']['contents'],
'error' : self.definition['data']['error_msg'],
})
class NonStaffErrorModule(XModule):
def get_html(self):
'''Show an error to a student.
TODO (vshnayder): proper style, divs, etc.
'''
# staff get to see all the details
return self.system.render_template('module-error.html', {
'staff_access' : False,
'data' : "",
'error' : "",
})
class ErrorDescriptor(EditingDescriptor):
"""
Module that provides a raw editing view of broken xml.
......@@ -99,3 +120,9 @@ class ErrorDescriptor(EditingDescriptor):
err_node = etree.SubElement(root, 'error_msg')
err_node.text = self.definition['data']['error_msg']
return etree.tostring(root)
class NonStaffErrorDescriptor(ErrorDescriptor):
"""
Module that provides non-staff error messages.
"""
module_class = NonStaffErrorModule
from xmodule.modulestore.django import modulestore
from xmodule.course_module import CourseDescriptor
from django.conf import settings
def get_subdomain(domain):
return domain.split(".")[0]
def get_visible_courses(domain=None):
"""
Return the set of CourseDescriptors that should be visible in this branded instance
"""
courses = [c for c in modulestore().get_courses()
if isinstance(c, CourseDescriptor)]
courses = sorted(courses, key=lambda course: course.number)
if domain and settings.MITX_FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
subdomain = get_subdomain(domain)
if subdomain not in settings.COURSE_LISTINGS:
subdomain = 'default'
visible_ids = frozenset(settings.COURSE_LISTINGS[subdomain])
return [course for course in courses if course.id in visible_ids]
else:
return courses
def get_university(domain=None):
"""
Return the university name specified for the domain, or None
if no university was specified
"""
if not settings.MITX_FEATURES['SUBDOMAIN_BRANDING'] or domain is None:
return None
subdomain = get_subdomain(domain)
return settings.SUBDOMAIN_BRANDING.get(subdomain)
def get_logo_url(domain=None):
"""
Return the url for the branded logo image to be used
"""
university = get_university(domain)
if university is None:
return '/static/images/header-logo.png'
return '/static/images/{uni}-on-edx-logo.png'.format(
uni=university
)
from django.conf import settings
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django_future.csrf import ensure_csrf_cookie
import student.views
import branding
import courseware.views
from util.cache import cache_if_anonymous
@ensure_csrf_cookie
@cache_if_anonymous
def index(request):
'''
Redirects to main page -- info page if user authenticated, or marketing if not
'''
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
return redirect(reverse('dashboard'))
if settings.MITX_FEATURES.get('AUTH_USE_MIT_CERTIFICATES'):
from external_auth.views import edXauth_ssl_login
return edXauth_ssl_login(request)
university = branding.get_university(request.META.get('HTTP_HOST'))
if university is None:
return student.views.index(request, user=request.user)
return courseware.views.university_profile(request, university)
@ensure_csrf_cookie
@cache_if_anonymous
def courses(request):
"""
Render the "find courses" page. If subdomain branding is on, this is the
university profile page, otherwise it's the edX courseware.views.courses page
"""
university = branding.get_university(request.META.get('HTTP_HOST'))
if university is None:
return courseware.views.courses(request)
return courseware.views.university_profile(request, university)
......@@ -5,6 +5,7 @@ from django.http import Http404
from django.shortcuts import redirect
from wiki.models import reverse as wiki_reverse
from courseware.access import has_access
from courseware.courses import get_course_with_access
......@@ -135,7 +136,9 @@ def context_processor(request):
try:
course = get_course_with_access(request.user, course_id, 'load')
return {'course' : course}
staff_access = has_access(request.user, course, 'staff')
return {'course' : course,
'staff_access': staff_access}
except Http404:
# We couldn't access the course for whatever reason. It is too late to change
# the URL here, so we just leave the course context. The middleware shouldn't
......
......@@ -80,8 +80,8 @@ def course_wiki_redirect(request, course_id):
urlpath = URLPath.create_article(
root,
course_slug,
title=course.number,
content="{0}\n===\nThis is the wiki for **{1}**'s _{2}_.".format(course.number, course.org, course.title),
title=course_slug,
content="This is the wiki for **{0}**'s _{1}_.".format(course.org, course.title),
user_message="Course page automatically created.",
user=None,
ip_address=None,
......@@ -114,7 +114,7 @@ def get_or_create_root():
"===",
"Visit a course wiki to add an article."))
root = URLPath.create_root(title="edX Wiki",
root = URLPath.create_root(title="Wiki",
content=starting_content)
article = root.article
article.group = None
......
......@@ -13,7 +13,6 @@ from xmodule.modulestore import Location
from xmodule.timeparse import parse_time
from xmodule.x_module import XModule, XModuleDescriptor
DEBUG_ACCESS = False
log = logging.getLogger(__name__)
......
......@@ -13,6 +13,7 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from static_replace import replace_urls, try_staticfiles_lookup
from courseware.access import has_access
import branding
log = logging.getLogger(__name__)
......@@ -141,9 +142,10 @@ def get_course_info_section(course, section_key):
raise KeyError("Invalid about key " + str(section_key))
# TODO: Fix this such that these are pulled in as extra course-specific tabs.
# arjun will address this by the end of October if no one does so prior to
# then.
# then.
def get_course_syllabus_section(course, section_key):
"""
This returns the snippet of html to be rendered on the syllabus page,
......@@ -178,24 +180,11 @@ def get_courses_by_university(user, domain=None):
'''
# TODO: Clean up how 'error' is done.
# filter out any courses that errored.
courses = [c for c in modulestore().get_courses()
if isinstance(c, CourseDescriptor)]
courses = sorted(courses, key=lambda course: course.number)
if domain and settings.MITX_FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
subdomain = domain.split(".")[0]
if subdomain not in settings.COURSE_LISTINGS:
subdomain = 'default'
visible_courses = frozenset(settings.COURSE_LISTINGS[subdomain])
else:
visible_courses = frozenset(c.id for c in courses)
visible_courses = branding.get_visible_courses(domain)
universities = defaultdict(list)
for course in courses:
for course in visible_courses:
if not has_access(user, course, 'see_exists'):
continue
if course.id not in visible_courses:
continue
universities[course.org].append(course)
return universities
import json
import logging
import sys
from django.conf import settings
from django.contrib.auth.models import User
......@@ -15,10 +16,12 @@ from courseware.access import has_access
from mitxmako.shortcuts import render_to_string
from models import StudentModule, StudentModuleCache
from static_replace import replace_urls
from xmodule.errortracker import exc_info_to_str
from xmodule.exceptions import NotFoundError
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from xmodule.x_module import ModuleSystem
from xmodule.error_module import ErrorDescriptor, NonStaffErrorDescriptor
from xmodule_modifiers import replace_course_urls, replace_static_urls, add_histogram, wrap_xmodule
log = logging.getLogger("mitx.courseware")
......@@ -73,6 +76,8 @@ def toc_for_course(user, request, course, active_chapter, active_section, course
student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(
course_id, user, course, depth=2)
course = get_module(user, request, course.location, student_module_cache, course_id)
if course is None:
return None
chapters = list()
for chapter in course.get_display_items():
......@@ -131,9 +136,9 @@ def get_section(course_module, chapter, section):
return section_module
def get_module(user, request, location, student_module_cache, course_id, position=None):
''' Get an instance of the xmodule class identified by location,
"""
Get an instance of the xmodule class identified by location,
setting the state based on an existing StudentModule, or creating one if none
exists.
......@@ -146,9 +151,22 @@ def get_module(user, request, location, student_module_cache, course_id, positio
- position : extra information from URL for user-specified
position within module
Returns: xmodule instance
Returns: xmodule instance, or None if the user does not have access to the
module. If there's an error, will try to return an instance of ErrorModule
if possible. If not possible, return None.
"""
try:
return _get_module(user, request, location, student_module_cache, course_id, position)
except:
# Something has gone terribly wrong, but still not letting it turn into a 500.
log.exception("Error in get_module")
return None
'''
def _get_module(user, request, location, student_module_cache, course_id, position=None):
"""
Actually implement get_module. See docstring there for details.
"""
location = Location(location)
descriptor = modulestore().get_instance(course_id, location)
# Short circuit--if the user shouldn't have access, bail without doing any work
......@@ -198,7 +216,7 @@ def get_module(user, request, location, student_module_cache, course_id, positio
'callback_url': xqueue_callback_url,
'default_queuename': xqueue_default_queuename.replace(' ', '_')}
def _get_module(location):
def inner_get_module(location):
"""
Delegate to get_module. It does an access check, so may return None
"""
......@@ -214,7 +232,7 @@ def get_module(user, request, location, student_module_cache, course_id, positio
xqueue=xqueue,
# TODO (cpennington): Figure out how to share info between systems
filestore=descriptor.system.resources_fs,
get_module=_get_module,
get_module=inner_get_module,
user=user,
# TODO (cpennington): This should be removed when all html from
# a module is coming through get_html and is therefore covered
......@@ -226,7 +244,22 @@ def get_module(user, request, location, student_module_cache, course_id, positio
system.set('position', position)
system.set('DEBUG', settings.DEBUG)
module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
try:
module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
except:
log.exception("Error creating module from descriptor {0}".format(descriptor))
# make an ErrorDescriptor -- assuming that the descriptor's system is ok
import_system = descriptor.system
if has_access(user, location, 'staff'):
err_descriptor = ErrorDescriptor.from_xml(str(descriptor), import_system,
error_msg=exc_info_to_str(sys.exc_info()))
else:
err_descriptor = NonStaffErrorDescriptor.from_xml(str(descriptor), import_system,
error_msg=exc_info_to_str(sys.exc_info()))
# Make an error module
return err_descriptor.xmodule_constructor(system)(None, None)
module.get_html = replace_static_urls(
wrap_xmodule(module.get_html, module, 'xmodule_display.html'),
......@@ -374,7 +407,7 @@ def modx_dispatch(request, dispatch, location, course_id):
# ''' (fix emacs broken parsing)
# Check for submitted files and basic file size checks
p = request.POST.dict()
p = request.POST.copy()
if request.FILES:
for fileinput_id in request.FILES.keys():
inputfiles = request.FILES.getlist(fileinput_id)
......
......@@ -55,9 +55,14 @@ MITX_FEATURES = {
# course_ids (see dev_int.py for an example)
'SUBDOMAIN_COURSE_LISTINGS' : False,
# When True, will override certain branding with university specific values
# Expects a SUBDOMAIN_BRANDING dictionary that maps the subdomain to the
# university to use for branding purposes
'SUBDOMAIN_BRANDING': False,
# TODO: This will be removed once course-specific tabs are in place. see
# courseware/courses.py
'ENABLE_SYLLABUS' : True,
'ENABLE_SYLLABUS' : True,
'ENABLE_TEXTBOOK' : True,
'ENABLE_DISCUSSION' : False,
......@@ -66,7 +71,7 @@ MITX_FEATURES = {
'ENABLE_SQL_TRACKING_LOGS': False,
'ENABLE_LMS_MIGRATION': False,
'DISABLE_LOGIN_BUTTON': False, # used in systems where login is automatic, eg MIT SSL
'DISABLE_LOGIN_BUTTON': False, # used in systems where login is automatic, eg MIT SSL
# extrernal access methods
'ACCESS_REQUIRE_STAFF_FOR_COURSE': False,
......@@ -199,6 +204,11 @@ COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x',
# TODO (vshnayder): Will probably need to change as we get real access control in.
LMS_MIGRATION_ALLOWED_IPS = []
######################## subdomain specific settings ###########################
COURSE_LISTINGS = {}
SUBDOMAIN_BRANDING = {}
############################### XModule Store ##################################
MODULESTORE = {
'default': {
......@@ -318,6 +328,7 @@ WIKI_ACCOUNT_HANDLING = False
WIKI_EDITOR = 'course_wiki.editors.CodeMirror'
WIKI_SHOW_MAX_CHILDREN = 0 # We don't use the little menu that shows children of an article in the breadcrumb
WIKI_ANONYMOUS = False # Don't allow anonymous access until the styling is figured out
WIKI_CAN_CHANGE_PERMISSIONS = lambda article, user: user.has_perm('wiki.assign')
################################# Jasmine ###################################
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
......
......@@ -15,7 +15,8 @@ TEMPLATE_DEBUG = True
MITX_FEATURES['DISABLE_START_DATES'] = True
MITX_FEATURES['ENABLE_SQL_TRACKING_LOGS'] = True
MITX_FEATURES['ENABLE_DISCUSSION_SERVICE'] = True
MITX_FEATURES['SUBDOMAIN_COURSE_LISTINGS'] = True
MITX_FEATURES['SUBDOMAIN_BRANDING'] = True
WIKI_ENABLED = True
......@@ -69,6 +70,28 @@ CACHE_TIMEOUT = 0
# Dummy secret key for dev
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
COURSE_LISTINGS = {
'default': ['BerkeleyX/CS169.1x/2012_Fall',
'BerkeleyX/CS188.1x/2012_Fall',
'HarvardX/CS50x/2012',
'HarvardX/PH207x/2012_Fall',
'MITx/3.091x/2012_Fall',
'MITx/6.002x/2012_Fall',
'MITx/6.00x/2012_Fall'],
'berkeley': ['BerkeleyX/CS169.1x/Cal_2012_Fall',
'BerkeleyX/CS188.1x/Cal_2012_Fall'],
'harvard': ['HarvardX/CS50x/2012H'],
'mit': [],
'sjsu': ['MITx/6.002x-EE98/2012_Fall_SJSU'],
}
SUBDOMAIN_BRANDING = {
'sjsu': 'MITx',
'mit': 'MITx',
'berkeley': 'BerkeleyX',
'harvard': 'HarvardX',
}
################################ LMS Migration #################################
MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True
MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll
......
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);
}
\ No newline at end of file
Sass Watch:
sass --watch lms/static/sass:lms/static/sass -r ./lms/static/sass/bourbon/lib/bourbon.rb
......@@ -55,10 +55,10 @@ $tag-text-color: #5b614f;
.sidebar-module {
@include clearfix;
padding: 0 24px 24px 0;
padding: 0 26px 24px;
margin-bottom: 24px;
border-bottom: 1px solid #d3d3d3;
font-size: 0.8em;
font-size: 13px;
header {
margin-bottom: 14px;
......@@ -67,16 +67,18 @@ $tag-text-color: #5b614f;
h4 {
float: left;
font-size: 1.1em;
font-size: 15px;
font-weight: bold;
}
.sidebar-new-post-button, .sidebar-promote-moderator-button {
@include button;
}
.sidebar-revoke-moderator-button {
@include button(simple, gray);
}
.sidebar-new-post-button, .sidebar-promote-moderator-button, .sidebar-revoke-moderator-button {
display: block;
box-sizing: border-box;
......@@ -91,9 +93,13 @@ $tag-text-color: #5b614f;
}
}
.sidebar-new-post-button {
margin: 40px 0 20px 0;
}
.sidebar-view-all {
float: right;
font-size: 0.9em;
font-size: 13px;
line-height: 1.6em;
@include standard-discussion-link;
}
......@@ -108,6 +114,10 @@ $tag-text-color: #5b614f;
a {
@include standard-discussion-link;
background: none;
span {
line-height: 1.3;
}
}
}
......
......@@ -15,16 +15,19 @@ $monospace: Monaco, 'Bitstream Vera Sans Mono', 'Lucida Console', monospace;
$body-font-size: em(14);
$body-line-height: golden-ratio(.875em, 1);
$base-font-color: rgb(60,60,60);
$lighter-base-font-color: rgb(160,160,160);
$lighter-base-font-color: rgb(100,100,100);
$blue: rgb(29,157,217);
$pink: rgb(182,37,104);
$yellow: rgb(255, 252, 221);
$error-red: rgb(253, 87, 87);
$border-color: #C8C8C8;
$sidebar-color: #f6f6f6;
$outer-border-color: #aaa;
// old variables
$light-gray: #ddd;
$dark-gray: #333;
$text-color: $dark-gray;
......@@ -11,6 +11,7 @@
// Course base / layout styles
@import 'course/layout/courseware_header';
@import 'course/layout/footer';
@import 'course/base/base';
@import 'course/base/extends';
@import 'module/module-styles.scss';
......@@ -34,6 +35,9 @@
@import "course/profile";
@import "course/gradebook";
// instructor
@import "course/instructor/instructor";
// Askbot / Discussion styles
@import "course/discussion/askbot-original";
@import "course/discussion/discussion";
......
......@@ -6,6 +6,9 @@ div.gradebook-wrapper {
section.gradebook-content {
@extend .content;
display: block;
width: 100%;
@include clearfix;
.student-search {
padding: 0 20px 0 15px;
......@@ -15,7 +18,7 @@ div.gradebook-wrapper {
width: 100%;
height: 27px;
padding: 0 15px 0 35px;
box-sizing: border-box;
@include box-sizing(border-box);
border-radius: 13px;
border: 1px solid $table-border-color;
background: url(../images/search-icon.png) no-repeat 9px center #f6f6f6;
......@@ -37,7 +40,6 @@ div.gradebook-wrapper {
.student-table {
float: left;
// width: 264px;
width: 24%;
border-radius: 3px 0 0 3px;
color: #3c3c3c;
......@@ -88,12 +90,20 @@ div.gradebook-wrapper {
.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));
background-image: -webkit-gradient(linear, left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -webkit-gradient(linear, left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
background-image: -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));
background-image: -moz-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -moz-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
background-image: -ms-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -ms-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
background-image: -o-linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -o-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));
background-image: -webkit-gradient(linear, right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -webkit-gradient(linear, right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
background-image: -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));
background-image: -moz-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -moz-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
background-image: -ms-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -ms-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
background-image: -o-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 20%), -o-linear-gradient(right, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0));
}
}
......@@ -103,9 +113,8 @@ div.gradebook-wrapper {
left: 0;
width: 1000px;
cursor: move;
-webkit-transition: none;
-webkit-user-select: none;
user-select: none;
@include transition(none);
@include user-select(none);
td,
th {
......@@ -116,32 +125,30 @@ div.gradebook-wrapper {
thead th {
position: relative;
height: 50px;
background: -webkit-linear-gradient(top, $cell-border-color, #ddd);
@include 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));
}
border-left: 1px solid #ccc;
// &:before {
// content: '';
// display: block;
// position: absolute;
// left: 0;
// top: 0;
// z-index: 9999;
// width: 1px;
// height: 50px;
// @include 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;
}
border-left: none;
}
&:last-child {
......@@ -161,7 +168,7 @@ div.gradebook-wrapper {
.max {
height: 12px;
background: -webkit-linear-gradient(top, #c6c6c6, #bababa);
@include linear-gradient(top, #c6c6c6, #bababa);
font-size: 9px;
line-height: 12px;
color: #fff;
......
......@@ -68,10 +68,10 @@ div.info-wrapper {
section.handouts {
@extend .sidebar;
border-left: 1px solid $border-color;
border-right: 0;
@include border-radius(0 4px 4px 0);
border-left: 1px solid #ddd;
@include box-shadow(none);
font-size: 14px;
&:after {
left: -1px;
......@@ -79,31 +79,51 @@ div.info-wrapper {
}
h1 {
@extend .bottom-border;
margin-bottom: 0;
padding: lh(.5) lh(.5);
padding: 32px 26px 20px 26px;
font-size: 18px;
font-style: normal;
font-weight: bold;
}
ol {
li {
margin: 0 26px 14px 26px;
a {
display: block;
padding-left: lh(.5);
padding-right: 0;
padding: 0;
&:hover {
background: transparent;
}
}
&.expandable,
&.collapsable {
margin: 0 16px 14px 16px;
@include transition(all .2s);
h4 {
color: $blue;
font-size: 1em;
font-weight: normal;
padding: lh(.25) 0 lh(.25) lh(1.5);
padding-left: 30px;
}
}
&.collapsable {
background: #fff;
border-radius: 3px;
padding: 14px 0;
@include box-shadow(0 0 1px 1px rgba(0, 0, 0, .1), 0 1px 3px rgba(0, 0, 0, .25));
h4 {
margin-bottom: 16px;
}
}
&.multiple {
padding: lh(.5) 0 lh(.5) lh(.5);
a {
@include inline-block;
......@@ -121,10 +141,10 @@ div.info-wrapper {
li {
border-bottom: 0;
border-top: 1px solid $border-color;
@include box-shadow(inset 0 1px 0 #eee);
font-size: 1em;
padding: lh(.5) 0 lh(.5) lh(.5);
border-top: 1px solid #e6e6e6;
font-size: 0.9em;
margin: 0;
padding: 15px 30px;
a {
@include inline-block;
......@@ -138,11 +158,11 @@ div.info-wrapper {
}
div.hitarea {
background-image: url('../images/treeview-default.gif');
background-image: url('../images/treeview-default.gif') no-repeat;
display: block;
height: 100%;
margin-left: 0;
max-height: 30px;
max-height: 20px;
position: absolute;
width: 100%;
......@@ -157,20 +177,20 @@ div.info-wrapper {
}
&.expandable-hitarea {
background-position: -72px 7px;
background-position: -72px 0px;
}
&.collapsable-hitarea {
background-position: -55px -15px;
background-position: -55px -23px;
}
}
h3 {
border-bottom: 0;
@include box-shadow(none);
color: #aaa;
color: #888;
font-size: 1em;
margin-bottom: em(6);
margin-bottom: 0;
}
p {
......
div.syllabus {
padding: 0px 10px;
padding: 2em 2.5em;
text-align: center;
......@@ -9,15 +9,14 @@ div.syllabus {
}
.notes {
width: 740px;
margin: 0px auto 10px;
margin: 0px auto 20px;
}
table {
text-align: left;
margin: 10px auto;
margin: 10px 0;
thead {
font-weight: bold;
......
div.book-wrapper {
@extend .table-wrapper;
#open_close_accordion {
display: none;
}
section.book-sidebar {
@extend .sidebar;
@extend .tran;
@include box-sizing(border-box);
padding: 10px 0;
border-radius: 3px 0 0 3px;
border-right: 1px solid #ccc;
ul#booknav {
font-size: em(14);
......@@ -32,7 +39,7 @@ div.book-wrapper {
li {
background: none;
border-bottom: 0;
padding-left: lh();
padding-left: lh();
a {
padding: 0;
......@@ -49,7 +56,7 @@ div.book-wrapper {
div.hitarea {
background-image: url('../images/treeview-default.gif');
margin-left: -22px;
position: relative;
top: 4px;
......@@ -62,26 +69,23 @@ div.book-wrapper {
ul {
background: none;
margin-top: lh(.25);
border-top: 1px solid $border-color;
padding-top: lh(.25);
li {
padding-bottom: lh(.25);
padding-bottom: 10px;
}
}
}
> li {
border-bottom: 1px solid $border-color;
padding: 7px 7px 7px 30px;
padding: 5px 6px;
margin: 0 16px 5px 25px;
}
}
}
section.book {
@extend .content;
padding-right: 0;
padding-left: lh();
nav {
@extend .clearfix;
......
body {
min-width: 980px;
min-height: 100%;
background: url(../images/bg-texture.png) #ddd;
}
body, h1, h2, h3, h4, h5, h6, p, p a:link, p a:visited, a, label {
......@@ -11,16 +13,37 @@ table {
table-layout: fixed;
}
a {
&:hover {
color: $pink;
text-decoration: none !important;
}
}
.content-wrapper {
background: none;
border: none;
}
.container {
padding: lh(2);
padding: 20px 0 0 0;
> div {
display: table;
width: 100%;
table-layout: fixed;
width: 100%;
border-radius: 3px;
border: 1px solid $outer-border-color;
background: #fff;
@include box-shadow(0 1px 2px rgba(0, 0, 0, 0.05));
}
}
form {
label {
display: block;
......@@ -75,11 +98,7 @@ img {
max-width: 100%;
}
.container {
padding: em(40) 0;
}
::selection, ::-moz-selection, ::-webkit-selection {
background:#444;
color:#fff;
background: #444;
color: #fff;
}
......@@ -37,7 +37,7 @@ h1.top-header {
.content {
@include box-sizing(border-box);
display: table-cell;
padding-right: lh();
padding: 2em 2.5em;
vertical-align: top;
width: flex-grid(9) + flex-gutter();
......@@ -47,34 +47,28 @@ h1.top-header {
}
.sidebar {
border-right: 1px solid #C8C8C8;
@include box-sizing(border-box);
display: table-cell;
font-family: $sans-serif;
font-size: 14px;
position: relative;
vertical-align: top;
width: flex-grid(3);
&:after {
width: 1px;
height: 100%;
@include position(absolute, 0px -1px 0px 0);
content: "";
@include background-image(linear-gradient(top, #fff, rgba(#fff, 0)), linear-gradient(top, rgba(#fff, 0), #fff));
background-position: top, bottom;
@include background-size(1px 20px);
background-repeat: no-repeat;
display: block;
}
background: $sidebar-color;
h1, h2 {
font-size: em(20);
font-weight: 100;
font-weight: bold;
letter-spacing: 0;
text-transform: none;
font-family: $sans-serif;
text-align: left;
font-style: italic;
font-style: normal;
}
h1 {
font-size: 18px;
padding: 32px 26px 20px 26px;
}
a {
......@@ -106,7 +100,7 @@ h1.top-header {
}
&.active {
@extend .bottom-border;
// @extend .bottom-border;
color: #000;
font-weight: bold;
......@@ -122,7 +116,7 @@ h1.top-header {
padding-left: 0;
li {
@extend .bottom-border;
// @extend .bottom-border;
@extend .clearfix;
background: none;
position: relative;
......
......@@ -12,8 +12,7 @@ div.course-wrapper {
section.course-content {
@extend .content;
padding-right: 0;
padding-left: lh();
padding: 40px;
h1 {
margin: 0 0 lh();
......@@ -46,6 +45,7 @@ div.course-wrapper {
ol.vert-mod {
padding: 0;
margin: 0;
line-height: 1.4;
> li {
@extend .clearfix;
......@@ -224,3 +224,12 @@ div.course-wrapper {
}
}
}
.xmodule_VideoModule {
margin-bottom: 30px;
}
section.course-index {
@extend .sidebar;
@extend .tran;
@include border-radius(3px 0 0 3px);
border-right: 1px solid #ddd;
#open_close_accordion {
display: none;
}
header {
max-height: 47px;
......@@ -11,10 +17,11 @@ section.course-index {
}
div#accordion {
width: auto;
font-size: 14px;
h3 {
@include border-radius(0);
border-top: 1px solid lighten($border-color, 10%);
font-size: em(16, 18);
margin: 0;
overflow: hidden;
......@@ -24,7 +31,6 @@ section.course-index {
&:hover {
color: #666;
background: #f6f6f6;
}
&.ui-state-hover {
......@@ -40,6 +46,7 @@ section.course-index {
a {
@include border-radius(0);
@include box-shadow(none);
padding-left: 19px;
}
&.ui-state-active {
......@@ -52,28 +59,50 @@ section.course-index {
}
span.ui-icon {
left: 0;
background-image: url("/static/images/ui-icons_222222_256x240.png");
opacity: .3;
}
}
}
.chapter {
width: 100%;
@include box-sizing(border-box);
padding: 11px 14px;
@include linear-gradient(top, rgba(255, 255, 255, .6), rgba(255, 255, 255, 0));
background-color: #eee;
@include box-shadow(0 1px 0 #fff inset, 0 -1px 0 rgba(0, 0, 0, .1) inset);
@include transition(background-color .1s);
&:first-child {
border-radius: 3px 0 0 0;
}
&:last-child {
border-radius: 0 0 0 3px;
@include box-shadow(0 1px 0 #fff inset);
}
&:hover {
background-color: #fff
}
}
ul.ui-accordion-content {
background: transparent;
border: none;
@include border-radius(0);
font-size: em(14, 18);
margin: 0;
padding: 1em 1.5em;
padding: 9px 0 9px 9px;
li {
border-bottom: 0;
@include border-radius(0);
margin-bottom: lh(.5);
margin-bottom: 4px;
a {
background: transparent;
border: 1px solid transparent;
@include border-radius(4px);
display: block;
padding: 5px 36px 5px 10px;
......@@ -84,39 +113,18 @@ section.course-index {
font-weight: bold;
font-family: $sans-serif;
margin-bottom: 0;
line-height: 1.3;
span.subtitle {
color: #666;
font-size: 13px;
font-weight: normal;
display: block;
}
}
&:after {
background: transparent;
border-right: 1px solid rgb(180,180,180);
border-top: 1px solid rgb(180,180,180);
content: "";
display: block;
height: 12px;
margin-top: -6px;
opacity: 0;
position: absolute;
right: 30px;
top: 50%;
@include transform(rotate(45deg));
width: 12px;
}
}
&:hover {
@include background-image(linear-gradient(-90deg, rgba(245,245,245, 0.4), rgba(230,230,230, 0.4)));
border-color: rgb(200,200,200);
&:after {
opacity: 1;
right: 15px;
@include transition();
}
background: rgba(0, 0, 0, .1);
> a p {
color: #333;
......@@ -136,8 +144,23 @@ section.course-index {
&.active {
font-weight: bold;
&:after {
content: '›';
position: absolute;
top: 50%;
right: 20px;
margin-top: -13px;
font-size: 30px;
font-weight: normal;
color: #333;
opacity: 0;
@include transition();
}
> a {
border-color: rgb(200,200,200);
border: 1px solid #bbb;
@include box-shadow(0 1px 0 rgba(255, 255, 255, .35) inset);
@include linear-gradient(top, #e6e6e6, #d6d6d6);
&:after {
opacity: 1;
......
......@@ -3,15 +3,16 @@ body.askbot {
section.container {
div.discussion-wrapper {
@extend .table-wrapper;
display: table;
div.discussion-content {
@include box-sizing(border-box);
display: table-cell;
min-width: 650px;
padding-right: lh();
vertical-align: top;
padding: 40px;
width: flex-grid(9) + flex-gutter();
a.tabula-rasa, .tabula-rasa{
@extend .light-button;
@include border-radius(5px);
......
......@@ -2,9 +2,10 @@
div.discussion-wrapper aside {
@extend .sidebar;
border-left: 1px solid $border-color;
border-left: 1px solid #ccc;
border-right: 0;
width: flex-grid(3);
border-radius: 0 3px 3px 0;
&:after {
left: -1px;
......@@ -16,9 +17,7 @@ div.discussion-wrapper aside {
}
h1 {
@extend .bottom-border;
padding: lh(.5) lh();
margin-bottom: em(16, 20);
margin-bottom: 0;
}
h2 {
......@@ -54,7 +53,7 @@ div.discussion-wrapper aside {
div.box {
display: block;
padding: lh(.5) lh();
padding: 18px 26px;
border-top: 1px solid lighten($border-color, 10%);
&:first-child {
......@@ -67,7 +66,7 @@ div.discussion-wrapper aside {
li {
border-bottom: 0;
background: #eee;
background: #ddd;
padding: 6px 10px 6px 5px;
a {
......@@ -298,6 +297,7 @@ div.discussion-wrapper aside {
div.view-profile {
border-top: 0;
padding-top: 0;
a {
@extend .gray-button;
......
......@@ -10,7 +10,7 @@ ul.tags {
}
li {
background: #eee;
background: #ddd;
color: #555;
display: inline-block;
font-size: 12px;
......@@ -19,7 +19,7 @@ ul.tags {
padding: 6px 10px 6px 5px;
&:before {
border-color:transparent #eee transparent transparent;
border-color:transparent #ddd transparent transparent;
border-style:solid;
border-width:12px 10px 12px 0;
content:"";
......
.instructor-dashboard-wrapper {
@extend .table-wrapper;
display: table;
section.instructor-dashboard-content {
@extend .content;
padding: 40px;
width: 100%;
h1 {
@extend .top-header;
}
}
}
nav.course-material {
@include clearfix;
@include box-sizing(border-box);
background: #f6f6f6;
border-bottom: 1px solid rgb(200,200,200);
border-bottom: none;
margin: 0px auto 0px;
padding: 0px;
width: 100%;
......@@ -16,33 +15,32 @@ nav.course-material {
ol.course-tabs {
@include border-top-radius(4px);
@include clearfix;
padding: 10px 0 0 0;
padding: 28px 0 10px 0;
margin-left: 10px;
li {
float: left;
list-style: none;
margin-right: 6px;
a {
color: darken($lighter-base-font-color, 20%);
border-radius: 3px;
color: #555;
display: block;
text-align: center;
padding: 8px 13px 12px;
padding: 10px 13px 12px;
font-size: 14px;
font-weight: 400;
font-weight: bold;
text-decoration: none;
text-shadow: 0 1px rgb(255,255,255);
&:hover {
color: $base-font-color;
color: #333;
background: rgba(255, 255, 255, .4);
}
&.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;
background: rgba(255, 255, 255, .8);
}
}
}
......@@ -57,7 +55,48 @@ nav.course-material {
}
}
.global {
header.global.slim {
border-bottom: 1px solid $outer-border-color;
@include box-shadow(0 1px 2px rgba(0, 0, 0, .1));
height: 50px;
@include linear-gradient(top, #fff, #eee);
.guest .secondary {
display: none;
}
nav {
padding-top: 5px;
}
h1.logo {
margin-left: 13px;
margin-right: 20px;
padding-right: 20px;
&::before {
@extend .faded-vertical-divider;
content: "";
display: block;
height: 40px;
position: absolute;
right: 3px;
top: -8px;
width: 1px;
}
&::after {
@extend .faded-vertical-divider-light;
content: "";
display: block;
height: 40px;
position: absolute;
right: 0px;
top: -12px;
width: 1px;
}
}
.find-courses-button {
display: none;
}
......@@ -68,8 +107,9 @@ nav.course-material {
float: left;
font-size: 0.9em;
font-weight: 600;
line-height: 40px;
color: #777;
letter-spacing: 0;
margin-top: 9px;
text-transform: none;
text-shadow: 0 1px 0 #fff;
white-space: nowrap;
......@@ -79,7 +119,16 @@ nav.course-material {
.provider {
font: inherit;
font-weight: bold;
color: #6d6d6d;
}
}
}
\ No newline at end of file
a#signup {
position: relative;
margin-top: 4px;
padding: 6px 12px 8px;
text-transform: none;
font-size: 14px;
font-weight: bold;
letter-spacing: 0;
}
}
nav.course-material {
@include clearfix;
@include box-sizing(border-box);
background: #f6f6f6;
border-bottom: 1px solid rgb(200,200,200);
background: none;
margin: 0px auto 0px;
padding: 0px;
width: 100%;
......@@ -37,11 +36,6 @@ nav.course-material {
}
&.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;
}
}
......
footer {
border: none;
box-shadow: none;
}
\ No newline at end of file
section.wiki {
padding-top: 25px;
> header {
height: 33px;
margin-bottom: 36px;
padding-bottom: 26px;
border-bottom: 1px solid $light-gray;
}
.pull-left {
float: left;
}
......@@ -16,6 +9,18 @@ section.wiki {
float: right;
}
.wiki-wrapper {
@include clearfix;
> header {
height: 33px;
padding: 24px 0 26px;
border-bottom: 1px solid #ccc;
border-radius: 3px 3px 0 0;
background-color: $sidebar-color;
}
}
/*-----------------
......@@ -27,7 +32,7 @@ section.wiki {
.breadcrumb {
list-style: none;
padding-left: 0;
margin: 0 0 0 flex-gutter();
margin: 0 0 0 40px;
li {
float: left;
......@@ -68,7 +73,7 @@ section.wiki {
.global-functions {
display: block;
width: auto;
margin-right: flex-gutter();
margin-right: 20px;
}
.add-article-btn {
......@@ -129,8 +134,9 @@ section.wiki {
.main-article {
float: left;
width: flex-grid(9);
margin-left: flex-gutter();
padding: 40px 0 40px 40px;
color: $base-font-color;
@include box-sizing(border-box);
}
&.view .main-article {
......@@ -193,6 +199,17 @@ section.wiki {
font-size: 0.9em;
font-family: Monaco, monospace;
}
.toc {
background-color: $sidebar-color;
padding: 9px;
margin: 10px 0;
@include border-radius(5px);
ul {
margin: 0;
}
}
}
......@@ -206,13 +223,14 @@ section.wiki {
.article-functions {
float: left;
width: flex-grid(2) + flex-gutter();
margin-left: flex-grid(1);
width: flex-grid(3);
padding: 40px 40px;
@include box-sizing(border-box);
.timestamp {
margin: 4px 0 15px;
padding: 0 0 15px 5px;
border-bottom: 1px solid $light-gray;
.timestamp{
margin-top: 15px;
padding: 15px 0 0 10px;
border-top: 1px solid $light-gray;
.label {
font-size: 0.7em;
......@@ -223,6 +241,26 @@ section.wiki {
.date {
font-size: 0.9em;
}
}
.see-children {
padding: 15px 0 0;
border-top: 1px solid $light-gray;
margin-top: 15px;
a {
display: block;
padding: 2px 4px 2px 10px;
border-radius: 3px;
font-size: 0.9em;
line-height: 25px;
&:hover {
background-color: #f6f6f6;
text-decoration: none;
}
}
}
}
......@@ -236,7 +274,8 @@ section.wiki {
a {
color: $blue;
.icon-view {
.icon-view,
.icon-home {
background-position: -25px 0;
}
......@@ -244,11 +283,13 @@ section.wiki {
background-position: -25px -25px;
}
.icon-changes {
.icon-changes,
.icon-time {
background-position: -25px -49px;
}
.icon-attachments {
.icon-attachments,
.icon-file {
background-position: -25px -73px;
}
......@@ -280,7 +321,8 @@ section.wiki {
background: url(../images/wiki-icons.png) no-repeat;
}
.icon-view {
.icon-view,
.icon-home {
background-position: 0 0;
}
......@@ -288,11 +330,13 @@ section.wiki {
background-position: 0 -25px;
}
.icon-changes {
.icon-changes,
.icon-time {
background-position: 0 -49px;
}
.icon-attachments {
.icon-attachments,
.icon-file {
background-position: 0 -73px;
}
......@@ -646,6 +690,59 @@ section.wiki {
margin-top: 9px;
}
/*-----------------
Directory
-----------------*/
.directory-toolbar {
background-color: $sidebar-color;
padding: 9px;
margin: 0 -9px 20px;
@include border-radius(5px);
.well-small {
@include clearfix;
a {
@include inline-block;
}
}
+ p {
font-size: 0.9em;
color: #aaa;
}
}
.filter-clear {
margin-right: 10px;
margin-top: 10px;
font-size: .9em;
a {
color: #aaa;
&:hover {
color: #777;
}
}
}
.table.table-striped {
width: 100%;
margin-top: 20px;
th, td {
border-bottom: 1px solid $light-gray;
padding: 8px;
}
tr:nth-child(even) {
background: #F6F6F6;
}
}
......@@ -706,6 +803,10 @@ section.wiki {
font-size: 0.8em;
}
.attachment-actions {
width: 175px;
}
.attachment-actions .btn {
float: right;
}
......@@ -767,6 +868,39 @@ section.wiki {
text-decoration: none;
}
}
.missing {
max-width: 400px;
margin: lh(2) auto;
display: block;
overflow: hidden;
background: $pink;
padding: lh();
@include box-shadow(inset 0 0 0 1px lighten($pink, 10%));
border: 1px solid darken($pink, 15%);
p {
color: #fff;
a {
display: block;
background: darken($pink, 8%);
margin: lh() (-(lh())) (-(lh()));
padding: lh();
border-top: 1px solid darken($pink, 15%);
color: #fff;
font-weight: bold;
font-size: em(18);
@include transition;
text-align: center;
-webkit-font-smoothing: antialiased;
&:hover {
background: darken($pink, 12%);
}
}
}
}
}
.modal-backdrop {
......
......@@ -48,7 +48,6 @@ footer {
a:link, a:visited {
color: $lighter-base-font-color;
letter-spacing: 1px;
padding: 6px 0px;
}
}
......@@ -70,6 +69,7 @@ footer {
position: relative;
width: 47px;
vertical-align: middle;
@include transition(none);
&:hover {
background-position: 0 0;
......@@ -90,7 +90,6 @@ footer {
a {
color: $lighter-base-font-color;
@include inline-block;
letter-spacing: 1px;
margin-right: 20px;
padding-top: 2px;
vertical-align: middle;
......@@ -165,7 +164,6 @@ footer {
color: $lighter-base-font-color;
font-family: $serif;
font-style: italic;
letter-spacing: 1px;
line-height: 1.6em;
margin-left: 20px;
text-transform: lowercase;
......
......@@ -19,7 +19,7 @@ header.global {
h1.logo {
float: left;
margin: 6px 15px 0px 0px;
margin: 0px 15px 0px 0px;
padding-right: 20px;
position: relative;
......@@ -46,12 +46,7 @@ header.global {
}
a {
@include background-image(url('/static/images/header-logo.png'));
background-position: 0 0;
background-repeat: no-repeat;
display: block;
height: 31px;
width: 64px;
}
}
......@@ -136,6 +131,7 @@ header.global {
&.user {
float: right;
margin-top: 4px;
> li.primary {
display: block;
......@@ -151,22 +147,22 @@ header.global {
> a {
@include border-radius(0 4px 4px 0);
border-left: none;
padding: 5px 8px 7px 8px;
}
}
}
a.user-link {
padding: 10px 12px 10px 42px;
padding: 6px 12px 8px 35px;
position: relative;
text-transform: none;
font-size: 14px;
font-weight: bold;
letter-spacing: 0;
.avatar {
//background: rgb(220,220,220);
@include background-image(url('../images/portal-icons/home-icon.png'));
background-size: cover;
//@include border-radius(3px);
//border: 1px solid rgb(80,80,80);
//@include box-shadow(0 1px 0 0 rgba(255,255,255, 0.6));
@include background-image(url('../images/small-header-home-icon.png'));
background-repeat: no-repeat;
height: 26px;
@include inline-block;
left: 8px;
......@@ -194,7 +190,7 @@ header.global {
padding: 5px 10px;
position: absolute;
right: 0px;
top: 50px;
top: 34px;
width: 170px;
z-index: 3;
......
<%! from django.core.urlresolvers import reverse %>
<%def name="make_chapter(chapter)">
<h3 ${' class="active"' if 'active' in chapter and chapter['active'] else ''}><a href="#">${chapter['display_name']}</a>
</h3>
<div class="chapter">
<h3 ${' class="active"' if 'active' in chapter and chapter['active'] else ''}><a href="#">${chapter['display_name']}</a>
</h3>
<ul>
% for section in chapter['sections']:
<li${' class="active"' if 'active' in section and section['active'] else ''}>
<a href="${reverse('courseware_section', args=[course_id, chapter['url_name'], section['url_name']])}">
<p>${section['display_name']}
<span class="subtitle">
${section['format']} ${"due " + section['due'] if 'due' in section and section['due'] != '' else ''}
</span>
</p>
</a>
</li>
% endfor
</ul>
<ul>
% for section in chapter['sections']:
<li${' class="active"' if 'active' in section and section['active'] else ''}>
<a href="${reverse('courseware_section', args=[course_id, chapter['url_name'], section['url_name']])}">
<p>${section['display_name']}
<span class="subtitle">
${section['format']} ${"due " + section['due'] if 'due' in section and section['due'] != '' else ''}
</span>
</p>
</a>
</li>
% endfor
</ul>
</div>
</%def>
% for chapter in toc:
......
<%inherit file="/main.html" />
<%namespace name='static' file='/static_content.html'/>
<%block name="bodyclass">courseware</%block>
<%block name="bodyclass">courseware ${course.css_class}</%block>
<%block name="title"><title>${course.number} Courseware</title></%block>
<%block name="headextra">
......@@ -11,6 +11,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>
......
......@@ -67,9 +67,9 @@
<thead>
<tr> <!-- Header Row -->
%for section in templateSummary['section_breakdown']:
<th>${section['label']}</th>
<th><div class="assignment-label">${section['label']}</div></th>
%endfor
<th>Total</th>
<th><div class="assignment-label">Total</div></th>
</tr>
</thead>
......
......@@ -13,12 +13,14 @@
%>
<section class="container">
<div class="syllabus">
<h1> Syllabus </h1>
% if user.is_authenticated():
${get_course_syllabus_section(course, 'syllabus')}
% else:
${get_course_syllabus_section(course, 'guest_syllabus')}
% endif
<div class="syllabus_wrapper">
<div class="syllabus">
<h1> Syllabus </h1>
% if user.is_authenticated():
${get_course_syllabus_section(course, 'syllabus')}
% else:
${get_course_syllabus_section(course, 'guest_syllabus')}
% endif
</div>
</div>
</section>
......@@ -6,7 +6,7 @@
<nav>
<section class="top">
<section class="primary">
<a href="${reverse('root')}" class="logo"></a>
<a href="https://www.edx.org" class="logo"></a>
<a href="${reverse('courses')}">Find Courses</a>
<a href="${reverse('about_edx')}">About</a>
<a href="http://edxonline.tumblr.com/">Blog</a>
......
......@@ -2,10 +2,19 @@
<h1>There has been an error on the <em>MITx</em> servers</h1>
<p>We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p>
<h1>Details below:</h1>
% if staff_access:
<h1>Details</h1>
<p>Error: ${error | h}</p>
<p>Error:
<pre>
${error | h}
</pre>
</p>
<p>Raw data: ${data | h}</p>
<p>Raw data:
<pre>${data | h}</pre>
</p>
% endif
</section>
<%inherit file="main.html" />
<%include file="navigation.html" args="active_page=''" />
<script>
function name_confirm(id) {
postJSON('/accept_name_change',{"id":id},
......
......@@ -3,11 +3,20 @@
## one for people who aren't. Assume a Course object is passed to the former,
## instead of using settings.COURSE_TITLE
<%namespace name='static' file='static_content.html'/>
<%! from django.core.urlresolvers import reverse %>
<%!
from django.core.urlresolvers import reverse
<header class="global" aria-label="Global Navigation">
# App that handles subdomain specific branding
import branding
%>
%if course:
<header class="global slim" aria-label="Global Navigation">
%else:
<header class="global" aria-label="Global Navigation">
%endif
<nav>
<h1 class="logo"><a href="${reverse('root')}"></a></h1>
<h1 class="logo"><a href="${reverse('root')}"><img src="${static.url(branding.get_logo_url(request.META.get('HTTP_HOST')))}"/></a></h1>
%if course:
<h2><span class="provider">${course.org}:</span> ${course.number} ${course.title}</h2>
......
<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>
......@@ -21,7 +23,7 @@
</nav>
% for item in items:
<div class="seq_contents tex2jax_ignore">${item['content'] | h}</div>
<div class="seq_contents tex2jax_ignore asciimath2jax_ignore">${item['content'] | h}</div>
% endfor
<div id="seq_content"></div>
......@@ -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>
<%inherit file="main.html" />
<%block name="title"><title>Textbook – MITx 6.002x</title></%block>
<div id="bodyContent">
<%include file="navigation.html" />
<div>
${ text }
</div>
</div>
......@@ -11,25 +11,32 @@
{% block wiki_contents %}
<div class="article-wrapper">
<article class="main-article">
{% if selected_tab != "edit" %}
<h1>{{ article.current_revision.title }}</h1>
<h1>{{ article.current_revision.title }}</h1>
{% endif %}
{% block wiki_contents_tab %}
{% wiki_render article %}
{% endblock %}
{% endblock %}
</article>
<div class="article-functions">
<ul class="nav nav-tabs">
{% include "wiki/includes/article_menu.html" %}
</ul>
<div class="timestamp">
<span class="label">{% trans "Last modified:" %}</span><br />
<span class="date">{{ article.current_revision.modified }}</span>
</div>
<ul class="nav nav-tabs">
{% include "wiki/includes/article_menu.html" %}
</ul>
{% if urlpath %}
<div class="see-children">
<a href="{% url 'wiki:dir' path=urlpath.path %}">See all children</a>
</div>
{% endif %}
</div>
</div>
......
......@@ -51,24 +51,24 @@
{% endif %}
<section class="container wiki {{ selected_tab }}">
<div class="wiki-wrapper">
{% block wiki_body %}
{% block wiki_breadcrumbs %}{% endblock %}
{% block wiki_body %}
{% block wiki_breadcrumbs %}{% endblock %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
<a class="close" data-dismiss="alert" href="#">&times;</a>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block wiki_contents %}{% endblock %}
{% endblock %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
<a class="close" data-dismiss="alert" href="#">&times;</a>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block wiki_contents %}{% endblock %}
{% endblock %}
</div>
</section>
{% endblock %}
{% extends "wiki/base.html" %}
{% load wiki_tags i18n sekizai_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "Delete article" %}{% endblock %}
{% block wiki_contents %}
<h1 class="page-header">{% trans "Delete" %} "{{ article.current_revision.title }}"</h1>
{% if cannot_delete_root %}
<p class="lead">{% trans "You cannot delete a root article." %}</p>
<p><a href="{% url 'wiki:get' path=urlpath.path article_id=article.id %}">{% trans "Go back" %}</a></p>
{% else %}
{% if cannot_delete_children %}
<p class="alert alert-error"><strong>{% trans "You cannot delete this article because you do not have permission to delete articles with children. Try to remove the children manually one-by-one." %}</strong></p>
{% endif %}
{% if delete_children %}
<p class="lead">{% trans "You are deleting an article. This means that its children will be deleted as well. If you choose to purge, children will also be purged!" %}</p>
<h2>{% trans "Articles that will be deleted" %}</h2>
<ul>
{% for child in delete_children %}
<li><a href="{% url 'wiki:get' article_id=child.article.id %}" target="_blank">{{ child.article }}</a></li>
{% if delete_children_more %}
<li><em>{% trans "...and more!" %}</em></li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if not cannot_delete_children %}
<p class="lead">{% trans "You are deleting an article. Please confirm." %}</p>
<form method="POST" class="form-horizontal">
{% wiki_form delete_form %}
<script type="text/javascript">
$('#id_revision').val('{{ article.current_revision.id }}');
</script>
<div class="form-actions">
<a href="{% url 'wiki:get' path=urlpath.path article_id=article.id %}" class="btn btn-large">
<span class="icon-circle-arrow-left"></span>
{% trans "Go back" %}
</a>
<button type="submit" name="save_changes" class="btn btn-danger btn-large">
<span class="icon-plus"></span>
{% trans "Delete article" %}
</button>
</div>
</form>
{% endif %}
{% endif %}
{% endblock %}
......@@ -3,7 +3,7 @@
<li class="${"active" if selected_tab == "view" else ""}">
<a href="${reverse('wiki:get', kwargs={'article_id' : article.id, 'path' : urlpath.path})}">
<span class="icon-home"></span>
<span class="icon-home icon"></span>
View
</a>
</li>
......@@ -11,7 +11,7 @@
%if article.can_write(user):
<li class="${"active" if selected_tab == "edit" else ""}">
<a href="${reverse('wiki:edit', kwargs={'article_id' : article.id, 'path' : urlpath.path})}">
<span class="icon-edit"></span>
<span class="icon-edit icon"></span>
Edit
</a>
</li>
......@@ -19,7 +19,7 @@
<li class="${"active" if selected_tab == "history" else ""}">
<a href="${reverse('wiki:history', kwargs={'article_id' : article.id, 'path' : urlpath.path})}">
<span class="icon-time"></span>
<span class="icon-changes icon"></span>
Changes
</a>
</li>
......@@ -28,19 +28,25 @@
%if hasattr(plugin, "article_tab"):
<li class="${"active" if selected_tab == plugin.slug else ""}">
<a href="${reverse('wiki:plugin', kwargs={'slug' : plugin.slug, 'article_id' : article.id, 'path' : urlpath.path}) }">
<span class="${plugin.article_tab[1]}"></span>
<span class="${plugin.article_tab[1]} icon"></span>
${plugin.article_tab[0]}
</a>
</li>
%endif
%endfor
<%doc>
The settings link has been disabled because the notifications app hasn't been integrated yet and those are the only useful settings.
%if not user.is_anonymous():
<li class="${"active" if selected_tab == "settings" else ""}">
<a href="${reverse('wiki:settings', kwargs={'article_id' : article.id, 'path' : urlpath.path})}">
<span class="icon-wrench"></span>
<span class="icon-settings icon"></span>
Settings
</a>
</li>
%endif
</%doc>
......@@ -115,7 +115,13 @@
{% if attachment.current_revision.user %}{{ attachment.current_revision.user }}{% else %}{% if user|is_moderator %}{{ attachment.current_revision.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %}
</td>
<td>{{ attachment.current_revision.get_size|filesizeformat }}</td>
<td>{{ attachment.attachmentrevision_set.all.count }} {% trans "revisions" %}</td>
<td>
<a href="{% url 'wiki:attachments_history' path=urlpath.path article_id=article.id attachment_id=attachment.id %}">
<span class="icon-time"></span>
{% trans "File history" %} ({{ attachment.attachmentrevision_set.all.count }} {% trans "revisions" %})
</a>
</td>
</tr>
</table>
</div>
......
......@@ -10,22 +10,31 @@
<div class="main-article">
{% if revision %}
<div class="alert alert-info">
<strong>{% trans "Previewing revision" %}:</strong> {{ revision.created }} (#{{ revision.revision_number }}) by {% if revision.user %}{{ revision.user }}{% else %}{% if user|is_moderator %}{{ revision.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %}
<strong>{% trans "Previewing revision" %}:</strong>
{% include "wiki/includes/revision_info.html" %}
</div>
{% endif %}
{% if merge %}
<div class="alert alert-info">
<strong>{% trans "Previewing merge between" %}:</strong>
{{ merge1.created }} (#{{ merge1.revision_number }}) by {% if merge1.user %}{{ merge1.user }}{% else %}{% if user|is_moderator %}{{ merge1.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %}
{% include "wiki/includes/revision_info.html" with revision=merge1 %}
<strong>{% trans "and" %}</strong>
{{ merge1.created }} (#{{ merge1.revision_number }}) by {% if merge1.user %}{{ merge1.user }}{% else %}{% if user|is_moderator %}{{ merge1.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %}
{% include "wiki/includes/revision_info.html" with revision=merge2 %}
</div>
{% endif %}
<h1 class="page-header">{{ title }}</h1>
{% wiki_render article content %}
{% if revision and revision.deleted %}
<div class="warning">
<strong>This revision has been deleted.</strong>
<p>Restoring to this revision will mark the article as deleted.</p>
</div>
{% else %}
{% wiki_render article content %}
{% endif %}
</div>
</section>
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{% trans "Settings" %}: {{ article.current_revision.title }}{% endblock %}
{% block wiki_breadcrumbs %}
{% include "wiki/includes/breadcrumbs.html" %}
{% endblock %}
{% block wiki_contents %}
<div class="article-wrapper">
<article class="main-article">
{% if selected_tab != "edit" %}
<h1>{{ article.current_revision.title }}</h1>
{% endif %}
{% for form in forms %}
<form method="POST" class="form-horizontal" id="settings_form" action="?f={{form.action}}">
<h2>{{ form.settings_form_headline }}</h2>
<div class="well">
{% wiki_form form %}
</div>
<div class="form-actions">
<button type="submit" name="save" value="1" class="btn btn-large btn-primary">
<span class="icon-ok"></span>
{% trans "Save changes" %}
</button>
</div>
</form>
{% endfor %}
</article>
<div class="article-functions">
<div class="timestamp">
<span class="label">{% trans "Last modified:" %}</span><br />
<span class="date">{{ article.current_revision.modified }}</span>
</div>
<ul class="nav nav-tabs">
{% with "settings" as selected %}
{% include "wiki/includes/article_menu.html" %}
{% endwith %}
</ul>
</div>
</div>
{% endblock %}
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{{ article.current_revision.title }}{% endblock %}
{% block wiki_breadcrumbs %}
{% include "wiki/includes/breadcrumbs.html" %}
{% endblock %}
{% block wiki_contents %}
<div class="missing-wrapper">
<p>This article was not found, and neither was the parent. <a href="#">Go back to the main wiki article.</a></p>
<button type="submit">Create a new article</button>
</div>
{% endblock %}
......@@ -10,7 +10,7 @@ if settings.DEBUG:
admin.autodiscover()
urlpatterns = ('',
url(r'^$', 'student.views.index', name="root"), # Main marketing page, or redirect to courseware
url(r'^$', 'branding.views.index', name="root"), # Main marketing page, or redirect to courseware
url(r'^dashboard$', 'student.views.dashboard', name="dashboard"),
url(r'^admin_dashboard$', 'dashboard.views.dashboard'),
......@@ -115,7 +115,7 @@ if settings.COURSEWARE_ENABLED:
# url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
# url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'),
url(r'^courses/?$', 'courseware.views.courses', name="courses"),
url(r'^courses/?$', 'branding.views.courses', name="courses"),
url(r'^change_enrollment$',
'student.views.change_enrollment_view', name="change_enrollment"),
......
-e git://github.com/MITx/django-staticfiles.git@6d2504e5c8#egg=django-staticfiles
-e git://github.com/MITx/django-pipeline.git#egg=django-pipeline
-e git://github.com/benjaoming/django-wiki.git@02275fb4#egg=django-wiki
-e git://github.com/benjaoming/django-wiki.git@63003aa#egg=django-wiki
-e git://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev
-e common/lib/capa
-e common/lib/xmodule
......@@ -2,7 +2,7 @@ django>=1.4,<1.5
pip
numpy
scipy
markdown
Markdown<2.3.0
pygments
lxml
boto
......@@ -43,5 +43,7 @@ django-ses
django-storages
django-threaded-multihost
django-sekizai<0.7
django-mptt>=0.5.3
sorl-thumbnail
networkx
-r repo-requirements.txt
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