diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..72ec77d0e2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "askbot"]
+ path = askbot
+ url = git@github.com:MITx/askbot-devel.git
diff --git a/.pylintrc b/.pylintrc
index 54e2f5c8a9..ce2f2e3b87 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -33,7 +33,7 @@ load-plugins=
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
-#disable=
+disable=E1102,W0142
[REPORTS]
@@ -82,7 +82,7 @@ zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent
+generated-members=REQUEST,acl_users,aq_parent,objects,DoesNotExist,can_read,can_write,get_url,size
[BASIC]
diff --git a/askbot b/askbot
new file mode 160000
index 0000000000..1c3381046c
--- /dev/null
+++ b/askbot
@@ -0,0 +1 @@
+Subproject commit 1c3381046c78e055439ba1c78e0df48410fcc13e
diff --git a/cms/djangoapps/contentstore/__init__.py b/cms/djangoapps/contentstore/__init__.py
deleted file mode 100644
index ef4e31614e..0000000000
--- a/cms/djangoapps/contentstore/__init__.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from xmodule.modulestore.django import modulestore
-from xmodule.modulestore.xml import XMLModuleStore
-import logging
-
-log = logging.getLogger(__name__)
-
-
-def import_from_xml(data_dir, course_dirs=None):
- """
- Import the specified xml data_dir into the django defined modulestore,
- using org and course as the location org and course.
- """
- module_store = XMLModuleStore(
- data_dir,
- default_class='xmodule.raw_module.RawDescriptor',
- eager=True,
- course_dirs=course_dirs
- )
- for module in module_store.modules.itervalues():
-
- # TODO (cpennington): This forces import to overrite the same items.
- # This should in the future create new revisions of the items on import
- try:
- modulestore().create_item(module.location)
- except:
- log.exception('Item already exists at %s' % module.location.url())
- pass
- if 'data' in module.definition:
- modulestore().update_item(module.location, module.definition['data'])
- if 'children' in module.definition:
- modulestore().update_children(module.location, module.definition['children'])
- modulestore().update_metadata(module.location, dict(module.metadata))
-
- return module_store
diff --git a/cms/djangoapps/contentstore/management/commands/import.py b/cms/djangoapps/contentstore/management/commands/import.py
index 75d4e2618c..69aaa35a7d 100644
--- a/cms/djangoapps/contentstore/management/commands/import.py
+++ b/cms/djangoapps/contentstore/management/commands/import.py
@@ -1,9 +1,11 @@
###
-### One-off script for importing courseware form XML format
+### Script for importing courseware from XML format
###
from django.core.management.base import BaseCommand, CommandError
-from contentstore import import_from_xml
+from xmodule.modulestore.xml_importer import import_from_xml
+from xmodule.modulestore.django import modulestore
+
unnamed_modules = 0
@@ -21,4 +23,4 @@ class Command(BaseCommand):
course_dirs = args[1:]
else:
course_dirs = None
- import_from_xml(data_dir, course_dirs)
+ import_from_xml(modulestore(), data_dir, course_dirs)
diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py
index b7c55389b6..429774c91e 100644
--- a/cms/djangoapps/contentstore/tests/tests.py
+++ b/cms/djangoapps/contentstore/tests/tests.py
@@ -12,7 +12,7 @@ from django.contrib.auth.models import User
from xmodule.modulestore.django import modulestore
import xmodule.modulestore.django
from xmodule.modulestore import Location
-from contentstore import import_from_xml
+from xmodule.modulestore.xml_importer import import_from_xml
import copy
@@ -74,7 +74,7 @@ class ContentStoreTestCase(TestCase):
return resp
def _activate_user(self, email):
- '''look up the user's activation key in the db, then hit the activate view.
+ '''Look up the activation key for the user, then hit the activate view.
No error checking'''
activation_key = registration(email).activation_key
@@ -102,7 +102,7 @@ class AuthTestCase(ContentStoreTestCase):
resp = self.client.get(url)
self.assertEqual(resp.status_code, expected)
return resp
-
+
def test_public_pages_load(self):
"""Make sure pages that don't require login load without error."""
pages = (
@@ -196,7 +196,7 @@ class EditTestCase(ContentStoreTestCase):
xmodule.modulestore.django.modulestore().collection.drop()
def check_edit_item(self, test_course_name):
- import_from_xml('common/test/data/', test_course_name)
+ import_from_xml(modulestore(), 'common/test/data/', [test_course_name])
for descriptor in modulestore().get_items(Location(None, None, None, None, None)):
print "Checking ", descriptor.location.url()
diff --git a/cms/djangoapps/github_sync/__init__.py b/cms/djangoapps/github_sync/__init__.py
index 149b92670a..e3215cbec1 100644
--- a/cms/djangoapps/github_sync/__init__.py
+++ b/cms/djangoapps/github_sync/__init__.py
@@ -5,35 +5,53 @@ from django.conf import settings
from fs.osfs import OSFS
from git import Repo, PushInfo
-from contentstore import import_from_xml
-from xmodule.modulestore import Location
+from xmodule.modulestore.xml_importer import import_from_xml
+from xmodule.modulestore.django import modulestore
+from collections import namedtuple
-from .exceptions import GithubSyncError
+from .exceptions import GithubSyncError, InvalidRepo
log = logging.getLogger(__name__)
+RepoSettings = namedtuple('RepoSettings', 'path branch origin')
+
+
+def sync_all_with_github():
+ """
+ Sync all defined repositories from github
+ """
+ for repo_name in settings.REPOS:
+ sync_with_github(load_repo_settings(repo_name))
+
+
+def sync_with_github(repo_settings):
+ """
+ Sync specified repository from github
+
+ repo_settings: A RepoSettings defining which repo to sync
+ """
+ revision, course = import_from_github(repo_settings)
+ export_to_github(course, "Changes from cms import of revision %s" % revision, "CMS ")
+
def setup_repo(repo_settings):
"""
Reset the local github repo specified by repo_settings
- repo_settings is a dictionary with the following keys:
- path: file system path to the local git repo
- branch: name of the branch to track on github
- origin: git url for the repository to track
+ repo_settings (RepoSettings): The settings for the repo to reset
"""
- course_dir = repo_settings['path']
+ course_dir = repo_settings.path
repo_path = settings.GITHUB_REPO_ROOT / course_dir
if not os.path.isdir(repo_path):
- Repo.clone_from(repo_settings['origin'], repo_path)
+ Repo.clone_from(repo_settings.origin, repo_path)
git_repo = Repo(repo_path)
origin = git_repo.remotes.origin
origin.fetch()
# Do a hard reset to the remote branch so that we have a clean import
- git_repo.git.checkout(repo_settings['branch'])
+ git_repo.git.checkout(repo_settings.branch)
return git_repo
@@ -42,21 +60,22 @@ def load_repo_settings(course_dir):
"""
Returns the repo_settings for the course stored in course_dir
"""
- for repo_settings in settings.REPOS.values():
- if repo_settings['path'] == course_dir:
- return repo_settings
- raise InvalidRepo(course_dir)
+ if course_dir not in settings.REPOS:
+ raise InvalidRepo(course_dir)
+
+ return RepoSettings(course_dir, **settings.REPOS[course_dir])
def import_from_github(repo_settings):
"""
Imports data into the modulestore based on the XML stored on github
"""
- course_dir = repo_settings['path']
+ course_dir = repo_settings.path
git_repo = setup_repo(repo_settings)
- git_repo.head.reset('origin/%s' % repo_settings['branch'], index=True, working_tree=True)
+ git_repo.head.reset('origin/%s' % repo_settings.branch, index=True, working_tree=True)
- module_store = import_from_xml(settings.GITHUB_REPO_ROOT, course_dirs=[course_dir])
+ module_store = import_from_xml(modulestore(),
+ settings.GITHUB_REPO_ROOT, course_dirs=[course_dir])
return git_repo.head.commit.hexsha, module_store.courses[course_dir]
diff --git a/cms/djangoapps/github_sync/exceptions.py b/cms/djangoapps/github_sync/exceptions.py
index 9097ffc2a6..1fe8d1d73e 100644
--- a/cms/djangoapps/github_sync/exceptions.py
+++ b/cms/djangoapps/github_sync/exceptions.py
@@ -1,2 +1,6 @@
class GithubSyncError(Exception):
pass
+
+
+class InvalidRepo(Exception):
+ pass
diff --git a/cms/djangoapps/github_sync/management/__init__.py b/cms/djangoapps/github_sync/management/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/cms/djangoapps/github_sync/management/commands/__init__.py b/cms/djangoapps/github_sync/management/commands/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/cms/djangoapps/github_sync/management/commands/sync_with_github.py b/cms/djangoapps/github_sync/management/commands/sync_with_github.py
new file mode 100644
index 0000000000..4383871df3
--- /dev/null
+++ b/cms/djangoapps/github_sync/management/commands/sync_with_github.py
@@ -0,0 +1,14 @@
+###
+### Script for syncing CMS with defined github repos
+###
+
+from django.core.management.base import NoArgsCommand
+from github_sync import sync_all_with_github
+
+
+class Command(NoArgsCommand):
+ help = \
+'''Sync the CMS with the defined github repos'''
+
+ def handle_noargs(self, **options):
+ sync_all_with_github()
diff --git a/cms/djangoapps/github_sync/tests/__init__.py b/cms/djangoapps/github_sync/tests/__init__.py
index c95d538030..581ac3cb25 100644
--- a/cms/djangoapps/github_sync/tests/__init__.py
+++ b/cms/djangoapps/github_sync/tests/__init__.py
@@ -1,14 +1,17 @@
from django.test import TestCase
from path import path
import shutil
-import os
-from github_sync import import_from_github, export_to_github
+from github_sync import (
+ import_from_github, export_to_github, load_repo_settings,
+ sync_all_with_github, sync_with_github
+)
from git import Repo
from django.conf import settings
from xmodule.modulestore.django import modulestore
from xmodule.modulestore import Location
from override_settings import override_settings
from github_sync.exceptions import GithubSyncError
+from mock import patch, Mock
REPO_DIR = settings.GITHUB_REPO_ROOT / 'local_repo'
WORKING_DIR = path(settings.TEST_ROOT)
@@ -16,8 +19,7 @@ REMOTE_DIR = WORKING_DIR / 'remote_repo'
@override_settings(REPOS={
- 'local': {
- 'path': 'local_repo',
+ 'local_repo': {
'origin': REMOTE_DIR,
'branch': 'master',
}
@@ -40,7 +42,7 @@ class GithubSyncTestCase(TestCase):
remote.git.commit(m='Initial commit')
remote.git.config("receive.denyCurrentBranch", "ignore")
- self.import_revision, self.import_course = import_from_github(settings.REPOS['local'])
+ self.import_revision, self.import_course = import_from_github(load_repo_settings('local_repo'))
def tearDown(self):
self.cleanup()
@@ -57,10 +59,23 @@ class GithubSyncTestCase(TestCase):
"""
self.assertEquals('Toy Course', self.import_course.metadata['display_name'])
self.assertIn(
- Location('i4x://edx/local_repo/chapter/Overview'),
+ Location('i4x://edX/toy/chapter/Overview'),
[child.location for child in self.import_course.get_children()])
self.assertEquals(1, len(self.import_course.get_children()))
+ @patch('github_sync.sync_with_github')
+ def test_sync_all_with_github(self, sync_with_github):
+ sync_all_with_github()
+ sync_with_github.assert_called_with(load_repo_settings('local_repo'))
+
+ def test_sync_with_github(self):
+ with patch('github_sync.import_from_github', Mock(return_value=(Mock(), Mock()))) as import_from_github:
+ with patch('github_sync.export_to_github') as export_to_github:
+ settings = load_repo_settings('local_repo')
+ sync_with_github(settings)
+ import_from_github.assert_called_with(settings)
+ export_to_github.assert_called
+
@override_settings(MITX_FEATURES={'GITHUB_PUSH': False})
def test_export_no_pash(self):
"""
diff --git a/cms/djangoapps/github_sync/tests/test_views.py b/cms/djangoapps/github_sync/tests/test_views.py
index f46e7f7db3..212d707340 100644
--- a/cms/djangoapps/github_sync/tests/test_views.py
+++ b/cms/djangoapps/github_sync/tests/test_views.py
@@ -1,52 +1,43 @@
import json
from django.test.client import Client
from django.test import TestCase
-from mock import patch, Mock
+from mock import patch
from override_settings import override_settings
-from django.conf import settings
+from github_sync import load_repo_settings
-@override_settings(REPOS={'repo': {'path': 'path', 'branch': 'branch'}})
+@override_settings(REPOS={'repo': {'branch': 'branch', 'origin': 'origin'}})
class PostReceiveTestCase(TestCase):
def setUp(self):
self.client = Client()
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github')
- def test_non_branch(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_non_branch(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/tags/foo'})
})
- self.assertFalse(import_from_github.called)
- self.assertFalse(export_to_github.called)
+ self.assertFalse(sync_with_github.called)
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github')
- def test_non_watched_repo(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_non_watched_repo(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/heads/branch',
'repository': {'name': 'bad_repo'}})
})
- self.assertFalse(import_from_github.called)
- self.assertFalse(export_to_github.called)
+ self.assertFalse(sync_with_github.called)
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github')
- def test_non_tracked_branch(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_non_tracked_branch(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/heads/non_branch',
'repository': {'name': 'repo'}})
})
- self.assertFalse(import_from_github.called)
- self.assertFalse(export_to_github.called)
+ self.assertFalse(sync_with_github.called)
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github', return_value=(Mock(), Mock()))
- def test_tracked_branch(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_tracked_branch(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/heads/branch',
'repository': {'name': 'repo'}})
})
- import_from_github.assert_called_with(settings.REPOS['repo'])
- mock_revision, mock_course = import_from_github.return_value
- export_to_github.assert_called_with(mock_course, 'path', "Changes from cms import of revision %s" % mock_revision)
+ sync_with_github.assert_called_with(load_repo_settings('repo'))
diff --git a/cms/djangoapps/github_sync/views.py b/cms/djangoapps/github_sync/views.py
index e4cae6cad8..941d50f986 100644
--- a/cms/djangoapps/github_sync/views.py
+++ b/cms/djangoapps/github_sync/views.py
@@ -5,7 +5,7 @@ from django.http import HttpResponse
from django.conf import settings
from django_future.csrf import csrf_exempt
-from . import import_from_github, export_to_github
+from . import sync_with_github, load_repo_settings
log = logging.getLogger()
@@ -40,13 +40,12 @@ def github_post_receive(request):
log.info('No repository matching %s found' % repo_name)
return HttpResponse('No Repo Found')
- repo = settings.REPOS[repo_name]
+ repo = load_repo_settings(repo_name)
- if repo['branch'] != branch_name:
+ if repo.branch != branch_name:
log.info('Ignoring changes to non-tracked branch %s in repo %s' % (branch_name, repo_name))
return HttpResponse('Ignoring non-tracked branch')
- revision, course = import_from_github(repo)
- export_to_github(course, repo['path'], "Changes from cms import of revision %s" % revision)
+ sync_with_github(repo)
return HttpResponse('Push received')
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
new file mode 100644
index 0000000000..f03e10c9b1
--- /dev/null
+++ b/cms/envs/aws.py
@@ -0,0 +1,48 @@
+"""
+This is the default template for our main set of AWS servers.
+"""
+import json
+
+from .logsettings import get_logger_config
+from .common import *
+
+############################### ALWAYS THE SAME ################################
+DEBUG = False
+TEMPLATE_DEBUG = False
+
+EMAIL_BACKEND = 'django_ses.SESBackend'
+SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
+DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
+
+########################### NON-SECURE ENV CONFIG ##############################
+# Things like server locations, ports, etc.
+with open(ENV_ROOT / "cms.env.json") as env_file:
+ ENV_TOKENS = json.load(env_file)
+
+SITE_NAME = ENV_TOKENS['SITE_NAME']
+
+LOG_DIR = ENV_TOKENS['LOG_DIR']
+
+CACHES = ENV_TOKENS['CACHES']
+
+for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
+ MITX_FEATURES[feature] = value
+
+LOGGING = get_logger_config(LOG_DIR,
+ logging_env=ENV_TOKENS['LOGGING_ENV'],
+ syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
+ debug=False)
+
+with open(ENV_ROOT / "repos.json") as repos_file:
+ REPOS = json.load(repos_file)
+
+
+############################## SECURE AUTH ITEMS ###############################
+# Secret things: passwords, access keys, etc.
+with open(ENV_ROOT / "cms.auth.json") as auth_file:
+ AUTH_TOKENS = json.load(auth_file)
+
+AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"]
+AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"]
+DATABASES = AUTH_TOKENS['DATABASES']
+MODULESTORE = AUTH_TOKENS['MODULESTORE']
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 582cb75abf..3f8f4440c5 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -243,7 +243,7 @@ with open(module_styles_path, 'w') as module_styles:
PIPELINE_CSS = {
'base-style': {
'source_filenames': ['sass/base-style.scss'],
- 'output_filename': 'css/base-style.css',
+ 'output_filename': 'css/cms-base-style.css',
},
}
@@ -260,15 +260,15 @@ PIPELINE_JS = {
for pth
in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')
],
- 'output_filename': 'js/application.js',
+ 'output_filename': 'js/cms-application.js',
},
'module-js': {
'source_filenames': module_js_sources,
- 'output_filename': 'js/modules.js',
+ 'output_filename': 'js/cms-modules.js',
},
'spec': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
- 'output_filename': 'js/spec.js'
+ 'output_filename': 'js/cms-spec.js'
}
}
@@ -309,6 +309,7 @@ INSTALLED_APPS = (
# For CMS
'contentstore',
+ 'github_sync',
'student', # misleading name due to sharing with lms
# For asset pipelining
diff --git a/cms/envs/dev.py b/cms/envs/dev.py
index dd12ce5770..b0729ba885 100644
--- a/cms/envs/dev.py
+++ b/cms/envs/dev.py
@@ -32,38 +32,23 @@ DATABASES = {
REPOS = {
'edx4edx': {
- 'path': "edx4edx",
- 'org': 'edx',
- 'course': 'edx4edx',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/edx4edx.git',
},
- '6002x-fall-2012': {
- 'path': '6002x-fall-2012',
- 'org': 'mit.edu',
- 'course': '6.002x',
- 'branch': 'for_cms',
+ 'content-mit-6002x': {
+ 'branch': 'master',
'origin': 'git@github.com:MITx/6002x-fall-2012.git',
},
'6.00x': {
- 'path': '6.00x',
- 'org': 'mit.edu',
- 'course': '6.00x',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/6.00x.git',
},
'7.00x': {
- 'path': '7.00x',
- 'org': 'mit.edu',
- 'course': '7.00x',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/7.00x.git',
},
'3.091x': {
- 'path': '3.091x',
- 'org': 'mit.edu',
- 'course': '3.091x',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/3.091x.git',
},
}
diff --git a/cms/envs/logsettings.py b/cms/envs/logsettings.py
new file mode 100644
index 0000000000..31130e33c6
--- /dev/null
+++ b/cms/envs/logsettings.py
@@ -0,0 +1,95 @@
+import os
+import os.path
+import platform
+import sys
+
+def get_logger_config(log_dir,
+ logging_env="no_env",
+ tracking_filename=None,
+ syslog_addr=None,
+ debug=False):
+ """Return the appropriate logging config dictionary. You should assign the
+ result of this to the LOGGING var in your settings. The reason it's done
+ this way instead of registering directly is because I didn't want to worry
+ about resetting the logging state if this is called multiple times when
+ settings are extended."""
+
+ # If we're given an explicit place to put tracking logs, we do that (say for
+ # debugging). However, logging is not safe for multiple processes hitting
+ # the same file. So if it's left blank, we dynamically create the filename
+ # based on the PID of this worker process.
+ if tracking_filename:
+ tracking_file_loc = os.path.join(log_dir, tracking_filename)
+ else:
+ pid = os.getpid() # So we can log which process is creating the log
+ tracking_file_loc = os.path.join(log_dir, "tracking_{0}.log".format(pid))
+
+ hostname = platform.node().split(".")[0]
+ syslog_format = ("[%(name)s][env:{logging_env}] %(levelname)s [{hostname} " +
+ " %(process)d] [%(filename)s:%(lineno)d] - %(message)s").format(
+ logging_env=logging_env, hostname=hostname)
+
+ handlers = ['console'] if debug else ['console', 'syslogger', 'newrelic']
+
+ return {
+ 'version': 1,
+ 'formatters' : {
+ 'standard' : {
+ 'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
+ },
+ 'syslog_format' : { 'format' : syslog_format },
+ 'raw' : { 'format' : '%(message)s' },
+ },
+ 'handlers' : {
+ 'console' : {
+ 'level' : 'DEBUG' if debug else 'INFO',
+ 'class' : 'logging.StreamHandler',
+ 'formatter' : 'standard',
+ 'stream' : sys.stdout,
+ },
+ 'syslogger' : {
+ 'level' : 'INFO',
+ 'class' : 'logging.handlers.SysLogHandler',
+ 'address' : syslog_addr,
+ 'formatter' : 'syslog_format',
+ },
+ 'tracking' : {
+ 'level' : 'DEBUG',
+ 'class' : 'logging.handlers.WatchedFileHandler',
+ 'filename' : tracking_file_loc,
+ 'formatter' : 'raw',
+ },
+ 'newrelic' : {
+ 'level': 'ERROR',
+ 'class': 'newrelic_logging.NewRelicHandler',
+ 'formatter': 'raw',
+ }
+ },
+ 'loggers' : {
+ 'django' : {
+ 'handlers' : handlers,
+ 'propagate' : True,
+ 'level' : 'INFO'
+ },
+ 'tracking' : {
+ 'handlers' : ['tracking'],
+ 'level' : 'DEBUG',
+ 'propagate' : False,
+ },
+ '' : {
+ 'handlers' : handlers,
+ 'level' : 'DEBUG',
+ 'propagate' : False
+ },
+ 'mitx' : {
+ 'handlers' : handlers,
+ 'level' : 'DEBUG',
+ 'propagate' : False
+ },
+ 'keyedcache' : {
+ 'handlers' : handlers,
+ 'level' : 'DEBUG',
+ 'propagate' : False
+ },
+ }
+ }
diff --git a/cms/static/img/content-types/module.png b/cms/static/img/content-types/module.png
new file mode 100644
index 0000000000..643c12d1d9
Binary files /dev/null and b/cms/static/img/content-types/module.png differ
diff --git a/cms/static/img/menu.png b/cms/static/img/menu.png
new file mode 100644
index 0000000000..7449b34c1c
Binary files /dev/null and b/cms/static/img/menu.png differ
diff --git a/cms/static/img/noise.png b/cms/static/img/noise.png
new file mode 100644
index 0000000000..8fa5168293
Binary files /dev/null and b/cms/static/img/noise.png differ
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index 05014dbb7e..cad315f6e4 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -5,7 +5,7 @@ $body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida
$body-font-size: 14px;
$body-line-height: 20px;
-$light-blue: #f0f8fa;
+$light-blue: #f0f7fd;
$dark-blue: #50545c;
$bright-blue: #3c8ebf;
$orange: #f96e5b;
@@ -13,6 +13,14 @@ $yellow: #fff8af;
$cream: #F6EFD4;
$mit-red: #933;
+@mixin hide-text {
+ background-color: transparent;
+ border: 0;
+ color: transparent;
+ font: 0/0 a;
+ text-shadow: none;
+}
+
// Base html styles
html {
height: 100%;
@@ -34,14 +42,18 @@ input {
button, input[type="submit"], .button {
background-color: $orange;
- border: 0;
+ border: 1px solid darken($orange, 15%);
+ @include border-radius(4px);
+ @include box-shadow(inset 0 0 0 1px adjust-hue($orange, 20%), 0 1px 0 #fff);
color: #fff;
font-weight: bold;
- padding: 8px 10px;
+ @include linear-gradient(adjust-hue($orange, 8%), $orange);
+ padding: 6px 20px;
+ text-shadow: 0 1px 0 darken($orange, 10%);
-webkit-font-smoothing: antialiased;
- &:hover {
- background-color: shade($orange, 10%);
+ &:hover, &:focus {
+ @include box-shadow(inset 0 0 6px 1px adjust-hue($orange, 30%));
}
}
@@ -122,10 +134,10 @@ textarea {
}
}
-.wip {
- outline: 1px solid #f00 !important;
- position: relative;
-}
+// .wip {
+// outline: 1px solid #f00 !important;
+// position: relative;
+// }
.hidden {
display: none;
diff --git a/cms/static/sass/_calendar.scss b/cms/static/sass/_calendar.scss
index 4070766617..35609b2d56 100644
--- a/cms/static/sass/_calendar.scss
+++ b/cms/static/sass/_calendar.scss
@@ -1,13 +1,15 @@
section.cal {
@include box-sizing(border-box);
@include clearfix;
- padding: 25px;
+ padding: 20px;
> header {
+ display: none;
@include clearfix;
margin-bottom: 10px;
opacity: .4;
@include transition;
+ text-shadow: 0 1px 0 #fff;
&:hover {
opacity: 1;
@@ -70,12 +72,15 @@ section.cal {
ol {
list-style: none;
@include clearfix;
- border-left: 1px solid lighten($dark-blue, 40%);
- border-top: 1px solid lighten($dark-blue, 40%);
+ border: 1px solid lighten( $dark-blue , 30% );
+ background: #FFF;
width: 100%;
@include box-sizing(border-box);
margin: 0;
padding: 0;
+ @include box-shadow(0 0 5px lighten($dark-blue, 45%));
+ @include border-radius(3px);
+ overflow: hidden;
> li {
border-right: 1px solid lighten($dark-blue, 40%);
@@ -84,6 +89,7 @@ section.cal {
float: left;
width: flex-grid(3) + ((flex-gutter() * 3) / 4);
background-color: $light-blue;
+ @include box-shadow(inset 0 0 0 1px lighten($light-blue, 8%));
&:hover {
li.create-module {
@@ -91,6 +97,10 @@ section.cal {
}
}
+ &:nth-child(4n) {
+ border-right: 0;
+ }
+
header {
border-bottom: 1px solid lighten($dark-blue, 40%);
@include box-shadow(0 2px 2px $light-blue);
@@ -128,6 +138,7 @@ section.cal {
color: #888;
border-bottom: 0;
font-size: 12px;
+ @include box-shadow(none);
}
}
}
@@ -138,9 +149,11 @@ section.cal {
padding: 0;
li {
- border-bottom: 1px solid darken($light-blue, 8%);
- position: relative;
+ border-bottom: 1px solid darken($light-blue, 6%);
+ // @include box-shadow(0 1px 0 lighten($light-blue, 4%));
overflow: hidden;
+ position: relative;
+ text-shadow: 0 1px 0 #fff;
&:hover {
background-color: lighten($yellow, 14%);
@@ -314,16 +327,13 @@ section.cal {
@include box-sizing(border-box);
opacity: .4;
@include transition();
- background: darken($light-blue, 2%);
&:hover {
opacity: 1;
width: flex-grid(5) + flex-gutter();
- background-color: transparent;
+ section.main-content {
width: flex-grid(7);
- opacity: .6;
}
}
@@ -340,6 +350,7 @@ section.cal {
display: block;
li {
+
ul {
display: inline;
}
@@ -351,6 +362,7 @@ section.cal {
li {
@include box-sizing(border-box);
width: 100%;
+ border-right: 0;
&.create-module {
display: none;
diff --git a/cms/static/sass/_content-types.scss b/cms/static/sass/_content-types.scss
index 587646fb39..00af06d5ad 100644
--- a/cms/static/sass/_content-types.scss
+++ b/cms/static/sass/_content-types.scss
@@ -53,3 +53,13 @@
@extend .content-type;
background-image: url('../img/content-types/chapter.png');
}
+
+.module a:first-child {
+ @extend .content-type;
+ background-image: url('/static/img/content-types/module.png');
+}
+
+.module a:first-child {
+ @extend .content-type;
+ background-image: url('/static/img/content-types/module.png');
+}
diff --git a/cms/static/sass/_index.scss b/cms/static/sass/_index.scss
new file mode 100644
index 0000000000..a3e210b558
--- /dev/null
+++ b/cms/static/sass/_index.scss
@@ -0,0 +1,80 @@
+body.index {
+ > header {
+ display: none;
+ }
+
+ > h1 {
+ font-weight: 300;
+ color: lighten($dark-blue, 40%);
+ text-shadow: 0 1px 0 #fff;
+ -webkit-font-smoothing: antialiased;
+ max-width: 600px;
+ text-align: center;
+ margin: 80px auto 30px;
+ }
+
+ section.main-container {
+ border-right: 3px;
+ background: #FFF;
+ max-width: 600px;
+ margin: 0 auto;
+ display: block;
+ @include box-sizing(border-box);
+ border: 1px solid lighten( $dark-blue , 30% );
+ @include border-radius(3px);
+ overflow: hidden;
+ @include bounce-in-animation(.8s);
+
+ header {
+ border-bottom: 1px solid lighten($dark-blue, 50%);
+ @include linear-gradient(#fff, lighten($dark-blue, 62%));
+ @include clearfix();
+ @include box-shadow( 0 2px 0 $light-blue, inset 0 -1px 0 #fff);
+ text-shadow: 0 1px 0 #fff;
+
+ h1 {
+ font-size: 14px;
+ padding: 8px 20px;
+ float: left;
+ color: $dark-blue;
+ margin: 0;
+ }
+
+ a {
+ float: right;
+ padding: 8px 20px;
+ border-left: 1px solid lighten($dark-blue, 50%);
+ @include box-shadow( inset -1px 0 0 #fff);
+ font-weight: bold;
+ font-size: 22px;
+ line-height: 1;
+ color: $dark-blue;
+ }
+ }
+
+ ol {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+
+ li {
+ border-bottom: 1px solid lighten($dark-blue, 50%);
+
+ a {
+ display: block;
+ padding: 10px 20px;
+
+ &:hover {
+ color: $dark-blue;
+ background: lighten($yellow, 10%);
+ text-shadow: 0 1px 0 #fff;
+ }
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+ }
+ }
+}
diff --git a/cms/static/sass/_keyframes.scss b/cms/static/sass/_keyframes.scss
new file mode 100644
index 0000000000..7661f18980
--- /dev/null
+++ b/cms/static/sass/_keyframes.scss
@@ -0,0 +1,27 @@
+@mixin bounce-in {
+ 0% {
+ opacity: 0;
+ @include transform(scale(.3));
+ }
+
+ 50% {
+ opacity: 1;
+ @include transform(scale(1.05));
+ }
+
+ 100% {
+ @include transform(scale(1));
+ }
+}
+
+@-moz-keyframes bounce-in { @include bounce-in(); }
+@-webkit-keyframes bounce-in { @include bounce-in(); }
+@-o-keyframes bounce-in { @include bounce-in(); }
+@keyframes bounce-in { @include bounce-in();}
+
+@mixin bounce-in-animation($duration, $timing: ease-in-out) {
+ @include animation-name(bounce-in);
+ @include animation-duration($duration);
+ @include animation-timing-function($timing);
+ @include animation-fill-mode(both);
+}
diff --git a/cms/static/sass/_layout.scss b/cms/static/sass/_layout.scss
index f4c9f63ea6..43308a973c 100644
--- a/cms/static/sass/_layout.scss
+++ b/cms/static/sass/_layout.scss
@@ -2,6 +2,8 @@ body {
@include clearfix();
height: 100%;
font: 14px $body-font-family;
+ background-color: lighten($dark-blue, 62%);
+ background-image: url('/static/img/noise.png');
> section {
display: table;
@@ -11,28 +13,53 @@ body {
> header {
background: $dark-blue;
+ @include background-image(url('/static/img/noise.png'), linear-gradient(lighten($dark-blue, 10%), $dark-blue));
+ border-bottom: 1px solid darken($dark-blue, 15%);
+ @include box-shadow(inset 0 -1px 0 lighten($dark-blue, 10%));
+ @include box-sizing(border-box);
color: #fff;
display: block;
float: none;
- padding: 8px 25px;
+ padding: 0 20px;
+ text-shadow: 0 -1px 0 darken($dark-blue, 15%);
width: 100%;
- @include box-sizing(border-box);
- -webkit-font-smoothing: antialiased;
nav {
@include clearfix;
- h2 {
- font-size: 14px;
- text-transform: uppercase;
+ > a {
+ @include hide-text;
+ background: url('/static/img/menu.png') 0 center no-repeat;
+ border-right: 1px solid darken($dark-blue, 10%);
+ @include box-shadow(1px 0 0 lighten($dark-blue, 10%));
+ display: block;
float: left;
- margin: 0 15px 0 0;
+ height: 19px;
+ padding: 8px 10px 8px 0;
+ width: 14px;
+
+ &:hover, &:focus {
+ opacity: .7;
+ }
+ }
+
+ h2 {
+ border-right: 1px solid darken($dark-blue, 10%);
+ @include box-shadow(1px 0 0 lighten($dark-blue, 10%));
+ float: left;
+ font-size: 14px;
+ margin: 0;
+ text-transform: uppercase;
+ -webkit-font-smoothing: antialiased;
a {
color: #fff;
+ padding: 8px 20px;
+ display: block;
&:hover {
- color: rgba(#fff, .6);
+ background-color: rgba(darken($dark-blue, 15%), .5);
+ color: $yellow;
}
}
}
@@ -48,21 +75,35 @@ body {
ul {
float: left;
margin: 0;
+ padding: 0;
+ @include clearfix;
&.user-nav {
float: right;
+ border-left: 1px solid darken($dark-blue, 10%);
}
li {
- @include inline-block();
+ border-right: 1px solid darken($dark-blue, 10%);
+ float: left;
+ @include box-shadow(1px 0 0 lighten($dark-blue, 10%));
a {
- padding: 8px 10px;
+ padding: 8px 20px;
display: block;
- margin: -8px 0;
&:hover {
- background-color: darken($dark-blue, 15%);
+ background-color: rgba(darken($dark-blue, 15%), .5);
+ color: $yellow;
+ }
+
+ &.new-module {
+ &:before {
+ @include inline-block;
+ content: "+";
+ font-weight: bold;
+ margin-right: 10px;
+ }
}
}
}
@@ -76,8 +117,9 @@ body {
@include box-sizing(border-box);
width: flex-grid(9) + flex-gutter();
float: left;
- @include box-shadow( -2px 0 0 darken($light-blue, 3%));
+ @include box-shadow( -2px 0 0 lighten($dark-blue, 55%));
@include transition();
+ background: #FFF;
}
}
}
diff --git a/cms/static/sass/_section.scss b/cms/static/sass/_section.scss
index fa08e02901..97818326be 100644
--- a/cms/static/sass/_section.scss
+++ b/cms/static/sass/_section.scss
@@ -1,6 +1,7 @@
section#unit-wrapper {
section.filters {
@include clearfix;
+ display: none;
opacity: .4;
margin-bottom: 10px;
@include transition;
@@ -52,22 +53,22 @@ section#unit-wrapper {
display: table;
border: 1px solid lighten($dark-blue, 40%);
width: 100%;
+ @include border-radius(3px);
+ @include box-shadow(0 0 4px lighten($dark-blue, 50%));
section {
header {
background: #fff;
padding: 6px;
border-bottom: 1px solid lighten($dark-blue, 60%);
- border-top: 1px solid lighten($dark-blue, 60%);
- margin-top: -1px;
@include clearfix;
h2 {
color: $bright-blue;
- float: left;
- font-size: 12px;
+ // float: left;
+ font-size: 14px;
letter-spacing: 1px;
- line-height: 19px;
+ // line-height: 20px;
text-transform: uppercase;
margin: 0;
}
@@ -172,7 +173,6 @@ section#unit-wrapper {
padding: 0;
li {
- border-bottom: 1px solid darken($light-blue, 8%);
background: $light-blue;
&:last-child {
@@ -181,6 +181,7 @@ section#unit-wrapper {
&.new-module a {
background-color: darken($light-blue, 2%);
+ border-bottom: 1px solid darken($light-blue, 8%);
&:hover {
background-color: lighten($yellow, 10%);
@@ -199,6 +200,7 @@ section#unit-wrapper {
li {
padding: 6px;
border-collapse: collapse;
+ border-bottom: 1px solid darken($light-blue, 8%);
position: relative;
&:last-child {
diff --git a/cms/static/sass/_unit.scss b/cms/static/sass/_unit.scss
index d8613be3c2..0ab0d1064d 100644
--- a/cms/static/sass/_unit.scss
+++ b/cms/static/sass/_unit.scss
@@ -1,19 +1,19 @@
section#unit-wrapper {
> header {
- border-bottom: 2px solid $dark-blue;
+ border-bottom: 1px solid lighten($dark-blue, 50%);
+ @include linear-gradient(#fff, lighten($dark-blue, 62%));
@include clearfix();
- @include box-shadow( 0 2px 0 darken($light-blue, 3%));
- padding: 6px 20px;
+ @include box-shadow( 0 2px 0 $light-blue, inset 0 -1px 0 #fff);
+ text-shadow: 0 1px 0 #fff;
section {
float: left;
+ padding: 10px 20px;
h1 {
- font-size: 16px;
- text-transform: uppercase;
- letter-spacing: 1px;
+ font-size: 18px;
@include inline-block();
- color: $bright-blue;
+ color: $dark-blue;
margin: 0;
}
@@ -22,32 +22,41 @@ section#unit-wrapper {
margin: 0;
a {
- text-indent: -9999px;
@include inline-block();
- width: 1px;
- height: 100%;
+ font-size: 12px;
}
}
}
div {
- float: right;
+ @include clearfix;
color: #666;
+ float: right;
+ padding: 6px 20px;
a {
- display: block;
@include inline-block;
- &.cancel {
- margin-right: 20px;
- font-style: italic;
- font-size: 12px;
- }
+ &.cancel {
+ margin-right: 20px;
+ font-style: italic;
+ font-size: 12px;
+ padding: 6px 0;
+ }
- &.save-update {
- @extend .button;
- margin: -6px -21px -6px 0;
- }
+ &.save-update {
+ padding: 6px 20px;
+ @include border-radius(3px);
+ border: 1px solid lighten($dark-blue, 40%);
+ @include box-shadow(inset 0 0 0 1px #fff);
+ color: $dark-blue;
+ @include linear-gradient(lighten($dark-blue, 60%), lighten($dark-blue, 55%));
+
+ &:hover, &:focus {
+ @include linear-gradient(lighten($dark-blue, 58%), lighten($dark-blue, 53%));
+ @include box-shadow(inset 0 0 6px 1px #fff);
+ }
+ }
}
}
}
diff --git a/cms/static/sass/base-style.scss b/cms/static/sass/base-style.scss
index 35c02a4758..49a51a59fb 100644
--- a/cms/static/sass/base-style.scss
+++ b/cms/static/sass/base-style.scss
@@ -1,8 +1,9 @@
@import 'bourbon/bourbon';
@import 'vendor/normalize';
+@import 'keyframes';
@import 'base', 'layout', 'content-types';
@import 'calendar';
-@import 'section', 'unit';
+@import 'section', 'unit', 'index';
@import 'module/module-styles.scss';
diff --git a/cms/templates/base.html b/cms/templates/base.html
index 96f881421a..dba7df95b9 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -15,7 +15,7 @@
-
+
<%include file="widgets/header.html"/>
<%include file="courseware_vendor_js.html"/>
diff --git a/cms/templates/course_index.html b/cms/templates/course_index.html
index 92b5cc296c..e490ad7817 100644
--- a/cms/templates/course_index.html
+++ b/cms/templates/course_index.html
@@ -1,5 +1,6 @@
<%inherit file="base.html" />
<%block name="title">Course Manager%block>
+<%include file="widgets/header.html"/>
<%block name="content">
diff --git a/cms/templates/index.html b/cms/templates/index.html
index 2998cb8bd6..6e3cb648ae 100644
--- a/cms/templates/index.html
+++ b/cms/templates/index.html
@@ -1,8 +1,16 @@
<%inherit file="base.html" />
+<%block name="bodyclass">index%block>
<%block name="title">Courses%block>
<%block name="content">
+edX Course Management
+
+
+
%for course, url in courses:
${course}
diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html
index c1c05671fa..c0b9f9e3af 100644
--- a/cms/templates/widgets/header.html
+++ b/cms/templates/widgets/header.html
@@ -1,13 +1,14 @@
<%! from django.core.urlresolvers import reverse %>
-
+ Home
+
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 1644822d5f..eeda9a6b65 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -30,6 +30,7 @@ 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
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -264,14 +265,17 @@ def create_account(request, post_override=None):
for a in ['username', 'email', 'password', 'name']:
if a not in post_vars:
js['value'] = "Error (401 {field}). E-mail us.".format(field=a)
+ js['field'] = a
return HttpResponse(json.dumps(js))
if post_vars.get('honor_code', 'false') != u'true':
js['value'] = "To enroll, you must follow the honor code.".format(field=a)
+ js['field'] = 'honor_code'
return HttpResponse(json.dumps(js))
if post_vars.get('terms_of_service', 'false') != u'true':
js['value'] = "You must accept the terms of service.".format(field=a)
+ js['field'] = 'terms_of_service'
return HttpResponse(json.dumps(js))
# Confirm appropriate fields are there.
@@ -288,18 +292,21 @@ def create_account(request, post_override=None):
'terms_of_service': 'Accepting Terms of Service is required.',
'honor_code': 'Agreeing to the Honor Code is required.'}
js['value'] = error_str[a]
+ js['field'] = a
return HttpResponse(json.dumps(js))
try:
validate_email(post_vars['email'])
except ValidationError:
js['value'] = "Valid e-mail is required.".format(field=a)
+ js['field'] = 'email'
return HttpResponse(json.dumps(js))
try:
validate_slug(post_vars['username'])
except ValidationError:
js['value'] = "Username should only consist of A-Z and 0-9.".format(field=a)
+ js['field'] = 'username'
return HttpResponse(json.dumps(js))
u = User(username=post_vars['username'],
@@ -315,10 +322,12 @@ def create_account(request, post_override=None):
# Figure out the cause of the integrity error
if len(User.objects.filter(username=post_vars['username'])) > 0:
js['value'] = "An account with this username already exists."
+ js['field'] = 'username'
return HttpResponse(json.dumps(js))
if len(User.objects.filter(email=post_vars['email'])) > 0:
js['value'] = "An account with this e-mail already exists."
+ js['field'] = 'email'
return HttpResponse(json.dumps(js))
raise
diff --git a/common/lib/xmodule/xmodule/backcompat_module.py b/common/lib/xmodule/xmodule/backcompat_module.py
index d379ced507..997ad476c4 100644
--- a/common/lib/xmodule/xmodule/backcompat_module.py
+++ b/common/lib/xmodule/xmodule/backcompat_module.py
@@ -5,6 +5,7 @@ from x_module import XModuleDescriptor
from lxml import etree
from functools import wraps
import logging
+import traceback
log = logging.getLogger(__name__)
@@ -12,8 +13,8 @@ log = logging.getLogger(__name__)
def process_includes(fn):
"""
Wraps a XModuleDescriptor.from_xml method, and modifies xml_data to replace
- any immediate child items with the contents of the file that they are
- supposed to include
+ any immediate child items with the contents of the file that they
+ are supposed to include
"""
@wraps(fn)
def from_xml(cls, xml_data, system, org=None, course=None):
@@ -21,23 +22,31 @@ def process_includes(fn):
next_include = xml_object.find('include')
while next_include is not None:
file = next_include.get('file')
- if file is not None:
- try:
- ifp = system.resources_fs.open(file)
- except Exception:
- log.exception('Error in problem xml include: %s' % (etree.tostring(next_include, pretty_print=True)))
- log.exception('Cannot find file %s in %s' % (file, dir))
- raise
- try:
- # read in and convert to XML
- incxml = etree.XML(ifp.read())
- except Exception:
- log.exception('Error in problem xml include: %s' % (etree.tostring(next_include, pretty_print=True)))
- log.exception('Cannot parse XML in %s' % (file))
- raise
+ parent = next_include.getparent()
+
+ if file is None:
+ continue
+
+ try:
+ ifp = system.resources_fs.open(file)
+ # read in and convert to XML
+ incxml = etree.XML(ifp.read())
+
# insert new XML into tree in place of inlcude
- parent = next_include.getparent()
parent.insert(parent.index(next_include), incxml)
+ except Exception:
+ msg = "Error in problem xml include: %s" % (etree.tostring(next_include, pretty_print=True))
+ log.exception(msg)
+ parent = next_include.getparent()
+
+ errorxml = etree.Element('error')
+ messagexml = etree.SubElement(errorxml, 'message')
+ messagexml.text = msg
+ stackxml = etree.SubElement(errorxml, 'stacktrace')
+ stackxml.text = traceback.format_exc()
+
+ # insert error XML in place of include
+ parent.insert(parent.index(next_include), errorxml)
parent.remove(next_include)
next_include = xml_object.find('include')
@@ -50,8 +59,8 @@ class SemanticSectionDescriptor(XModuleDescriptor):
@process_includes
def from_xml(cls, xml_data, system, org=None, course=None):
"""
- Removes sections single child elements in favor of just embedding the child element
-
+ Removes sections with single child elements in favor of just embedding
+ the child element
"""
xml_object = etree.fromstring(xml_data)
@@ -76,7 +85,6 @@ class TranslateCustomTagDescriptor(XModuleDescriptor):
xml_object = etree.fromstring(xml_data)
tag = xml_object.tag
xml_object.tag = 'customtag'
- impl = etree.SubElement(xml_object, 'impl')
- impl.text = tag
+ xml_object.attrib['impl'] = tag
return system.process_xml(etree.tostring(xml_object))
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 1aa1b4c823..2fae8b94e2 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -67,7 +67,8 @@ class ComplexEncoder(json.JSONEncoder):
class CapaModule(XModule):
'''
- An XModule implementing LonCapa format problems, implemented by way of capa.capa_problem.LoncapaProblem
+ An XModule implementing LonCapa format problems, implemented by way of
+ capa.capa_problem.LoncapaProblem
'''
icon_class = 'problem'
@@ -77,8 +78,10 @@ class CapaModule(XModule):
js_module_name = "Problem"
css = {'scss': [resource_string(__name__, 'css/capa/display.scss')]}
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
- XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
+ def __init__(self, system, location, definition, instance_state=None,
+ shared_state=None, **kwargs):
+ XModule.__init__(self, system, location, definition, instance_state,
+ shared_state, **kwargs)
self.attempts = 0
self.max_attempts = None
@@ -133,7 +136,8 @@ class CapaModule(XModule):
seed = None
try:
- self.lcp = LoncapaProblem(self.definition['data'], self.location.html_id(), instance_state, seed=seed, system=self.system)
+ self.lcp = LoncapaProblem(self.definition['data'], self.location.html_id(),
+ instance_state, seed=seed, system=self.system)
except Exception:
msg = 'cannot create LoncapaProblem %s' % self.location.url()
log.exception(msg)
@@ -141,15 +145,20 @@ class CapaModule(XModule):
msg = '%s
' % msg.replace('<', '<')
msg += '
%s
' % traceback.format_exc().replace('<', '<')
# create a dummy problem with error message instead of failing
- problem_text = 'Problem %s has an error: %s ' % (self.location.url(), msg)
- self.lcp = LoncapaProblem(problem_text, self.location.html_id(), instance_state, seed=seed, system=self.system)
+ problem_text = (''
+ 'Problem %s has an error: %s ' %
+ (self.location.url(), msg))
+ self.lcp = LoncapaProblem(
+ problem_text, self.location.html_id(),
+ instance_state, seed=seed, system=self.system)
else:
raise
@property
def rerandomize(self):
"""
- Property accessor that returns self.metadata['rerandomize'] in a canonical form
+ Property accessor that returns self.metadata['rerandomize'] in a
+ canonical form
"""
rerandomize = self.metadata.get('rerandomize', 'always')
if rerandomize in ("", "always", "true"):
@@ -203,7 +212,10 @@ class CapaModule(XModule):
except Exception, err:
if self.system.DEBUG:
log.exception(err)
- msg = '[courseware.capa.capa_module] Failed to generate HTML for problem %s ' % (self.location.url())
+ msg = (
+ '[courseware.capa.capa_module] '
+ 'Failed to generate HTML for problem %s ' %
+ (self.location.url()))
msg += 'Error:
%s ' % str(err).replace('<', '<')
msg += '
%s ' % traceback.format_exc().replace('<', '<')
html = msg
@@ -215,8 +227,8 @@ class CapaModule(XModule):
'weight': self.weight,
}
- # We using strings as truthy values, because the terminology of the check button
- # is context-specific.
+ # We using strings as truthy values, because the terminology of the
+ # check button is context-specific.
check_button = "Grade" if self.max_attempts else "Check"
reset_button = True
save_button = True
@@ -242,7 +254,8 @@ class CapaModule(XModule):
if not self.lcp.done:
reset_button = False
- # We don't need a "save" button if infinite number of attempts and non-randomized
+ # We don't need a "save" button if infinite number of attempts and
+ # non-randomized
if self.max_attempts is None and self.rerandomize != "always":
save_button = False
@@ -517,11 +530,13 @@ class CapaModule(XModule):
self.lcp.do_reset()
if self.rerandomize == "always":
- # reset random number generator seed (note the self.lcp.get_state() in next line)
+ # reset random number generator seed (note the self.lcp.get_state()
+ # in next line)
self.lcp.seed = None
self.lcp = LoncapaProblem(self.definition['data'],
- self.location.html_id(), self.lcp.get_state(), system=self.system)
+ self.location.html_id(), self.lcp.get_state(),
+ system=self.system)
event_info['new_state'] = self.lcp.get_state()
self.system.track_function('reset_problem', event_info)
@@ -537,6 +552,7 @@ class CapaDescriptor(RawDescriptor):
module_class = CapaModule
+ # VS[compat]
# TODO (cpennington): Delete this method once all fall 2012 course are being
# edited in the cms
@classmethod
@@ -545,3 +561,7 @@ class CapaDescriptor(RawDescriptor):
'problems/' + path[8:],
path[8:],
]
+ @classmethod
+ def split_to_file(cls, xml_object):
+ '''Problems always written in their own files'''
+ return True
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index a04324237c..dfac1ac9c6 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -10,6 +10,7 @@ log = logging.getLogger(__name__)
class CourseDescriptor(SequenceDescriptor):
module_class = SequenceModule
+ metadata_attributes = SequenceDescriptor.metadata_attributes + ('org', 'course')
def __init__(self, system, definition=None, **kwargs):
super(CourseDescriptor, self).__init__(system, definition, **kwargs)
@@ -17,23 +18,40 @@ class CourseDescriptor(SequenceDescriptor):
try:
self.start = time.strptime(self.metadata["start"], "%Y-%m-%dT%H:%M")
except KeyError:
- self.start = time.gmtime(0) # The epoch
- log.critical("Course loaded without a start date. " + str(self.id))
- except ValueError, e:
- self.start = time.gmtime(0) # The epoch
- log.critical("Course loaded with a bad start date. " + str(self.id) + " '" + str(e) + "'")
+ self.start = time.gmtime(0) #The epoch
+ log.critical("Course loaded without a start date. %s", self.id)
+ except ValueError as e:
+ self.start = time.gmtime(0) #The epoch
+ log.critical("Course loaded with a bad start date. %s '%s'",
+ self.id, e)
def has_started(self):
return time.gmtime() > self.start
- @classmethod
- def id_to_location(cls, course_id):
+ @staticmethod
+ def id_to_location(course_id):
+ '''Convert the given course_id (org/course/name) to a location object.
+ Throws ValueError if course_id is of the wrong format.
+ '''
org, course, name = course_id.split('/')
return Location('i4x', org, course, 'course', name)
+ @staticmethod
+ def location_to_id(location):
+ '''Convert a location of a course to a course_id. If location category
+ is not "course", raise a ValueError.
+
+ location: something that can be passed to Location
+ '''
+ loc = Location(location)
+ if loc.category != "course":
+ raise ValueError("{0} is not a course location".format(loc))
+ return "/".join([loc.org, loc.course, loc.name])
+
+
@property
def id(self):
- return "/".join([self.location.org, self.location.course, self.location.name])
+ return self.location_to_id(self.location)
@property
def start_date_text(self):
diff --git a/common/lib/xmodule/xmodule/errorhandlers.py b/common/lib/xmodule/xmodule/errorhandlers.py
new file mode 100644
index 0000000000..0f97377b2a
--- /dev/null
+++ b/common/lib/xmodule/xmodule/errorhandlers.py
@@ -0,0 +1,45 @@
+import logging
+import sys
+
+log = logging.getLogger(__name__)
+
+def in_exception_handler():
+ '''Is there an active exception?'''
+ return sys.exc_info() != (None, None, None)
+
+def strict_error_handler(msg, exc_info=None):
+ '''
+ Do not let errors pass. If exc_info is not None, ignore msg, and just
+ re-raise. Otherwise, check if we are in an exception-handling context.
+ If so, re-raise. Otherwise, raise Exception(msg).
+
+ Meant for use in validation, where any errors should trap.
+ '''
+ if exc_info is not None:
+ raise exc_info[0], exc_info[1], exc_info[2]
+
+ if in_exception_handler():
+ raise
+
+ raise Exception(msg)
+
+
+def logging_error_handler(msg, exc_info=None):
+ '''Log all errors, but otherwise let them pass, relying on the caller to
+ workaround.'''
+ if exc_info is not None:
+ log.exception(msg, exc_info=exc_info)
+ return
+
+ if in_exception_handler():
+ log.exception(msg)
+ return
+
+ log.error(msg)
+
+
+def ignore_errors_handler(msg, exc_info=None):
+ '''Ignore all errors, relying on the caller to workaround.
+ Meant for use in the LMS, where an error in one part of the course
+ shouldn't bring down the whole system'''
+ pass
diff --git a/common/lib/xmodule/xmodule/exceptions.py b/common/lib/xmodule/xmodule/exceptions.py
index 9107d9dc4d..3db5ceccde 100644
--- a/common/lib/xmodule/xmodule/exceptions.py
+++ b/common/lib/xmodule/xmodule/exceptions.py
@@ -1,5 +1,6 @@
class InvalidDefinitionError(Exception):
pass
+
class NotFoundError(Exception):
pass
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 97509c6f34..b9bc34aed6 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -12,8 +12,10 @@ class HtmlModule(XModule):
def get_html(self):
return self.html
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
- XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
+ def __init__(self, system, location, definition,
+ instance_state=None, shared_state=None, **kwargs):
+ XModule.__init__(self, system, location, definition,
+ instance_state, shared_state, **kwargs)
self.html = self.definition['data']
@@ -42,3 +44,8 @@ class HtmlDescriptor(RawDescriptor):
def file_to_xml(cls, file_object):
parser = etree.HTMLParser()
return etree.parse(file_object, parser).getroot()
+
+ @classmethod
+ def split_to_file(cls, xml_object):
+ # never include inline html
+ return True
diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee
index b5a41e3da5..4ee8257e36 100644
--- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -31,8 +31,20 @@ class @Problem
else
$.postWithPrefix "#{@url}/problem_get", (response) =>
@el.html(response.html)
+ @executeProblemScripts()
@bind()
+ executeProblemScripts: ->
+ @el.find(".script_placeholder").each (index, placeholder) ->
+ s = $("
-
-Lab 2A: Superposition Experiment
-
-Note: This part of the lab is just to develop your intuition about
-superposition. There are no responses that need to be checked.
-
- Circuits with multiple sources can be hard to analyze as-is. For example, what is the voltage
-between the two terminals on the right of Figure 1?
-
-
-
-Figure 1. Example multi-source circuit
-
-
- We can use superposition to make the analysis much easier.
-The circuit in Figure 1 can be decomposed into two separate
-subcircuits: one involving only the voltage source and one involving only the
-current source. We'll analyze each circuit separately and combine the
-results using superposition. Recall that to decompose a circuit for
-analysis, we'll pick each source in turn and set all the other sources
-to zero (i.e., voltage sources become short circuits and current
-sources become open circuits). The circuit above has two sources, so
-the decomposition produces two subcircuits, as shown in Figure 2.
-
-
-
-
-(a) Subcircuit for analyzing contribution of voltage source
-
-
-(b) Subcircuit for analyzing contribution of current source
-
- Figure 2. Decomposition of Figure 1 into subcircuits
-
-
- Let's use the DC analysis capability of the schematic tool to see superposition
-in action. The sliders below control the resistances of R1, R2, R3 and R4 in all
-the diagrams. As you move the sliders, the schematic tool will adjust the appropriate
-resistance, perform a DC analysis and display the node voltages on the diagrams. Here's
-what you want to observe as you play with the sliders:
-
-
-The voltage for a node in Figure 1 is the sum of the voltages for
-that node in Figures 2(a) and 2(b), just as predicted by
-superposition. (Note that due to round-off in the display of the
-voltages, the sum of the displayed voltages in Figure 2 may only be within
-.01 of the voltages displayed in Figure 1.)
-
-
-
-
-
-
-
-
- R1
-
-
-
-
-
- R2
-
-
-
-
-
- R3
-
-
-
-
-
- R4
-
-
-
-
-
-
-
diff --git a/common/test/data/toy/html/toylab.html b/common/test/data/toy/html/toylab.html
new file mode 100644
index 0000000000..81df84bd63
--- /dev/null
+++ b/common/test/data/toy/html/toylab.html
@@ -0,0 +1,3 @@
+Lab 2A: Superposition Experiment
+
+Isn't the toy course great?
diff --git a/doc/overview.md b/doc/overview.md
index 88ea3bdb5e..36e22e16eb 100644
--- a/doc/overview.md
+++ b/doc/overview.md
@@ -13,17 +13,17 @@ You should be familiar with the following. If you're not, go read some docs...
- css
- git
- mako templates -- we use these instead of django templates, because they support embedding real python.
-
+
## Other relevant terms
- CAPA -- lon-capa.org -- content management system that has defined a standard for online learning and assessment materials. Many of our materials follow this standard.
- - TODO: add more details / link to relevant docs. lon-capa.org is not immediately intuitive.
+ - TODO: add more details / link to relevant docs. lon-capa.org is not immediately intuitive.
- lcp = loncapa problem
## Parts of the system
- - LMS -- Learning Management System. The student-facing parts of the system. Handles student accounts, displaying videos, tutorials, exercies, problems, etc.
+ - LMS -- Learning Management System. The student-facing parts of the system. Handles student accounts, displaying videos, tutorials, exercies, problems, etc.
- CMS -- Course Management System. The instructor-facing parts of the system. Allows instructors to see and modify their course, add lectures, problems, reorder things, etc.
@@ -42,7 +42,7 @@ You should be familiar with the following. If you're not, go read some docs...
## High Level Entities in the code
-### Common libraries
+### Common libraries
- xmodule: generic learning modules. *x* can be sequence, video, template, html,
vertical, capa, etc. These are the things that one puts inside sections
@@ -51,7 +51,7 @@ You should be familiar with the following. If you're not, go read some docs...
- XModuleDescriptor: This defines the problem and all data and UI needed to edit
that problem. It is unaware of any student data, but can be used to retrieve
an XModule, which is aware of that student state.
-
+
- XModule: The XModule is a problem instance that is particular to a student. It knows
how to render itself to html to display the problem, how to score itself,
and how to handle ajax calls from the front end.
@@ -59,19 +59,25 @@ You should be familiar with the following. If you're not, go read some docs...
- Both XModule and XModuleDescriptor take system context parameters. These are named
ModuleSystem and DescriptorSystem respectively. These help isolate the XModules
from any interactions with external resources that they require.
-
+
For instance, the DescriptorSystem has a function to load an XModuleDescriptor
from a Location object, and the ModuleSystem knows how to render things,
track events, and complain about 404s
- - TODO: document the system context interface--it's different in `x_module.XModule.__init__` and in `x_module tests.py` (do this in the code, not here)
+
+ - `course.xml` format. We use python setuptools to connect supported tags with the descriptors that handle them. See `common/lib/xmodule/setup.py`. There are checking and validation tools in `common/validate`.
+
+ - the xml import+export functionality is in `xml_module.py:XmlDescriptor`, which is a mixin class that's used by the actual descriptor classes.
+
+ - There is a distinction between descriptor _definitions_ that stay the same for any use of that descriptor (e.g. here is what a particular problem is), and _metadata_ describing how that descriptor is used (e.g. whether to allow checking of answers, due date, etc). When reading in `from_xml`, the code pulls out the metadata attributes into a separate structure, and puts it back on export.
+
- in `common/lib/xmodule`
-- capa modules -- defines `LoncapaProblem` and many related things.
+- capa modules -- defines `LoncapaProblem` and many related things.
- in `common/lib/capa`
-### LMS
+### LMS
-The LMS is a django site, with root in `lms/`. It runs in many different environments--the settings files are in `lms/envs`.
+The LMS is a django site, with root in `lms/`. It runs in many different environments--the settings files are in `lms/envs`.
- We use the Django Auth system, including the is_staff and is_superuser flags. User profiles and related code lives in `lms/djangoapps/student/`. There is support for groups of students (e.g. 'want emails about future courses', 'have unenrolled', etc) in `lms/djangoapps/student/models.py`.
@@ -79,19 +85,19 @@ The LMS is a django site, with root in `lms/`. It runs in many different enviro
- `lms/djangoapps/courseware/models.py`
- Core rendering path:
- - `lms/urls.py` points to `courseware.views.index`, which gets module info from the course xml file, pulls list of `StudentModule` objects for this user (to avoid multiple db hits).
+ - `lms/urls.py` points to `courseware.views.index`, which gets module info from the course xml file, pulls list of `StudentModule` objects for this user (to avoid multiple db hits).
- Calls `render_accordion` to render the "accordion"--the display of the course structure.
- To render the current module, calls `module_render.py:render_x_module()`, which gets the `StudentModule` instance, and passes the `StudentModule` state and other system context to the module constructor the get an instance of the appropriate module class for this user.
- calls the module's `.get_html()` method. If the module has nested submodules, render_x_module() will be called again for each.
-
+
- ajax calls go to `module_render.py:modx_dispatch()`, which passes it to the module's `handle_ajax()` function, and then updates the grade and state if they changed.
- [This diagram](https://github.com/MITx/mitx/wiki/MITx-Architecture) visually shows how the clients communicate with problems + modules.
-
-- See `lms/urls.py` for the wirings of urls to views.
+
+- See `lms/urls.py` for the wirings of urls to views.
- Tracking: there is support for basic tracking of client-side events in `lms/djangoapps/track`.
@@ -110,7 +116,7 @@ environments, defined in `cms/envs`.
- _mako_ -- we use this for templates, and have wrapper called mitxmako that makes mako look like the django templating calls.
-We use a fork of django-pipeline to make sure that the js and css always reflect the latest `*.coffee` and `*.sass` files (We're hoping to get our changes merged in the official version soon). This works differently in development and production. Test uses the production settings.
+We use a fork of django-pipeline to make sure that the js and css always reflect the latest `*.coffee` and `*.sass` files (We're hoping to get our changes merged in the official version soon). This works differently in development and production. Test uses the production settings.
In production, the django `collectstatic` command recompiles everything and puts all the generated static files in a static/ dir. A starting point in the code is `django-pipeline/pipeline/packager.py:pack`.
@@ -127,8 +133,6 @@ See `testing.md`.
## TODO:
-- update lms/envs/README.txt
-
- describe our production environment
- describe the front-end architecture, tools, etc. Starting point: `lms/static`
diff --git a/lms/djangoapps/courseware/management/commands/clean_xml.py b/lms/djangoapps/courseware/management/commands/clean_xml.py
new file mode 100644
index 0000000000..7523fd8373
--- /dev/null
+++ b/lms/djangoapps/courseware/management/commands/clean_xml.py
@@ -0,0 +1,171 @@
+import os
+import sys
+import traceback
+
+from filecmp import dircmp
+from fs.osfs import OSFS
+from path import path
+from lxml import etree
+
+from django.core.management.base import BaseCommand
+
+from xmodule.modulestore.xml import XMLModuleStore
+
+
+def traverse_tree(course):
+ '''Load every descriptor in course. Return bool success value.'''
+ queue = [course]
+ while len(queue) > 0:
+ node = queue.pop()
+# print '{0}:'.format(node.location)
+# if 'data' in node.definition:
+# print '{0}'.format(node.definition['data'])
+ queue.extend(node.get_children())
+
+ return True
+
+def make_logging_error_handler():
+ '''Return a tuple (handler, error_list), where
+ the handler appends the message and any exc_info
+ to the error_list on every call.
+ '''
+ errors = []
+
+ def error_handler(msg, exc_info=None):
+ '''Log errors'''
+ if exc_info is None:
+ if sys.exc_info() != (None, None, None):
+ exc_info = sys.exc_info()
+
+ errors.append((msg, exc_info))
+
+ return (error_handler, errors)
+
+
+def export(course, export_dir):
+ """Export the specified course to course_dir. Creates dir if it doesn't exist.
+ Overwrites files, does not clean out dir beforehand.
+ """
+ fs = OSFS(export_dir, create=True)
+ if not fs.isdirempty('.'):
+ print ('WARNING: Directory {dir} not-empty.'
+ ' May clobber/confuse things'.format(dir=export_dir))
+
+ try:
+ xml = course.export_to_xml(fs)
+ with fs.open('course.xml', mode='w') as f:
+ f.write(xml)
+
+ return True
+ except:
+ print 'Export failed!'
+ traceback.print_exc()
+
+ return False
+
+
+def import_with_checks(course_dir, verbose=True):
+ all_ok = True
+
+ print "Attempting to load '{0}'".format(course_dir)
+
+ course_dir = path(course_dir)
+ data_dir = course_dir.dirname()
+ course_dirs = [course_dir.basename()]
+
+ (error_handler, errors) = make_logging_error_handler()
+ # No default class--want to complain if it doesn't find plugins for any
+ # module.
+ modulestore = XMLModuleStore(data_dir,
+ default_class=None,
+ eager=True,
+ course_dirs=course_dirs,
+ error_handler=error_handler)
+
+ def str_of_err(tpl):
+ (msg, exc_info) = tpl
+ if exc_info is None:
+ return msg
+
+ exc_str = '\n'.join(traceback.format_exception(*exc_info))
+ return '{msg}\n{exc}'.format(msg=msg, exc=exc_str)
+
+ courses = modulestore.get_courses()
+ if len(errors) != 0:
+ all_ok = False
+ print '\n'
+ print "=" * 40
+ print 'ERRORs during import:'
+ print '\n'.join(map(str_of_err,errors))
+ print "=" * 40
+ print '\n'
+
+ n = len(courses)
+ if n != 1:
+ print 'ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format(
+ n=n, lst=courses)
+ return (False, None)
+
+ course = courses[0]
+
+ #print course
+ validators = (
+ traverse_tree,
+ )
+
+ print "=" * 40
+ print "Running validators..."
+
+ for validate in validators:
+ print 'Running {0}'.format(validate.__name__)
+ all_ok = validate(course) and all_ok
+
+
+ if all_ok:
+ print 'Course passes all checks!'
+ else:
+ print "Course fails some checks. See above for errors."
+ return all_ok, course
+
+
+def check_roundtrip(course_dir):
+ '''Check that import->export leaves the course the same'''
+
+ print "====== Roundtrip import ======="
+ (ok, course) = import_with_checks(course_dir)
+ if not ok:
+ raise Exception("Roundtrip import failed!")
+
+ print "====== Roundtrip export ======="
+ export_dir = course_dir + ".rt"
+ export(course, export_dir)
+
+ # dircmp doesn't do recursive diffs.
+ # diff = dircmp(course_dir, export_dir, ignore=[], hide=[])
+ print "======== Roundtrip diff: ========="
+ os.system("diff -r {0} {1}".format(course_dir, export_dir))
+ print "======== ideally there is no diff above this ======="
+
+
+def clean_xml(course_dir, export_dir):
+ (ok, course) = import_with_checks(course_dir)
+ if ok:
+ export(course, export_dir)
+ check_roundtrip(export_dir)
+ else:
+ print "Did NOT export"
+
+
+
+class Command(BaseCommand):
+ help = """Imports specified course.xml, validate it, then exports in
+ a canonical format.
+
+Usage: clean_xml PATH-TO-COURSE-DIR PATH-TO-OUTPUT-DIR
+"""
+ def handle(self, *args, **options):
+ if len(args) != 2:
+ print Command.help
+ return
+
+ clean_xml(args[0], args[1])
diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py
index 3f111c2953..bf7d1f4c51 100644
--- a/lms/djangoapps/courseware/module_render.py
+++ b/lms/djangoapps/courseware/module_render.py
@@ -56,11 +56,13 @@ def toc_for_course(user, request, course, active_chapter, active_section):
active = (chapter.metadata.get('display_name') == active_chapter and
section.metadata.get('display_name') == active_section)
+ hide_from_toc = section.metadata.get('hide_from_toc', 'false').lower() == 'true'
- sections.append({'name': section.metadata.get('display_name'),
- 'format': section.metadata.get('format', ''),
- 'due': section.metadata.get('due', ''),
- 'active': active})
+ if not hide_from_toc:
+ sections.append({'name': section.metadata.get('display_name'),
+ 'format': section.metadata.get('format', ''),
+ 'due': section.metadata.get('due', ''),
+ 'active': active})
chapters.append({'name': chapter.metadata.get('display_name'),
'sections': sections,
@@ -117,16 +119,18 @@ def get_module(user, request, location, student_module_cache, position=None):
instance_module is a StudentModule specific to this module for this student,
or None if this is an anonymous user
shared_module is a StudentModule specific to all modules with the same
- 'shared_state_key' attribute, or None if the module doesn't elect to
+ 'shared_state_key' attribute, or None if the module does not elect to
share state
'''
descriptor = modulestore().get_item(location)
- instance_module = student_module_cache.lookup(descriptor.category, descriptor.location.url())
+ instance_module = student_module_cache.lookup(descriptor.category,
+ descriptor.location.url())
shared_state_key = getattr(descriptor, 'shared_state_key', None)
if shared_state_key is not None:
- shared_module = student_module_cache.lookup(descriptor.category, shared_state_key)
+ shared_module = student_module_cache.lookup(descriptor.category,
+ shared_state_key)
else:
shared_module = None
@@ -136,10 +140,12 @@ def get_module(user, request, location, student_module_cache, position=None):
# TODO (vshnayder): fix hardcoded urls (use reverse)
# Setup system context for module instance
ajax_url = settings.MITX_ROOT_URL + '/modx/' + descriptor.location.url() + '/'
- xqueue_callback_url = settings.MITX_ROOT_URL + '/xqueue/' + str(user.id) + '/' + descriptor.location.url() + '/'
+ xqueue_callback_url = (settings.MITX_ROOT_URL + '/xqueue/' +
+ str(user.id) + '/' + descriptor.location.url() + '/')
def _get_module(location):
- (module, _, _, _) = get_module(user, request, location, student_module_cache, position)
+ (module, _, _, _) = get_module(user, request, location,
+ student_module_cache, position)
return module
# TODO (cpennington): When modules are shared between courses, the static
diff --git a/lms/static/sass/course/old/print.scss b/lms/djangoapps/courseware/tests/__init__.py
similarity index 100%
rename from lms/static/sass/course/old/print.scss
rename to lms/djangoapps/courseware/tests/__init__.py
diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py
new file mode 100644
index 0000000000..8e9d13f8d5
--- /dev/null
+++ b/lms/djangoapps/courseware/tests/tests.py
@@ -0,0 +1,208 @@
+import copy
+import json
+import os
+
+from pprint import pprint
+
+from django.test import TestCase
+from django.test.client import Client
+from mock import patch, Mock
+from override_settings import override_settings
+from django.conf import settings
+from django.core.urlresolvers import reverse
+from path import path
+
+from student.models import Registration
+from django.contrib.auth.models import User
+
+from xmodule.modulestore.django import modulestore
+import xmodule.modulestore.django
+from xmodule.modulestore import Location
+from xmodule.modulestore.xml_importer import import_from_xml
+
+
+def parse_json(response):
+ """Parse response, which is assumed to be json"""
+ return json.loads(response.content)
+
+
+def user(email):
+ '''look up a user by email'''
+ return User.objects.get(email=email)
+
+
+def registration(email):
+ '''look up registration object by email'''
+ return Registration.objects.get(user__email=email)
+
+
+# A bit of a hack--want mongo modulestore for these tests, until
+# jump_to works with the xmlmodulestore or we have an even better solution
+# NOTE: this means this test requires mongo to be running.
+
+def mongo_store_config(data_dir):
+ return {
+ 'default': {
+ 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
+ 'OPTIONS': {
+ 'default_class': 'xmodule.raw_module.RawDescriptor',
+ 'host': 'localhost',
+ 'db': 'xmodule',
+ 'collection': 'modulestore',
+ 'fs_root': data_dir,
+ }
+ }
+}
+
+TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
+TEST_DATA_MODULESTORE = mongo_store_config(TEST_DATA_DIR)
+
+REAL_DATA_DIR = settings.GITHUB_REPO_ROOT
+REAL_DATA_MODULESTORE = mongo_store_config(REAL_DATA_DIR)
+
+class ActivateLoginTestCase(TestCase):
+ '''Check that we can activate and log in'''
+
+ def setUp(self):
+ email = 'view@test.com'
+ password = 'foo'
+ self.create_account('viewtest', email, password)
+ self.activate_user(email)
+ self.login(email, password)
+
+ # ============ User creation and login ==============
+
+ def _login(self, email, pw):
+ '''Login. View should always return 200. The success/fail is in the
+ returned json'''
+ resp = self.client.post(reverse('login'),
+ {'email': email, 'password': pw})
+ self.assertEqual(resp.status_code, 200)
+ return resp
+
+ def login(self, email, pw):
+ '''Login, check that it worked.'''
+ resp = self._login(email, pw)
+ data = parse_json(resp)
+ self.assertTrue(data['success'])
+ return resp
+
+ def _create_account(self, username, email, pw):
+ '''Try to create an account. No error checking'''
+ resp = self.client.post('/create_account', {
+ 'username': username,
+ 'email': email,
+ 'password': pw,
+ 'name': 'Fred Weasley',
+ 'terms_of_service': 'true',
+ 'honor_code': 'true',
+ })
+ return resp
+
+ def create_account(self, username, email, pw):
+ '''Create the account and check that it worked'''
+ resp = self._create_account(username, email, pw)
+ self.assertEqual(resp.status_code, 200)
+ data = parse_json(resp)
+ self.assertEqual(data['success'], True)
+
+ # Check both that the user is created, and inactive
+ self.assertFalse(user(email).is_active)
+
+ return resp
+
+ def _activate_user(self, email):
+ '''Look up the activation key for the user, then hit the activate view.
+ No error checking'''
+ activation_key = registration(email).activation_key
+
+ # and now we try to activate
+ resp = self.client.get(reverse('activate', kwargs={'key': activation_key}))
+ return resp
+
+ def activate_user(self, email):
+ resp = self._activate_user(email)
+ self.assertEqual(resp.status_code, 200)
+ # Now make sure that the user is now actually activated
+ self.assertTrue(user(email).is_active)
+
+ def test_activate_login(self):
+ '''The setup function does all the work'''
+ pass
+
+
+class PageLoader(ActivateLoginTestCase):
+ ''' Base class that adds a function to load all pages in a modulestore '''
+
+ def check_pages_load(self, course_name, data_dir, modstore):
+ print "Checking course {0} in {1}".format(course_name, data_dir)
+ import_from_xml(modstore, data_dir, [course_name])
+
+ n = 0
+ num_bad = 0
+ all_ok = True
+ for descriptor in modstore.get_items(
+ Location(None, None, None, None, None)):
+ n += 1
+ print "Checking ", descriptor.location.url()
+ #print descriptor.__class__, descriptor.location
+ resp = self.client.get(reverse('jump_to',
+ kwargs={'location': descriptor.location.url()}))
+ msg = str(resp.status_code)
+
+ if resp.status_code != 200:
+ msg = "ERROR " + msg
+ all_ok = False
+ num_bad += 1
+ print msg
+ self.assertTrue(all_ok) # fail fast
+
+ print "{0}/{1} good".format(n - num_bad, n)
+ self.assertTrue(all_ok)
+
+
+@override_settings(MODULESTORE=TEST_DATA_MODULESTORE)
+class TestCoursesLoadTestCase(PageLoader):
+ '''Check that all pages in test courses load properly'''
+
+ def setUp(self):
+ ActivateLoginTestCase.setUp(self)
+ xmodule.modulestore.django._MODULESTORES = {}
+ xmodule.modulestore.django.modulestore().collection.drop()
+
+ def test_toy_course_loads(self):
+ self.check_pages_load('toy', TEST_DATA_DIR, modulestore())
+
+ def test_full_course_loads(self):
+ self.check_pages_load('full', TEST_DATA_DIR, modulestore())
+
+
+ # ========= TODO: check ajax interaction here too?
+
+
+@override_settings(MODULESTORE=REAL_DATA_MODULESTORE)
+class RealCoursesLoadTestCase(PageLoader):
+ '''Check that all pages in real courses load properly'''
+
+ def setUp(self):
+ ActivateLoginTestCase.setUp(self)
+ xmodule.modulestore.django._MODULESTORES = {}
+ xmodule.modulestore.django.modulestore().collection.drop()
+
+ # TODO: Disabled test for now.. Fix once things are cleaned up.
+ def Xtest_real_courses_loads(self):
+ '''See if any real courses are available at the REAL_DATA_DIR.
+ If they are, check them.'''
+
+ # TODO: adjust staticfiles_dirs
+ if not os.path.isdir(REAL_DATA_DIR):
+ # No data present. Just pass.
+ return
+
+ courses = [course_dir for course_dir in os.listdir(REAL_DATA_DIR)
+ if os.path.isdir(REAL_DATA_DIR / course_dir)]
+ for course in courses:
+ self.check_pages_load(course, REAL_DATA_DIR, modulestore())
+
+
+ # ========= TODO: check ajax interaction here too?
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index f273778a3c..00fde8a84c 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -20,12 +20,16 @@ from module_render import toc_for_course, get_module, get_section
from models import StudentModuleCache
from student.models import UserProfile
from multicourse import multicourse_settings
+from xmodule.modulestore import Location
+from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
+from xmodule.modulestore.django import modulestore
+from xmodule.course_module import CourseDescriptor
from util.cache import cache, cache_if_anonymous
from student.models import UserTestGroup, CourseEnrollment
from courseware import grades
from courseware.courses import check_course
-from xmodule.modulestore.django import modulestore
+
log = logging.getLogger("mitx.courseware")
@@ -196,65 +200,59 @@ def index(request, course_id, chapter=None, section=None,
if look_for_module:
# TODO (cpennington): Pass the right course in here
- section = get_section(course, chapter, section)
- student_module_cache = StudentModuleCache(request.user, section)
- module, _, _, _ = get_module(request.user, request, section.location, student_module_cache)
- context['content'] = module.get_html()
+ section_descriptor = get_section(course, chapter, section)
+ if section_descriptor is not None:
+ student_module_cache = StudentModuleCache(request.user,
+ section_descriptor)
+ module, _, _, _ = get_module(request.user, request,
+ section_descriptor.location,
+ student_module_cache)
+ context['content'] = module.get_html()
+ else:
+ log.warning("Couldn't find a section descriptor for course_id '{0}',"
+ "chapter '{1}', section '{2}'".format(
+ course_id, chapter, section))
+
result = render_to_response('courseware.html', context)
return result
-
-def jump_to(request, probname=None):
+@ensure_csrf_cookie
+def jump_to(request, location):
'''
- Jump to viewing a specific problem. The problem is specified by a
- problem name - currently the filename (minus .xml) of the problem.
- Maybe this should change to a more generic tag, eg "name" given as
- an attribute in .
+ Show the page that contains a specific location.
- We do the jump by (1) reading course.xml to find the first
- instance of with the given filename, then (2) finding
- the parent element of the problem, then (3) rendering that parent
- element with a specific computed position value (if it is
- ).
+ If the location is invalid, return a 404.
+ If the location is valid, but not present in a course, ?
+
+ If the location is valid, but in a course the current user isn't registered for, ?
+ TODO -- let the index view deal with it?
'''
- # get coursename if stored
- coursename = multicourse_settings.get_coursename_from_request(request)
+ # Complain if the location isn't valid
+ try:
+ location = Location(location)
+ except InvalidLocationError:
+ raise Http404("Invalid location")
- # begin by getting course.xml tree
- xml = content_parser.course_file(request.user, coursename)
+ # Complain if there's not data for this location
+ try:
+ (course_id, chapter, section, position) = modulestore().path_to_location(location)
+ except ItemNotFoundError:
+ raise Http404("No data at this location: {0}".format(location))
+ except NoPathToItem:
+ raise Http404("This location is not in any class: {0}".format(location))
- # look for problem of given name
- pxml = xml.xpath('//problem[@filename="%s"]' % probname)
- if pxml:
- pxml = pxml[0]
-
- # get the parent element
- parent = pxml.getparent()
-
- # figure out chapter and section names
- chapter = None
- section = None
- branch = parent
- for k in range(4): # max depth of recursion
- if branch.tag == 'section':
- section = branch.get('name')
- if branch.tag == 'chapter':
- chapter = branch.get('name')
- branch = branch.getparent()
-
- position = None
- if parent.tag == 'sequential':
- position = parent.index(pxml) + 1 # position in sequence
-
- return index(request,
- course=coursename, chapter=chapter,
- section=section, position=position)
+ return index(request, course_id, chapter, section, position)
@ensure_csrf_cookie
def course_info(request, course_id):
+ '''
+ Display the course's info.html, or 404 if there is no such course.
+
+ Assumes the course_id is in a valid format.
+ '''
course = check_course(course_id)
return render_to_response('info.html', {'course': course})
diff --git a/lms/envs/README.txt b/lms/envs/README.txt
index 7a527b290f..6d1512e6f6 100644
--- a/lms/envs/README.txt
+++ b/lms/envs/README.txt
@@ -1,14 +1,16 @@
-Transitional for moving to new settings scheme.
+Transitional for moving to new settings scheme.
-To use:
- django-admin.py runserver --settings=envs.dev --pythonpath=.
+To use:
+ rake lms
+ or
+ django-admin.py runserver --settings=lms.envs.dev --pythonpath=.
NOTE: Using manage.py will automatically run mitx/settings.py first, regardless
of what you send it for an explicit --settings flag. It still works, but might
-have odd side effects. Using django-admin.py avoids that problem.
+have odd side effects. Using django-admin.py avoids that problem.
django-admin.py is installed by default when you install Django.
To use with gunicorn_django in debug mode:
- gunicorn_django envs/dev.py
+ gunicorn_django lms/envs/dev.py
diff --git a/lms/envs/aws.py b/lms/envs/aws.py
index bd2a0fc389..460ec18d27 100644
--- a/lms/envs/aws.py
+++ b/lms/envs/aws.py
@@ -32,12 +32,12 @@ LOG_DIR = ENV_TOKENS['LOG_DIR']
CACHES = ENV_TOKENS['CACHES']
-for feature,value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
+for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
MITX_FEATURES[feature] = value
-WIKI_ENABLED = ENV_TOKENS.get('WIKI_ENABLED',WIKI_ENABLED)
+WIKI_ENABLED = ENV_TOKENS.get('WIKI_ENABLED', WIKI_ENABLED)
-LOGGING = get_logger_config(LOG_DIR,
+LOGGING = get_logger_config(LOG_DIR,
logging_env=ENV_TOKENS['LOGGING_ENV'],
syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
debug=False)
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 093e97c325..4f84aba93a 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -6,16 +6,16 @@ MITX_FEATURES[...]. Modules that extend this one can change the feature
configuration in an environment specific config file and re-calculate those
values.
-We should make a method that calls all these config methods so that you just
+We should make a method that calls all these config methods so that you just
make one call at the end of your site-specific dev file to reset all the
dependent variables (like INSTALLED_APPS) for you.
Longer TODO:
-1. Right now our treatment of static content in general and in particular
+1. Right now our treatment of static content in general and in particular
course-specific static content is haphazard.
2. We should have a more disciplined approach to feature flagging, even if it
just means that we stick them in a dict called MITX_FEATURES.
-3. We need to handle configuration for multiple courses. This could be as
+3. We need to handle configuration for multiple courses. This could be as
multiple sites, but we do need a way to map their data assets.
"""
import sys
@@ -42,7 +42,7 @@ MITX_FEATURES = {
'SAMPLE' : False,
'USE_DJANGO_PIPELINE' : True,
'DISPLAY_HISTOGRAMS_TO_STAFF' : True,
- 'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
+ 'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
'DEBUG_LEVEL' : 0, # 0 = lowest level, least verbose, 255 = max level, most verbose
## DO NOT SET TO True IN THIS FILE
@@ -61,7 +61,7 @@ PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /mitx/lms
REPO_ROOT = PROJECT_ROOT.dirname()
COMMON_ROOT = REPO_ROOT / "common"
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /mitx is in
-ASKBOT_ROOT = ENV_ROOT / "askbot-devel"
+ASKBOT_ROOT = REPO_ROOT / "askbot"
COURSES_ROOT = ENV_ROOT / "data"
# FIXME: To support multiple courses, we should walk the courses dir at startup
@@ -85,7 +85,7 @@ MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
COMMON_ROOT / 'lib' / 'capa' / 'capa' / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates']
-# This is where Django Template lookup is defined. There are a few of these
+# This is where Django Template lookup is defined. There are a few of these
# still left lying around.
TEMPLATE_DIRS = (
PROJECT_ROOT / "templates",
@@ -103,8 +103,8 @@ TEMPLATE_CONTEXT_PROCESSORS = (
)
-# FIXME:
-# We should have separate S3 staged URLs in case we need to make changes to
+# FIXME:
+# We should have separate S3 staged URLs in case we need to make changes to
# these assets and test them.
LIB_URL = '/static/js/'
@@ -120,7 +120,7 @@ STATIC_GRAB = False
DEV_CONTENT = True
# FIXME: Should we be doing this truncation?
-TRACK_MAX_EVENT = 10000
+TRACK_MAX_EVENT = 10000
DEBUG_TRACK_LOG = False
MITX_ROOT_URL = ''
@@ -129,7 +129,7 @@ COURSE_NAME = "6.002_Spring_2012"
COURSE_NUMBER = "6.002x"
COURSE_TITLE = "Circuits and Electronics"
-### Dark code. Should be enabled in local settings for devel.
+### Dark code. Should be enabled in local settings for devel.
ENABLE_MULTICOURSE = False # set to False to disable multicourse display (see lib.util.views.mitxhome)
QUICKEDIT = False
@@ -211,9 +211,9 @@ USE_L10N = True
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
#################################### AWS #######################################
-# S3BotoStorage insists on a timeout for uploaded assets. We should make it
+# S3BotoStorage insists on a timeout for uploaded assets. We should make it
# permanent instead, but rather than trying to figure out exactly where that
-# setting is, I'm just bumping the expiration time to something absurd (100
+# setting is, I'm just bumping the expiration time to something absurd (100
# years). This is only used if DEFAULT_FILE_STORAGE is overriden to use S3
# in the global settings.py
AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years
@@ -279,7 +279,7 @@ MIDDLEWARE_CLASSES = (
# Instead of AuthenticationMiddleware, we use a cached backed version
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
-
+
'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware',
'mitxmako.middleware.MakoMiddleware',
@@ -301,15 +301,15 @@ STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
PIPELINE_CSS = {
'application': {
'source_filenames': ['sass/application.scss'],
- 'output_filename': 'css/application.css',
+ 'output_filename': 'css/lms-application.css',
},
'course': {
- 'source_filenames': ['sass/course.scss', 'js/vendor/CodeMirror/codemirror.css', 'css/vendor/jquery.treeview.css'],
- 'output_filename': 'css/course.css',
+ 'source_filenames': ['sass/course.scss', 'js/vendor/CodeMirror/codemirror.css', 'css/vendor/jquery.treeview.css', 'css/vendor/jquery-ui-1.8.16.custom.css', 'css/vendor/jquery.qtip.min.css'],
+ 'output_filename': 'css/lms-course.css',
},
'ie-fixes': {
'source_filenames': ['sass/ie.scss'],
- 'output_filename': 'css/ie.css',
+ 'output_filename': 'css/lms-ie.css',
},
}
@@ -410,26 +410,44 @@ PIPELINE_JS = {
'js/toggle_login_modal.js',
'js/sticky_filter.js',
],
- 'output_filename': 'js/application.js'
+ 'output_filename': 'js/lms-application.js'
},
'courseware': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in courseware_only_js],
- 'output_filename': 'js/courseware.js'
+ 'output_filename': 'js/lms-courseware.js'
},
'main_vendor': {
'source_filenames': main_vendor_js,
- 'output_filename': 'js/main_vendor.js',
+ 'output_filename': 'js/lms-main_vendor.js',
},
'module-js': {
'source_filenames': module_js_sources,
- 'output_filename': 'js/modules.js',
+ 'output_filename': 'js/lms-modules.js',
},
'spec': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
- 'output_filename': 'js/spec.js'
+ 'output_filename': 'js/lms-spec.js'
}
}
+# Compile all coffee files in course data directories if they are out of date.
+# TODO: Remove this once we move data into Mongo. This is only temporary while
+# course data directories are still in use.
+if os.path.isdir(DATA_DIR):
+ for course_dir in os.listdir(DATA_DIR):
+ js_dir = DATA_DIR / course_dir / "js"
+ if not os.path.isdir(js_dir):
+ continue
+ for filename in os.listdir(js_dir):
+ if filename.endswith('coffee'):
+ new_filename = os.path.splitext(filename)[0] + ".js"
+ if os.path.exists(js_dir / new_filename):
+ coffee_timestamp = os.stat(js_dir / filename).st_mtime
+ js_timestamp = os.stat(js_dir / new_filename).st_mtime
+ if coffee_timestamp <= js_timestamp:
+ continue
+ os.system("coffee -c %s" % (js_dir / filename))
+
PIPELINE_COMPILERS = [
'pipeline.compilers.sass.SASSCompiler',
'pipeline.compilers.coffee.CoffeeScriptCompiler',
@@ -484,7 +502,7 @@ INSTALLED_APPS = (
# For testing
'django_jasmine',
- # For Askbot
+ # For Askbot
'django.contrib.sitemaps',
'django.contrib.admin',
'django_countries',
diff --git a/lms/envs/logsettings.py b/lms/envs/logsettings.py
index 916cd77748..3683314d02 100644
--- a/lms/envs/logsettings.py
+++ b/lms/envs/logsettings.py
@@ -3,19 +3,19 @@ import os.path
import platform
import sys
-def get_logger_config(log_dir,
- logging_env="no_env",
+def get_logger_config(log_dir,
+ logging_env="no_env",
tracking_filename=None,
syslog_addr=None,
debug=False):
"""Return the appropriate logging config dictionary. You should assign the
- result of this to the LOGGING var in your settings. The reason it's done
+ result of this to the LOGGING var in your settings. The reason it's done
this way instead of registering directly is because I didn't want to worry
- about resetting the logging state if this is called multiple times when
+ about resetting the logging state if this is called multiple times when
settings are extended."""
# If we're given an explicit place to put tracking logs, we do that (say for
- # debugging). However, logging is not safe for multiple processes hitting
+ # debugging). However, logging is not safe for multiple processes hitting
# the same file. So if it's left blank, we dynamically create the filename
# based on the PID of this worker process.
if tracking_filename:
@@ -33,7 +33,7 @@ def get_logger_config(log_dir,
return {
'version': 1,
- 'disable_existing_loggers': True,
+ 'disable_existing_loggers': False,
'formatters' : {
'standard' : {
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
diff --git a/lms/envs/test.py b/lms/envs/test.py
index fdfbfb20c4..e6fedcb373 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -12,17 +12,21 @@ from .logsettings import get_logger_config
import os
from path import path
-INSTALLED_APPS = [
- app
- for app
- in INSTALLED_APPS
- if not app.startswith('askbot')
-]
+# can't test start dates with this True, but on the other hand,
+# can test everything else :)
+MITX_FEATURES['DISABLE_START_DATES'] = True
+
+# Need wiki for courseware views to work. TODO (vshnayder): shouldn't need it.
+WIKI_ENABLED = True
+
+# Makes the tests run much faster...
+SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead
# Nose Test Runner
-INSTALLED_APPS += ['django_nose']
+INSTALLED_APPS += ('django_nose',)
NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html',
- '--cover-inclusive', '--cover-html-dir', os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
+ '--cover-inclusive', '--cover-html-dir',
+ os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
NOSE_ARGS += ['--cover-package', app]
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
@@ -30,25 +34,23 @@ TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
# Local Directories
TEST_ROOT = path("test_root")
# Want static files in the same dir for running on jenkins.
-STATIC_ROOT = TEST_ROOT / "staticfiles"
+STATIC_ROOT = TEST_ROOT / "staticfiles"
COURSES_ROOT = TEST_ROOT / "data"
DATA_DIR = COURSES_ROOT
-MAKO_TEMPLATES['course'] = [DATA_DIR]
-MAKO_TEMPLATES['sections'] = [DATA_DIR / 'sections']
-MAKO_TEMPLATES['custom_tags'] = [DATA_DIR / 'custom_tags']
-MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
- DATA_DIR / 'info',
- DATA_DIR / 'problems']
-LOGGING = get_logger_config(TEST_ROOT / "log",
+LOGGING = get_logger_config(TEST_ROOT / "log",
logging_env="dev",
tracking_filename="tracking.log",
debug=True)
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
+# Where the content data is checked out. This may not exist on jenkins.
+GITHUB_REPO_ROOT = ENV_ROOT / "data"
-# 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
+
+# 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 = [
COMMON_ROOT / "static",
PROJECT_ROOT / "static",
@@ -67,7 +69,7 @@ DATABASES = {
}
CACHES = {
- # This is the cache used for most things. Askbot will not work without a
+ # This is the cache used for most things. Askbot will not work without a
# functioning cache -- it relies on caching to load its settings in places.
# In staging/prod envs, the sessions also live here.
'default': {
diff --git a/lms/envs/with_cms.py b/lms/envs/with_cms.py
new file mode 100644
index 0000000000..b807a0f545
--- /dev/null
+++ b/lms/envs/with_cms.py
@@ -0,0 +1,10 @@
+"""
+Settings for the LMS that runs alongside the CMS on AWS
+"""
+
+from .aws import *
+
+with open(ENV_ROOT / "cms.auth.json") as auth_file:
+ CMS_AUTH_TOKENS = json.load(auth_file)
+
+MODULESTORE = CMS_AUTH_TOKENS['MODULESTORE']
diff --git a/lms/static/.gitignore b/lms/static/.gitignore
index 03f1cdabff..afc42d5e7e 100644
--- a/lms/static/.gitignore
+++ b/lms/static/.gitignore
@@ -5,4 +5,5 @@
*.orig
*.DS_Store
application.css
-ie.css
\ No newline at end of file
+ie.css
+Gemfile.lock
diff --git a/lms/static/sass/course/old/plugins/_jquery-ui-1.8.16.custom.scss b/lms/static/css/vendor/jquery-ui-1.8.16.custom.css
similarity index 100%
rename from lms/static/sass/course/old/plugins/_jquery-ui-1.8.16.custom.scss
rename to lms/static/css/vendor/jquery-ui-1.8.16.custom.css
diff --git a/lms/static/sass/course/old/plugins/_jquery.qtip.min.scss b/lms/static/css/vendor/jquery.qtip.min.css
similarity index 100%
rename from lms/static/sass/course/old/plugins/_jquery.qtip.min.scss
rename to lms/static/css/vendor/jquery.qtip.min.css
diff --git a/lms/static/js/jquery.treeview.js b/lms/static/js/jquery.treeview.js
new file mode 100755
index 0000000000..02b452c22a
--- /dev/null
+++ b/lms/static/js/jquery.treeview.js
@@ -0,0 +1,256 @@
+/*
+ * Treeview 1.5pre - jQuery plugin to hide and show branches of a tree
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
+ * http://docs.jquery.com/Plugins/Treeview
+ *
+ * Copyright (c) 2007 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $
+ *
+ */
+
+;(function($) {
+
+ // TODO rewrite as a widget, removing all the extra plugins
+ $.extend($.fn, {
+ swapClass: function(c1, c2) {
+ var c1Elements = this.filter('.' + c1);
+ this.filter('.' + c2).removeClass(c2).addClass(c1);
+ c1Elements.removeClass(c1).addClass(c2);
+ return this;
+ },
+ replaceClass: function(c1, c2) {
+ return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
+ },
+ hoverClass: function(className) {
+ className = className || "hover";
+ return this.hover(function() {
+ $(this).addClass(className);
+ }, function() {
+ $(this).removeClass(className);
+ });
+ },
+ heightToggle: function(animated, callback) {
+ animated ?
+ this.animate({ height: "toggle" }, animated, callback) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ if(callback)
+ callback.apply(this, arguments);
+ });
+ },
+ heightHide: function(animated, callback) {
+ if (animated) {
+ this.animate({ height: "hide" }, animated, callback);
+ } else {
+ this.hide();
+ if (callback)
+ this.each(callback);
+ }
+ },
+ prepareBranches: function(settings) {
+ if (!settings.prerendered) {
+ // mark last tree items
+ this.filter(":last-child:not(ul)").addClass(CLASSES.last);
+ // collapse whole tree, or only those marked as closed, anyway except those marked as open
+ this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
+ }
+ // return all items with sublists
+ return this.filter(":has(>ul)");
+ },
+ applyClasses: function(settings, toggler) {
+ // TODO use event delegation
+ this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
+ // don't handle click events on children, eg. checkboxes
+ if ( this == event.target )
+ toggler.apply($(this).next());
+ }).add( $("a", this) ).hoverClass();
+
+ if (!settings.prerendered) {
+ // handle closed ones first
+ this.filter(":has(>ul:hidden)")
+ .addClass(CLASSES.expandable)
+ .replaceClass(CLASSES.last, CLASSES.lastExpandable);
+
+ // handle open ones
+ this.not(":has(>ul:hidden)")
+ .addClass(CLASSES.collapsable)
+ .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
+
+ // create hitarea if not present
+ var hitarea = this.find("div." + CLASSES.hitarea);
+ if (!hitarea.length)
+ hitarea = this.prepend("
").find("div." + CLASSES.hitarea);
+ hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
+ var classes = "";
+ $.each($(this).parent().attr("class").split(" "), function() {
+ classes += this + "-hitarea ";
+ });
+ $(this).addClass( classes );
+ })
+ }
+
+ // apply event to hitarea
+ this.find("div." + CLASSES.hitarea).click( toggler );
+ },
+ treeview: function(settings) {
+
+ settings = $.extend({
+ cookieId: "treeview"
+ }, settings);
+
+ if ( settings.toggle ) {
+ var callback = settings.toggle;
+ settings.toggle = function() {
+ return callback.apply($(this).parent()[0], arguments);
+ };
+ }
+
+ // factory for treecontroller
+ function treeController(tree, control) {
+ // factory for click handlers
+ function handler(filter) {
+ return function() {
+ // reuse toggle event handler, applying the elements to toggle
+ // start searching for all hitareas
+ toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
+ // for plain toggle, no filter is provided, otherwise we need to check the parent element
+ return filter ? $(this).parent("." + filter).length : true;
+ }) );
+ return false;
+ };
+ }
+ // click on first element to collapse tree
+ $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
+ // click on second to expand tree
+ $("a:eq(1)", control).click( handler(CLASSES.expandable) );
+ // click on third to toggle tree
+ $("a:eq(2)", control).click( handler() );
+ }
+
+ // handle toggle event
+ function toggler() {
+ $(this)
+ .parent()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ // swap classes for parent li
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ // find child lists
+ .find( ">ul" )
+ // toggle them
+ .heightToggle( settings.animated, settings.toggle );
+ if ( settings.unique ) {
+ $(this).parent()
+ .siblings()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ .replaceClass( CLASSES.collapsable, CLASSES.expandable )
+ .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find( ">ul" )
+ .heightHide( settings.animated, settings.toggle );
+ }
+ }
+ this.data("toggler", toggler);
+
+ function serialize() {
+ function binary(arg) {
+ return arg ? 1 : 0;
+ }
+ var data = [];
+ branches.each(function(i, e) {
+ data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
+ });
+ $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
+ }
+
+ function deserialize() {
+ var stored = $.cookie(settings.cookieId);
+ if ( stored ) {
+ var data = stored.split("");
+ branches.each(function(i, e) {
+ $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
+ });
+ }
+ }
+
+ // add treeview class to activate styles
+ this.addClass("treeview");
+
+ // prepare branches and find all tree items with child lists
+ var branches = this.find("li").prepareBranches(settings);
+
+ switch(settings.persist) {
+ case "cookie":
+ var toggleCallback = settings.toggle;
+ settings.toggle = function() {
+ serialize();
+ if (toggleCallback) {
+ toggleCallback.apply(this, arguments);
+ }
+ };
+ deserialize();
+ break;
+ case "location":
+ var current = this.find("a").filter(function() {
+ return this.href.toLowerCase() == location.href.toLowerCase();
+ });
+ if ( current.length ) {
+ // TODO update the open/closed classes
+ var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
+ if (settings.prerendered) {
+ // if prerendered is on, replicate the basic class swapping
+ items.filter("li")
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
+ }
+ }
+ break;
+ }
+
+ branches.applyClasses(settings, toggler);
+
+ // if control option is set, create the treecontroller and show it
+ if ( settings.control ) {
+ treeController(this, settings.control);
+ $(settings.control).show();
+ }
+
+ return this;
+ }
+ });
+
+ // classes used by the plugin
+ // need to be styled via external stylesheet, see first example
+ $.treeview = {};
+ var CLASSES = ($.treeview.classes = {
+ open: "open",
+ closed: "closed",
+ expandable: "expandable",
+ expandableHitarea: "expandable-hitarea",
+ lastExpandableHitarea: "lastExpandable-hitarea",
+ collapsable: "collapsable",
+ collapsableHitarea: "collapsable-hitarea",
+ lastCollapsableHitarea: "lastCollapsable-hitarea",
+ lastCollapsable: "lastCollapsable",
+ lastExpandable: "lastExpandable",
+ last: "last",
+ hitarea: "hitarea"
+ });
+
+})(jQuery);
\ No newline at end of file
diff --git a/lms/static/sass/base/_mixins.scss b/lms/static/sass/base/_mixins.scss
index bcff3e0d67..7c53b6e14f 100644
--- a/lms/static/sass/base/_mixins.scss
+++ b/lms/static/sass/base/_mixins.scss
@@ -1,3 +1,14 @@
+// Line-height
+@function lh($amount: 1) {
+ @return $body-line-height * $amount;
+}
+
+@mixin hide-text(){
+ text-indent: -9999px;
+ overflow: hidden;
+ display: block;
+}
+
@mixin vertically-and-horizontally-centered ( $height, $width ) {
left: 50%;
margin-left: -$width / 2;
diff --git a/lms/static/sass/base/_variables.scss b/lms/static/sass/base/_variables.scss
index 7471ba5d13..6c8d0d4000 100644
--- a/lms/static/sass/base/_variables.scss
+++ b/lms/static/sass/base/_variables.scss
@@ -16,3 +16,17 @@ $pink: rgb(182,37,104);
$yellow: rgb(255, 252, 221);
$error-red: rgb(253, 87, 87);
+// old variables
+$body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+$body-font-size: 14px;
+$body-line-height: golden-ratio($body-font-size, 1);
+
+$fg-max-width: 1400px;
+$fg-min-width: 810px;
+
+$light-gray: #ddd;
+$dark-gray: #333;
+$mit-red: #993333;
+$cream: #F6EFD4;
+$text-color: $dark-gray;
+$border-color: $light-gray;
diff --git a/lms/static/sass/course.scss b/lms/static/sass/course.scss
index 2be4d0ade5..4e84ebfadb 100644
--- a/lms/static/sass/course.scss
+++ b/lms/static/sass/course.scss
@@ -8,22 +8,39 @@
@import 'base/extends';
@import 'base/animations';
-// Course styles
-@import 'course/courseware_subnav';
-
-// Courseware styles
-@import 'course/old/base/variables';
-@import 'course/old/base/extends';
-@import 'course/old/base/functions';
-
+// Course base / layout styles
+@import 'course/layout/courseware_subnav';
+@import 'course/base/extends';
@import 'module/module-styles.scss';
-@import 'course/old/courseware/courseware';
-@import 'course/old/courseware/sidebar';
-@import 'course/old/courseware/amplifier';
-// @import 'course/old/courseware/problems';
+// courseware
+@import 'course/courseware/courseware';
+@import 'course/courseware/sidebar';
+@import 'course/courseware/amplifier';
-@import "course/old/info";
+// wiki
+@import "course/wiki/basic-html";
+@import "course/wiki/sidebar";
+@import "course/wiki/create";
+@import "course/wiki/wiki";
+@import "course/wiki/table";
-@import "course/old/plugins/jquery-ui-1.8.16.custom", "course/old/plugins/jquery.qtip.min";
-@import "course/old/textbook";
+// pages
+@import "course/info";
+@import "course/textbook";
+@import "course/profile";
+@import "course/gradebook";
+
+// Askbot / Discussion styles
+@import "course/discussion/askbot-original";
+@import "course/discussion/discussion";
+@import "course/discussion/sidebar";
+@import "course/discussion/questions";
+@import "course/discussion/tags";
+@import "course/discussion/question-view" ;
+@import "course/discussion/answers";
+@import "course/discussion/forms";
+@import "course/discussion/form-wmd-toolbar";
+@import "course/discussion/modals";
+@import "course/discussion/profile";
+@import "course/discussion/badges";
diff --git a/lms/static/sass/course/old/_gradebook.scss b/lms/static/sass/course/_gradebook.scss
similarity index 100%
rename from lms/static/sass/course/old/_gradebook.scss
rename to lms/static/sass/course/_gradebook.scss
diff --git a/lms/static/sass/course/old/_help.scss b/lms/static/sass/course/_help.scss
similarity index 100%
rename from lms/static/sass/course/old/_help.scss
rename to lms/static/sass/course/_help.scss
diff --git a/lms/static/sass/course/old/_info.scss b/lms/static/sass/course/_info.scss
similarity index 98%
rename from lms/static/sass/course/old/_info.scss
rename to lms/static/sass/course/_info.scss
index 7fcdcc8d10..45dd2d57b3 100644
--- a/lms/static/sass/course/old/_info.scss
+++ b/lms/static/sass/course/_info.scss
@@ -14,6 +14,7 @@ div.info-wrapper {
> ol {
list-style: none;
+ padding-left: 0;
> li {
@extend .clearfix;
@@ -85,6 +86,7 @@ div.info-wrapper {
ol {
background: none;
list-style: none;
+ padding-left: 0;
li {
@extend .clearfix;
diff --git a/lms/static/sass/course/old/_profile.scss b/lms/static/sass/course/_profile.scss
similarity index 100%
rename from lms/static/sass/course/old/_profile.scss
rename to lms/static/sass/course/_profile.scss
diff --git a/lms/static/sass/course/old/_textbook.scss b/lms/static/sass/course/_textbook.scss
similarity index 100%
rename from lms/static/sass/course/old/_textbook.scss
rename to lms/static/sass/course/_textbook.scss
diff --git a/lms/static/sass/course/old/base/_extends.scss b/lms/static/sass/course/base/_extends.scss
similarity index 86%
rename from lms/static/sass/course/old/base/_extends.scss
rename to lms/static/sass/course/base/_extends.scss
index bc6b70322b..260230cb7b 100644
--- a/lms/static/sass/course/old/base/_extends.scss
+++ b/lms/static/sass/course/base/_extends.scss
@@ -1,11 +1,3 @@
-.clearfix:after {
- clear: both;
- content: ".";
- display: block;
- height: 0;
- visibility: hidden;
-}
-
.wrapper {
margin: 0 auto;
max-width: $fg-max-width;
@@ -17,10 +9,6 @@
display: table;
width: flex-grid(12);
overflow: hidden;
-
- @media screen and (min-width: 1400px) {
- @include border-radius(4px);
- }
}
}
@@ -29,6 +17,7 @@ h1.top-header {
border-bottom: 1px solid #e3e3e3;
margin: (-(lh())) (-(lh())) lh();
padding: lh();
+ text-align: left;
}
.button {
@@ -82,7 +71,6 @@ h1.top-header {
}
.content {
- @include box-shadow(inset 0 0 2px 3px #f3f3f3);
@include box-sizing(border-box);
display: table-cell;
padding: lh();
@@ -96,15 +84,11 @@ h1.top-header {
}
.sidebar {
- background: #e3e3e3;
- @include border-radius(4px 0 0 4px);
border-right: 1px solid #d3d3d3;
- @include box-shadow( inset 0 0 0 1px #f6f6f6);
@include box-sizing(border-box);
display: table-cell;
- font-family: $body-font-family;
+ font-family: $sans-serif;
position: relative;
- text-shadow: 0 1px 0 #f1f1f1;
vertical-align: top;
width: flex-grid(3);
@@ -113,6 +97,7 @@ h1.top-header {
font-weight: bold;
letter-spacing: 0;
text-transform: none;
+ font-family: $sans-serif;
}
a {
@@ -122,7 +107,6 @@ h1.top-header {
.bottom-border {
border-bottom: 1px solid #d3d3d3;
- @include box-shadow(0 1px 0 #eee);
}
@media print {
@@ -151,10 +135,7 @@ h1.top-header {
}
&.active {
- background: none;
- @include background-image(linear-gradient(-90deg, rgb(245,245,245), rgb(225,225,225)));
border-bottom: 1px solid #d3d3d3;
- @include box-shadow(inset 0 1px 0 0 #eee);
color: #000;
font-weight: bold;
@@ -203,9 +184,7 @@ h1.top-header {
background: $cream;
border-bottom: 1px solid darken($cream, 10%);
border-top: 1px solid #fff;
- // @include box-shadow(inset 0 1px 0 #fff, inset 1px 0 0 #fff);
font-size: 12px;
- // height:46px;
line-height: 46px;
text-shadow: 0 1px 0 #fff;
diff --git a/lms/static/sass/course/old/courseware/_amplifier.scss b/lms/static/sass/course/courseware/_amplifier.scss
similarity index 100%
rename from lms/static/sass/course/old/courseware/_amplifier.scss
rename to lms/static/sass/course/courseware/_amplifier.scss
diff --git a/lms/static/sass/course/old/courseware/_courseware.scss b/lms/static/sass/course/courseware/_courseware.scss
similarity index 99%
rename from lms/static/sass/course/old/courseware/_courseware.scss
rename to lms/static/sass/course/courseware/_courseware.scss
index d7911f49ed..8a0d880ceb 100644
--- a/lms/static/sass/course/old/courseware/_courseware.scss
+++ b/lms/static/sass/course/courseware/_courseware.scss
@@ -8,7 +8,7 @@ body.courseware {
max-height: 100%;
.container {
- margin-bottom: 40px;
+ padding-bottom: 40px;
margin-top: 20px;
}
diff --git a/lms/static/sass/course/old/courseware/_sidebar.scss b/lms/static/sass/course/courseware/_sidebar.scss
similarity index 98%
rename from lms/static/sass/course/old/courseware/_sidebar.scss
rename to lms/static/sass/course/courseware/_sidebar.scss
index 235426294e..fc0291f48a 100644
--- a/lms/static/sass/course/old/courseware/_sidebar.scss
+++ b/lms/static/sass/course/courseware/_sidebar.scss
@@ -45,7 +45,6 @@ section.course-index {
ul.ui-accordion-content {
@include border-radius(0);
@include box-shadow(inset -1px 0 0 #e6e6e6);
- background: #dadada;
border: none;
font-size: 12px;
margin: 0;
@@ -66,6 +65,7 @@ section.course-index {
p {
font-weight: bold;
+ font-family: $sans-serif;
margin-bottom: 0;
span.subtitle {
diff --git a/lms/static/sass/course/old/discussion/_answers.scss b/lms/static/sass/course/discussion/_answers.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_answers.scss
rename to lms/static/sass/course/discussion/_answers.scss
diff --git a/lms/static/sass/course/old/discussion/_askbot-original.scss b/lms/static/sass/course/discussion/_askbot-original.scss
similarity index 99%
rename from lms/static/sass/course/old/discussion/_askbot-original.scss
rename to lms/static/sass/course/discussion/_askbot-original.scss
index 09db42ce4e..8926fb1c98 100644
--- a/lms/static/sass/course/old/discussion/_askbot-original.scss
+++ b/lms/static/sass/course/discussion/_askbot-original.scss
@@ -1820,27 +1820,27 @@ body.anon #searchbar {
.tabbar-user {
width: 375px; }
-.user {
- padding: 5px;
- line-height: 140%;
- width: 166px;
- border: #eee 1px solid;
- margin-bottom: 5px;
- border-radius: 3px;
- -ms-border-radius: 3px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- -khtml-border-radius: 3px;
- .user-micro-info {
- color: #525252; }
- ul {
- margin: 0;
- list-style-type: none; }
- .thumb {
- clear: both;
- float: left;
- margin-right: 4px;
- display: inline; } }
+// .user {
+// padding: 5px;
+// line-height: 140%;
+// width: 166px;
+// border: #eee 1px solid;
+// margin-bottom: 5px;
+// border-radius: 3px;
+// -ms-border-radius: 3px;
+// -moz-border-radius: 3px;
+// -webkit-border-radius: 3px;
+// -khtml-border-radius: 3px;
+// .user-micro-info {
+// color: #525252; }
+// ul {
+// margin: 0;
+// list-style-type: none; }
+// .thumb {
+// clear: both;
+// float: left;
+// margin-right: 4px;
+// display: inline; } }
// .tabbar-tags {
// width: 270px;
diff --git a/lms/static/sass/course/old/discussion/_badges.scss b/lms/static/sass/course/discussion/_badges.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_badges.scss
rename to lms/static/sass/course/discussion/_badges.scss
diff --git a/lms/static/sass/course/old/discussion/_discussion.scss b/lms/static/sass/course/discussion/_discussion.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_discussion.scss
rename to lms/static/sass/course/discussion/_discussion.scss
diff --git a/lms/static/sass/course/old/discussion/_form-wmd-toolbar.scss b/lms/static/sass/course/discussion/_form-wmd-toolbar.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_form-wmd-toolbar.scss
rename to lms/static/sass/course/discussion/_form-wmd-toolbar.scss
diff --git a/lms/static/sass/course/old/discussion/_forms.scss b/lms/static/sass/course/discussion/_forms.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_forms.scss
rename to lms/static/sass/course/discussion/_forms.scss
diff --git a/lms/static/sass/course/old/discussion/_modals.scss b/lms/static/sass/course/discussion/_modals.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_modals.scss
rename to lms/static/sass/course/discussion/_modals.scss
diff --git a/lms/static/sass/course/old/discussion/_profile.scss b/lms/static/sass/course/discussion/_profile.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_profile.scss
rename to lms/static/sass/course/discussion/_profile.scss
diff --git a/lms/static/sass/course/old/discussion/_question-view.scss b/lms/static/sass/course/discussion/_question-view.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_question-view.scss
rename to lms/static/sass/course/discussion/_question-view.scss
diff --git a/lms/static/sass/course/old/discussion/_questions.scss b/lms/static/sass/course/discussion/_questions.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_questions.scss
rename to lms/static/sass/course/discussion/_questions.scss
diff --git a/lms/static/sass/course/old/discussion/_sidebar.scss b/lms/static/sass/course/discussion/_sidebar.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_sidebar.scss
rename to lms/static/sass/course/discussion/_sidebar.scss
diff --git a/lms/static/sass/course/old/discussion/_tags.scss b/lms/static/sass/course/discussion/_tags.scss
similarity index 100%
rename from lms/static/sass/course/old/discussion/_tags.scss
rename to lms/static/sass/course/discussion/_tags.scss
diff --git a/lms/static/sass/course/old/layout/_calculator.scss b/lms/static/sass/course/layout/_calculator.scss
similarity index 100%
rename from lms/static/sass/course/old/layout/_calculator.scss
rename to lms/static/sass/course/layout/_calculator.scss
diff --git a/lms/static/sass/course/_courseware_subnav.scss b/lms/static/sass/course/layout/_courseware_subnav.scss
similarity index 100%
rename from lms/static/sass/course/_courseware_subnav.scss
rename to lms/static/sass/course/layout/_courseware_subnav.scss
diff --git a/lms/static/sass/course/old/README.md b/lms/static/sass/course/old/README.md
deleted file mode 100644
index e94076e6e0..0000000000
--- a/lms/static/sass/course/old/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-SASS
-====
-
-This project is using Sass to generate its CSS. Sass is a CSS preprocessor that
-allows for faster development of CSS. For more information about sass:
-
- http://sass-lang.com
-
-Install SASS
-------------
-
-To use sass, make sure that you have RubyGems install, then you can use Bundler:
-
- $ gem install bundler
- $ bundle install
-
-This should ensure that you have all the dependencies required for compiling.
-
-Compiling
----------
-
-The dev server will automatically compile sass files that have changed. Simply start
-the server using:
-
- $ rake runserver
-
-To run it along side of development:
-
- $ sass --watch lms/static/sass:lms/static/sass -r ./lms/static/sass/bourbon/lib/bourbon.rb
diff --git a/lms/static/sass/course/old/application.scss b/lms/static/sass/course/old/application.scss
deleted file mode 100644
index c493202e33..0000000000
--- a/lms/static/sass/course/old/application.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-@import "bourbon/bourbon";
-
-// Base layout
-@import "base/reset", "base/font-face";
-@import "base/variables", "base/functions", "base/extends", "base/base";
-@import "layout/layout", "layout/header", "layout/footer", "layout/calculator", "layout/leanmodal";
-@import "plugins/jquery-ui-1.8.16.custom", "plugins/jquery.qtip.min";
-
-// pages
-@import "courseware/courseware", "courseware/sidebar", "courseware/video", "courseware/sequence-nav", "courseware/amplifier";
-@import "textbook";
-@import "info";
-@import "profile";
-@import "gradebook";
-@import "wiki/basic-html", "wiki/sidebar", "wiki/create", "wiki/wiki", "wiki/table";
-@import "help";
-
-@import "discussion/askbot-original", "discussion/discussion","discussion/sidebar", "discussion/questions", "discussion/tags", "discussion/question-view" , "discussion/answers", "discussion/forms", "discussion/form-wmd-toolbar", "discussion/modals", "discussion/profile", "discussion/badges";
diff --git a/lms/static/sass/course/old/base/_base.scss b/lms/static/sass/course/old/base/_base.scss
deleted file mode 100644
index 41c421844c..0000000000
--- a/lms/static/sass/course/old/base/_base.scss
+++ /dev/null
@@ -1,77 +0,0 @@
-:focus {
- outline-color: #ccc;
-}
-
-h1, h2, h3, h4, h5, h6 {
- a {
- color: #000;
- }
-}
-
-h1 {
- font-size:1.6em;
- margin:20px 0 10px 0;
-}
-
-h2 {
- font-size: $body-font-size;
- font-weight: bold;
- letter-spacing: 1px;
- margin:20px 0 10px 0;
- text-transform: uppercase;
-}
-
-p {
- margin-bottom: $body-line-height;
-}
-
-em {
- font-style: italic;
-}
-
-img {
- max-width: 100%;
- height: auto;
-}
-
-#{$all-text-inputs}, textarea {
- border: 1px solid #999;
- @include box-shadow(0 -1px 0 #fff);
- font: $body-font-size $body-font-family;
- @include linear-gradient(#eee, #fff);
- padding: 4px;
-
- &:focus {
- border-color: $mit-red;
- }
-}
-
-a {
- color: $mit-red;
-
- &:link {
- color: $mit-red;
- }
-
- &:visited {
- color: darken($mit-red, 10%);
- }
-
- &:link, &:visited {
- text-decoration:none;
- }
-
- p &, li > &, span > &, .inline {
- border-bottom: 1px solid #bbb;
- // font-style: italic;
- }
-
- &:hover, &:focus {
- color: #000;
- }
-}
-
-input[type="submit"], input[type="button"], button {
- @extend .button;
-}
-
diff --git a/lms/static/sass/course/old/base/_font-face.scss b/lms/static/sass/course/old/base/_font-face.scss
deleted file mode 100644
index 36e60a6ca5..0000000000
--- a/lms/static/sass/course/old/base/_font-face.scss
+++ /dev/null
@@ -1,125 +0,0 @@
-/* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 25, 2012 05:06:34 PM America/New_York */
-
-
-// Not used in UI
-// @font-face {
-// font-family: 'Open Sans';
-// src: url('../fonts/OpenSans-Light-webfont.eot');
-// src: url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
-// url('../fonts/OpenSans-Light-webfont.woff') format('woff'),
-// url('../fonts/OpenSans-Light-webfont.ttf') format('truetype'),
-// url('../fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg');
-// font-weight: 300;
-// font-style: normal;
-
-// }
-
-// @font-face {
-// font-family: 'Open Sans';
-// src: url('../fonts/OpenSans-LightItalic-webfont.eot');
-// src: url('../fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
-// url('../fonts/OpenSans-LightItalic-webfont.woff') format('woff'),
-// url('../fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'),
-// url('../fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg');
-// font-weight: 300;
-// font-style: italic;
-
-// }
-
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Regular-webfont.eot');
- src: url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
- font-weight: 600;
- font-style: normal;
-
-}
-
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Italic-webfont.eot');
- src: url('../fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Italic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Italic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg');
- font-weight: 400;
- font-style: italic;
-
-}
-
-// Not used in UI
-// @font-face {
-// font-family: 'Open Sans';
-// src: url('../fonts/OpenSans-Semibold-webfont.eot');
-// src: url('../fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
-// url('../fonts/OpenSans-Semibold-webfont.woff') format('woff'),
-// url('../fonts/OpenSans-Semibold-webfont.ttf') format('truetype'),
-// url('../fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
-// font-weight: 600;
-// font-style: normal;
-
-// }
-
-// @font-face {
-// font-family: 'Open Sans';
-// src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot');
-// src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
-// url('../fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'),
-// url('../fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
-// url('../fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
-// font-weight: 600;
-// font-style: italic;
-
-// }
-
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Bold-webfont.eot');
- src: url('../fonts/OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Bold-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Bold-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Bold-webfont.svg#OpenSansBold') format('svg');
- font-weight: 700;
- font-style: normal;
-
-}
-
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-BoldItalic-webfont.eot');
- src: url('../fonts/OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-BoldItalic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-BoldItalic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg');
- font-weight: 700;
- font-style: italic;
-
-}
-
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-ExtraBold-webfont.eot');
- src: url('../fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-ExtraBold-webfont.woff') format('woff'),
- url('../fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold') format('svg');
- font-weight: 800;
- font-style: normal;
-
-}
-
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-ExtraBoldItalic-webfont.eot');
- src: url('../fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-ExtraBoldItalic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-ExtraBoldItalic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic') format('svg');
- font-weight: 800;
- font-style: italic;
-
-}
-
diff --git a/lms/static/sass/course/old/base/_functions.scss b/lms/static/sass/course/old/base/_functions.scss
deleted file mode 100644
index a947d94034..0000000000
--- a/lms/static/sass/course/old/base/_functions.scss
+++ /dev/null
@@ -1,10 +0,0 @@
-// Line-height
-@function lh($amount: 1) {
- @return $body-line-height * $amount;
-}
-
-@mixin hide-text(){
- text-indent: -9999px;
- overflow: hidden;
- display: block;
-}
diff --git a/lms/static/sass/course/old/base/_reset.scss b/lms/static/sass/course/old/base/_reset.scss
deleted file mode 100644
index 3cf4758c7b..0000000000
--- a/lms/static/sass/course/old/base/_reset.scss
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-html5doctor.com Reset Stylesheet
-v1.6.1
-Last Updated: 2010-09-17
-Author: Richard Clark - http://richclarkdesign.com
-Twitter: @rich_clark
-*/
-
-html, body, div, span, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-abbr, address, cite, code,
-del, dfn, em, img, ins, kbd, q, samp,
-small, strong, var,
-b, i,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section, summary,
-time, mark, audio, video {
- margin:0;
- padding:0;
- border:0;
- outline:0;
- font-size:100%;
- vertical-align:baseline;
- background:transparent;
-}
-
-body {
- line-height:1;
-}
-
-article,aside,details,figcaption,figure,
-footer,header,hgroup,menu,nav,section {
- display:block;
-}
-
-nav ul {
- list-style:none;
-}
-
-blockquote, q {
- quotes:none;
-}
-
-blockquote:before, blockquote:after,
-q:before, q:after {
- content:'';
- content:none;
-}
-
-a {
- margin:0;
- padding:0;
- font-size:100%;
- vertical-align:baseline;
- background:transparent;
-}
-
-/* change colours to suit your needs */
-ins {
- background-color:#ff9;
- color:#000;
- text-decoration:none;
-}
-
-/* change colours to suit your needs */
-mark {
- background-color:#ff9;
- color:#000;
- font-style:italic;
- font-weight:bold;
-}
-
-del {
- text-decoration: line-through;
-}
-
-abbr[title], dfn[title] {
- border-bottom:1px dotted;
- cursor:help;
-}
-
-table {
- border-collapse:collapse;
- border-spacing:0;
-}
-
-/* change border colour to suit your needs */
-hr {
- display:block;
- height:1px;
- border:0;
- border-top:1px solid #cccccc;
- margin:1em 0;
- padding:0;
-}
-
-input, select {
- vertical-align:middle;
-}
diff --git a/lms/static/sass/course/old/base/_variables.scss b/lms/static/sass/course/old/base/_variables.scss
deleted file mode 100644
index 674de12ee6..0000000000
--- a/lms/static/sass/course/old/base/_variables.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-// Variables
-// ---------------------------------------- //
-
-// Type
-$body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
-$body-font-size: 14px;
-$body-line-height: golden-ratio($body-font-size, 1);
-
-// Grid
-$fg-column: 80px;
-$fg-gutter: 25px;
-$fg-max-columns: 12;
-$fg-max-width: 1400px;
-$fg-min-width: 810px;
-
-// Color
-$light-gray: #ddd;
-$dark-gray: #333;
-$mit-red: #993333;
-$cream: #F6EFD4;
-$text-color: $dark-gray;
-$border-color: $light-gray;
diff --git a/lms/static/sass/course/old/bourbon/_bourbon.scss b/lms/static/sass/course/old/bourbon/_bourbon.scss
deleted file mode 100644
index 27b056e303..0000000000
--- a/lms/static/sass/course/old/bourbon/_bourbon.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-// Custom Functions
-@import "functions/deprecated-webkit-gradient";
-@import "functions/flex-grid";
-@import "functions/grid-width";
-@import "functions/linear-gradient";
-@import "functions/modular-scale";
-@import "functions/radial-gradient";
-@import "functions/render-gradients";
-@import "functions/tint-shade";
-
-// CSS3 Mixins
-@import "css3/animation";
-@import "css3/appearance";
-@import "css3/background-image";
-@import "css3/background-size";
-@import "css3/border-image";
-@import "css3/border-radius";
-@import "css3/box-shadow";
-@import "css3/box-sizing";
-@import "css3/columns";
-@import "css3/flex-box";
-@import "css3/inline-block";
-@import "css3/linear-gradient";
-@import "css3/radial-gradient";
-@import "css3/transform";
-@import "css3/transition";
-@import "css3/user-select";
-
-// Addons & other mixins
-@import "addons/button";
-@import "addons/clearfix";
-@import "addons/font-family";
-@import "addons/html5-input-types";
-@import "addons/position";
-@import "addons/timing-functions";
diff --git a/lms/static/sass/course/old/bourbon/addons/_button.scss b/lms/static/sass/course/old/bourbon/addons/_button.scss
deleted file mode 100644
index 1d32125140..0000000000
--- a/lms/static/sass/course/old/bourbon/addons/_button.scss
+++ /dev/null
@@ -1,267 +0,0 @@
-@mixin button ($style: simple, $base-color: #4294f0) {
-
- @if type-of($style) == color {
- $base-color: $style;
- $style: simple;
- }
-
- // Grayscale button
- @if $base-color == grayscale($base-color) {
- @if $style == simple {
- @include simple($base-color, $grayscale: true);
- }
-
- @else if $style == shiny {
- @include shiny($base-color, $grayscale: true);
- }
-
- @else if $style == pill {
- @include pill($base-color, $grayscale: true);
- }
- }
-
- // Colored button
- @else {
- @if $style == simple {
- @include simple($base-color);
- }
-
- @else if $style == shiny {
- @include shiny($base-color);
- }
-
- @else if $style == pill {
- @include pill($base-color);
- }
- }
-}
-
-
-// Simple Button
-//************************************************************************//
-@mixin simple($base-color, $grayscale: false) {
- $color: hsl(0, 0, 100%);
- $border: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
- $inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%);
- $stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%);
- $text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%);
-
- @if lightness($base-color) > 70% {
- $color: hsl(0, 0, 20%);
- $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
- }
-
- @if $grayscale == true {
- $border: grayscale($border);
- $inset-shadow: grayscale($inset-shadow);
- $stop-gradient: grayscale($stop-gradient);
- $text-shadow: grayscale($text-shadow);
- }
-
- border: 1px solid $border;
- @include border-radius (3px);
- @include box-shadow (inset 0 1px 0 0 $inset-shadow);
- color: $color;
- display: inline;
- font-size: 11px;
- font-weight: bold;
- @include linear-gradient ($base-color, $stop-gradient);
- padding: 6px 18px 7px;
- text-shadow: 0 1px 0 $text-shadow;
- -webkit-background-clip: padding-box;
-
- &:hover {
- $base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
- $inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%);
- $stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%);
-
- @if $grayscale == true {
- $base-color-hover: grayscale($base-color-hover);
- $inset-shadow-hover: grayscale($inset-shadow-hover);
- $stop-gradient-hover: grayscale($stop-gradient-hover);
- }
-
- @include box-shadow (inset 0 1px 0 0 $inset-shadow-hover);
- cursor: pointer;
- @include linear-gradient ($base-color-hover, $stop-gradient-hover);
- }
-
- &:active {
- $border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
- $inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%);
-
- @if $grayscale == true {
- $border-active: grayscale($border-active);
- $inset-shadow-active: grayscale($inset-shadow-active);
- }
-
- border: 1px solid $border-active;
- @include box-shadow (inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active, 0 1px 1px 0 #eee);
- }
-}
-
-
-// Shiny Button
-//************************************************************************//
-@mixin shiny($base-color, $grayscale: false) {
- $color: hsl(0, 0, 100%);
- $border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81);
- $border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122);
- $fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46);
- $inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12);
- $second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33);
- $text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114);
- $third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48);
-
- @if lightness($base-color) > 70% {
- $color: hsl(0, 0, 20%);
- $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
- }
-
- @if $grayscale == true {
- $border: grayscale($border);
- $border-bottom: grayscale($border-bottom);
- $fourth-stop: grayscale($fourth-stop);
- $inset-shadow: grayscale($inset-shadow);
- $second-stop: grayscale($second-stop);
- $text-shadow: grayscale($text-shadow);
- $third-stop: grayscale($third-stop);
- }
-
- border: 1px solid $border;
- border-bottom: 1px solid $border-bottom;
- @include border-radius(5px);
- @include box-shadow(inset 0 1px 0 0 $inset-shadow);
- color: $color;
- display: inline;
- font-size: 14px;
- font-weight: bold;
- @include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%);
- padding: 7px 20px 8px;
- text-align: center;
- text-decoration: none;
- text-shadow: 0 -1px 1px $text-shadow;
-
- &:hover {
- $first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18);
- $second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51);
- $third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66);
- $fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63);
-
- @if $grayscale == true {
- $first-stop-hover: grayscale($first-stop-hover);
- $second-stop-hover: grayscale($second-stop-hover);
- $third-stop-hover: grayscale($third-stop-hover);
- $fourth-stop-hover: grayscale($fourth-stop-hover);
- }
-
- cursor: pointer;
- @include linear-gradient(top, $first-stop-hover 0%,
- $second-stop-hover 50%,
- $third-stop-hover 50%,
- $fourth-stop-hover 100%);
- }
-
- &:active {
- $inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122);
-
- @if $grayscale == true {
- $inset-shadow-active: grayscale($inset-shadow-active);
- }
-
- @include box-shadow(inset 0 0 20px 0 $inset-shadow-active, 0 1px 0 #fff);
- }
-}
-
-
-// Pill Button
-//************************************************************************//
-@mixin pill($base-color, $grayscale: false) {
- $color: hsl(0, 0, 100%);
- $border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%);
- $border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%);
- $border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%);
- $inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%);
- $stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%);
- $text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%);
-
- @if lightness($base-color) > 70% {
- $color: hsl(0, 0, 20%);
- $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
- }
-
- @if $grayscale == true {
- $border-bottom: grayscale($border-bottom);
- $border-sides: grayscale($border-sides);
- $border-top: grayscale($border-top);
- $inset-shadow: grayscale($inset-shadow);
- $stop-gradient: grayscale($stop-gradient);
- $text-shadow: grayscale($text-shadow);
- }
-
- border: 1px solid $border-top;
- border-color: $border-top $border-sides $border-bottom;
- @include border-radius(16px);
- @include box-shadow(inset 0 1px 0 0 $inset-shadow, 0 1px 2px 0 #b3b3b3);
- color: $color;
- display: inline;
- font-size: 11px;
- font-weight: normal;
- line-height: 1;
- @include linear-gradient ($base-color, $stop-gradient);
- padding: 3px 16px 5px;
- text-align: center;
- text-shadow: 0 -1px 1px $text-shadow;
- -webkit-background-clip: padding-box;
-
- &:hover {
- $base-color-hover: adjust-color($base-color, $lightness: -4.5%);
- $border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%);
- $border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%);
- $border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%);
- $inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%);
- $stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%);
- $text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%);
-
- @if $grayscale == true {
- $base-color-hover: grayscale($base-color-hover);
- $border-bottom: grayscale($border-bottom);
- $border-sides: grayscale($border-sides);
- $border-top: grayscale($border-top);
- $inset-shadow-hover: grayscale($inset-shadow-hover);
- $stop-gradient-hover: grayscale($stop-gradient-hover);
- $text-shadow-hover: grayscale($text-shadow-hover);
- }
-
- border: 1px solid $border-top;
- border-color: $border-top $border-sides $border-bottom;
- @include box-shadow(inset 0 1px 0 0 $inset-shadow-hover);
- cursor: pointer;
- @include linear-gradient ($base-color-hover, $stop-gradient-hover);
- text-shadow: 0 -1px 1px $text-shadow-hover;
- -webkit-background-clip: padding-box;
- }
-
- &:active {
- $active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%);
- $border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%);
- $border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%);
- $inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%);
- $text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%);
-
- @if $grayscale == true {
- $active-color: grayscale($active-color);
- $border-active: grayscale($border-active);
- $border-bottom-active: grayscale($border-bottom-active);
- $inset-shadow-active: grayscale($inset-shadow-active);
- $text-shadow-active: grayscale($text-shadow-active);
- }
-
- background: $active-color;
- border: 1px solid $border-active;
- border-bottom: 1px solid $border-bottom-active;
- @include box-shadow(inset 0 0 6px 3px $inset-shadow-active, 0 1px 0 0 #fff);
- text-shadow: 0 -1px 1px $text-shadow-active;
- }
-}
-
diff --git a/lms/static/sass/course/old/bourbon/addons/_clearfix.scss b/lms/static/sass/course/old/bourbon/addons/_clearfix.scss
deleted file mode 100644
index a9f6a795c5..0000000000
--- a/lms/static/sass/course/old/bourbon/addons/_clearfix.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-// Micro clearfix provides an easy way to contain floats without adding additional markup
-//
-// Example usage:
-//
-// // Contain all floats within .wrapper
-// .wrapper {
-// @include clearfix;
-// .content,
-// .sidebar {
-// float : left;
-// }
-// }
-
-@mixin clearfix {
- zoom: 1;
-
- &:before,
- &:after {
- content: "";
- display: table;
- }
-
- &:after {
- clear: both;
- }
-}
-
-// Acknowledgements
-// Micro clearfix: [Nicolas Gallagher](http://nicolasgallagher.com/micro-clearfix-hack/)
diff --git a/lms/static/sass/course/old/bourbon/addons/_font-family.scss b/lms/static/sass/course/old/bourbon/addons/_font-family.scss
deleted file mode 100644
index df8a80ddfc..0000000000
--- a/lms/static/sass/course/old/bourbon/addons/_font-family.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-$georgia: Georgia, Cambria, "Times New Roman", Times, serif;
-$helvetica: "Helvetica Neue", Helvetica, Arial, sans-serif;
-$lucida-grande: "Lucida Grande", Tahoma, Verdana, Arial, sans-serif;
-$monospace: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;
-$verdana: Verdana, Geneva, sans-serif;
diff --git a/lms/static/sass/course/old/bourbon/addons/_html5-input-types.scss b/lms/static/sass/course/old/bourbon/addons/_html5-input-types.scss
deleted file mode 100644
index 9d86fbb4d4..0000000000
--- a/lms/static/sass/course/old/bourbon/addons/_html5-input-types.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-//************************************************************************//
-// Generate a variable ($all-text-inputs) with a list of all html5
-// input types that have a text-based input, excluding textarea.
-// http://diveintohtml5.org/forms.html
-//************************************************************************//
-$inputs-list: 'input[type="email"]',
- 'input[type="number"]',
- 'input[type="password"]',
- 'input[type="search"]',
- 'input[type="tel"]',
- 'input[type="text"]',
- 'input[type="url"]',
-
- // Webkit & Gecko may change the display of these in the future
- 'input[type="color"]',
- 'input[type="date"]',
- 'input[type="datetime"]',
- 'input[type="datetime-local"]',
- 'input[type="month"]',
- 'input[type="time"]',
- 'input[type="week"]';
-
-$unquoted-inputs-list: ();
-
-@each $input-type in $inputs-list {
- $unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma);
-}
-
-$all-text-inputs: $unquoted-inputs-list;
-
-// You must use interpolation on the variable:
-// #{$all-text-inputs}
-//************************************************************************//
-// #{$all-text-inputs}, textarea {
-// border: 1px solid red;
-// }
diff --git a/lms/static/sass/course/old/bourbon/addons/_position.scss b/lms/static/sass/course/old/bourbon/addons/_position.scss
deleted file mode 100644
index 6ad330f1df..0000000000
--- a/lms/static/sass/course/old/bourbon/addons/_position.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-@mixin position ($position: relative, $coordinates: 0 0 0 0) {
-
- @if type-of($position) == list {
- $coordinates: $position;
- $position: relative;
- }
-
- $top: nth($coordinates, 1);
- $right: nth($coordinates, 2);
- $bottom: nth($coordinates, 3);
- $left: nth($coordinates, 4);
-
- position: $position;
-
- @if not(unitless($top)) {
- top: $top;
- }
-
- @if not(unitless($right)) {
- right: $right;
- }
-
- @if not(unitless($bottom)) {
- bottom: $bottom;
- }
-
- @if not(unitless($left)) {
- left: $left;
- }
-}
diff --git a/lms/static/sass/course/old/bourbon/addons/_timing-functions.scss b/lms/static/sass/course/old/bourbon/addons/_timing-functions.scss
deleted file mode 100644
index 51b2410914..0000000000
--- a/lms/static/sass/course/old/bourbon/addons/_timing-functions.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie)
-// Timing functions are the same as demo'ed here: http://jqueryui.com/demos/effect/easing.html
-
-// EASE IN
-$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
-$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190);
-$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220);
-$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715);
-$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035);
-$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335);
-$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045);
-
-// EASE OUT
-$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940);
-$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
-$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000);
-$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000);
-$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000);
-$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000);
-$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275);
-
-// EASE IN OUT
-$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955);
-$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
-$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000);
-$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000);
-$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950);
-$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000);
-$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860);
-$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550);
diff --git a/lms/static/sass/course/old/bourbon/css3/_animation.scss b/lms/static/sass/course/old/bourbon/css3/_animation.scss
deleted file mode 100644
index f99e06eb6f..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_animation.scss
+++ /dev/null
@@ -1,171 +0,0 @@
-// http://www.w3.org/TR/css3-animations/#the-animation-name-property-
-// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties.
-
-// Official animation shorthand property.
-@mixin animation ($animation-1,
- $animation-2: false, $animation-3: false,
- $animation-4: false, $animation-5: false,
- $animation-6: false, $animation-7: false,
- $animation-8: false, $animation-9: false)
- {
- $full: compact($animation-1, $animation-2, $animation-3, $animation-4,
- $animation-5, $animation-6, $animation-7, $animation-8, $animation-9);
-
- -webkit-animation: $full;
- -moz-animation: $full;
- animation: $full;
-}
-
-// Individual Animation Properties
-@mixin animation-name ($name-1,
- $name-2: false, $name-3: false,
- $name-4: false, $name-5: false,
- $name-6: false, $name-7: false,
- $name-8: false, $name-9: false)
- {
- $full: compact($name-1, $name-2, $name-3, $name-4,
- $name-5, $name-6, $name-7, $name-8, $name-9);
-
- -webkit-animation-name: $full;
- -moz-animation-name: $full;
- animation-name: $full;
-}
-
-
-@mixin animation-duration ($time-1: 0,
- $time-2: false, $time-3: false,
- $time-4: false, $time-5: false,
- $time-6: false, $time-7: false,
- $time-8: false, $time-9: false)
- {
- $full: compact($time-1, $time-2, $time-3, $time-4,
- $time-5, $time-6, $time-7, $time-8, $time-9);
-
- -webkit-animation-duration: $full;
- -moz-animation-duration: $full;
- animation-duration: $full;
-}
-
-
-@mixin animation-timing-function ($motion-1: ease,
-// ease | linear | ease-in | ease-out | ease-in-out
- $motion-2: false, $motion-3: false,
- $motion-4: false, $motion-5: false,
- $motion-6: false, $motion-7: false,
- $motion-8: false, $motion-9: false)
- {
- $full: compact($motion-1, $motion-2, $motion-3, $motion-4,
- $motion-5, $motion-6, $motion-7, $motion-8, $motion-9);
-
- -webkit-animation-timing-function: $full;
- -moz-animation-timing-function: $full;
- animation-timing-function: $full;
-}
-
-
-@mixin animation-iteration-count ($value-1: 1,
-// infinite |
- $value-2: false, $value-3: false,
- $value-4: false, $value-5: false,
- $value-6: false, $value-7: false,
- $value-8: false, $value-9: false)
- {
- $full: compact($value-1, $value-2, $value-3, $value-4,
- $value-5, $value-6, $value-7, $value-8, $value-9);
-
- -webkit-animation-iteration-count: $full;
- -moz-animation-iteration-count: $full;
- animation-iteration-count: $full;
-}
-
-
-@mixin animation-direction ($direction-1: normal,
-// normal | alternate
- $direction-2: false, $direction-3: false,
- $direction-4: false, $direction-5: false,
- $direction-6: false, $direction-7: false,
- $direction-8: false, $direction-9: false)
- {
- $full: compact($direction-1, $direction-2, $direction-3, $direction-4,
- $direction-5, $direction-6, $direction-7, $direction-8, $direction-9);
-
- -webkit-animation-direction: $full;
- -moz-animation-direction: $full;
- animation-direction: $full;
-}
-
-
-@mixin animation-play-state ($state-1: running,
-// running | paused
- $state-2: false, $state-3: false,
- $state-4: false, $state-5: false,
- $state-6: false, $state-7: false,
- $state-8: false, $state-9: false)
- {
- $full: compact($state-1, $state-2, $state-3, $state-4,
- $state-5, $state-6, $state-7, $state-8, $state-9);
-
- -webkit-animation-play-state: $full;
- -moz-animation-play-state: $full;
- animation-play-state: $full;
-}
-
-
-@mixin animation-delay ($time-1: 0,
- $time-2: false, $time-3: false,
- $time-4: false, $time-5: false,
- $time-6: false, $time-7: false,
- $time-8: false, $time-9: false)
- {
- $full: compact($time-1, $time-2, $time-3, $time-4,
- $time-5, $time-6, $time-7, $time-8, $time-9);
-
- -webkit-animation-delay: $full;
- -moz-animation-delay: $full;
- animation-delay: $full;
-}
-
-
-@mixin animation-fill-mode ($mode-1: none,
-// http://goo.gl/l6ckm
-// none | forwards | backwards | both
- $mode-2: false, $mode-3: false,
- $mode-4: false, $mode-5: false,
- $mode-6: false, $mode-7: false,
- $mode-8: false, $mode-9: false)
- {
- $full: compact($mode-1, $mode-2, $mode-3, $mode-4,
- $mode-5, $mode-6, $mode-7, $mode-8, $mode-9);
-
- -webkit-animation-fill-mode: $full;
- -moz-animation-fill-mode: $full;
- animation-fill-mode: $full;
-}
-
-
-// Deprecated
-@mixin animation-basic ($name, $time: 0, $motion: ease) {
- $length-of-name: length($name);
- $length-of-time: length($time);
- $length-of-motion: length($motion);
-
- @if $length-of-name > 1 {
- @include animation-name(zip($name));
- } @else {
- @include animation-name( $name);
- }
-
- @if $length-of-time > 1 {
- @include animation-duration(zip($time));
- } @else {
- @include animation-duration( $time);
- }
-
- @if $length-of-motion > 1 {
- @include animation-timing-function(zip($motion));
- } @else {
- @include animation-timing-function( $motion);
- }
- @warn "The animation-basic mixin is deprecated. Use the animation mixin instead.";
-}
-
diff --git a/lms/static/sass/course/old/bourbon/css3/_appearance.scss b/lms/static/sass/course/old/bourbon/css3/_appearance.scss
deleted file mode 100644
index 548767e166..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_appearance.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-@mixin appearance ($value) {
- -webkit-appearance: $value;
- -moz-appearance: $value;
- -ms-appearance: $value;
- -o-appearance: $value;
- appearance: $value;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_background-image.scss b/lms/static/sass/course/old/bourbon/css3/_background-image.scss
deleted file mode 100644
index c23cef7c31..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_background-image.scss
+++ /dev/null
@@ -1,57 +0,0 @@
-//************************************************************************//
-// Background-image property for adding multiple background images with
-// gradients, or for stringing multiple gradients together.
-//************************************************************************//
-
-@mixin background-image(
- $image-1 , $image-2: false,
- $image-3: false, $image-4: false,
- $image-5: false, $image-6: false,
- $image-7: false, $image-8: false,
- $image-9: false, $image-10: false
-) {
- $images: compact($image-1, $image-2,
- $image-3, $image-4,
- $image-5, $image-6,
- $image-7, $image-8,
- $image-9, $image-10);
-
- background-image: add-prefix($images, webkit);
- background-image: add-prefix($images, moz);
- background-image: add-prefix($images, ms);
- background-image: add-prefix($images, o);
- background-image: add-prefix($images);
-}
-
-
-@function add-prefix($images, $vendor: false) {
- $images-prefixed: ();
-
- @for $i from 1 through length($images) {
- $type: type-of(nth($images, $i)); // Get type of variable - List or String
-
- // If variable is a list - Gradient
- @if $type == list {
- $gradient-type: nth(nth($images, $i), 1); // Get type of gradient (linear || radial)
- $gradient-args: nth(nth($images, $i), 2); // Get actual gradient (red, blue)
-
- $gradient: render-gradients($gradient-args, $gradient-type, $vendor);
- $images-prefixed: append($images-prefixed, $gradient, comma);
- }
-
- // If variable is a string - Image
- @else if $type == string {
- $images-prefixed: join($images-prefixed, nth($images, $i), comma);
- }
- }
- @return $images-prefixed;
-}
-
-
-
-//Examples:
- //@include background-image(linear-gradient(top, orange, red));
- //@include background-image(radial-gradient(50% 50%, cover circle, orange, red));
- //@include background-image(url("/images/a.png"), linear-gradient(orange, red));
- //@include background-image(url("image.png"), linear-gradient(orange, red), url("image.png"));
- //@include background-image(linear-gradient(hsla(0, 100%, 100%, 0.25) 0%, hsla(0, 100%, 100%, 0.08) 50%, transparent 50%), linear-gradient(orange, red);
diff --git a/lms/static/sass/course/old/bourbon/css3/_background-size.scss b/lms/static/sass/course/old/bourbon/css3/_background-size.scss
deleted file mode 100644
index 4bba11027d..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_background-size.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-@mixin background-size ($length-1,
- $length-2: false, $length-3: false,
- $length-4: false, $length-5: false,
- $length-6: false, $length-7: false,
- $length-8: false, $length-9: false)
- {
- $full: compact($length-1, $length-2, $length-3, $length-4,
- $length-5, $length-6, $length-7, $length-8, $length-9);
-
- -webkit-background-size: $full;
- -moz-background-size: $full;
- -ms-background-size: $full;
- -o-background-size: $full;
- background-size: $full;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_border-image.scss b/lms/static/sass/course/old/bourbon/css3/_border-image.scss
deleted file mode 100644
index 0373980422..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_border-image.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-@mixin border-image ($image) {
- -webkit-border-image: $image;
- -moz-border-image: $image;
- -ms-border-image: $image;
- -o-border-image: $image;
- border-image: $image;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_border-radius.scss b/lms/static/sass/course/old/bourbon/css3/_border-radius.scss
deleted file mode 100644
index f24389ebbe..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_border-radius.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-@mixin border-radius ($radii) {
- -webkit-border-radius: $radii;
- -moz-border-radius: $radii;
- -ms-border-radius: $radii;
- -o-border-radius: $radii;
- border-radius: $radii;
-}
-
-@mixin border-top-left-radius($radii) {
- -webkit-border-top-left-radius: $radii;
- -moz-border-top-left-radius: $radii;
- -moz-border-radius-topleft: $radii;
- -ms-border-top-left-radius: $radii;
- -o-border-top-left-radius: $radii;
- border-top-left-radius: $radii;
-}
-
-@mixin border-top-right-radius($radii) {
- -webkit-border-top-right-radius: $radii;
- -moz-border-top-right-radius: $radii;
- -moz-border-radius-topright: $radii;
- -ms-border-top-right-radius: $radii;
- -o-border-top-right-radius: $radii;
- border-top-right-radius: $radii;
-}
-
-@mixin border-bottom-left-radius($radii) {
- -webkit-border-bottom-left-radius: $radii;
- -moz-border-bottom-left-radius: $radii;
- -moz-border-radius-bottomleft: $radii;
- -ms-border-bottom-left-radius: $radii;
- -o-border-bottom-left-radius: $radii;
- border-bottom-left-radius: $radii;
-}
-
-@mixin border-bottom-right-radius($radii) {
- -webkit-border-bottom-right-radius: $radii;
- -moz-border-bottom-right-radius: $radii;
- -moz-border-radius-bottomright: $radii;
- -ms-border-bottom-right-radius: $radii;
- -o-border-bottom-right-radius: $radii;
- border-bottom-right-radius: $radii;
-}
-
-@mixin border-top-radius($radii) {
- @include border-top-left-radius($radii);
- @include border-top-right-radius($radii);
-}
-
-@mixin border-right-radius($radii) {
- @include border-top-right-radius($radii);
- @include border-bottom-right-radius($radii);
-}
-
-@mixin border-bottom-radius($radii) {
- @include border-bottom-left-radius($radii);
- @include border-bottom-right-radius($radii);
-}
-
-@mixin border-left-radius($radii) {
- @include border-top-left-radius($radii);
- @include border-bottom-left-radius($radii);
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_box-shadow.scss b/lms/static/sass/course/old/bourbon/css3/_box-shadow.scss
deleted file mode 100644
index 327b66d251..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_box-shadow.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-// Box-Shadow Mixin Requires Sass v3.1.1+
-@mixin box-shadow ($shadow-1,
- $shadow-2: false, $shadow-3: false,
- $shadow-4: false, $shadow-5: false,
- $shadow-6: false, $shadow-7: false,
- $shadow-8: false, $shadow-9: false)
- {
- $full: compact($shadow-1, $shadow-2, $shadow-3, $shadow-4,
- $shadow-5, $shadow-6, $shadow-7, $shadow-8, $shadow-9);
-
- -webkit-box-shadow: $full;
- -moz-box-shadow: $full;
- box-shadow: $full;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_box-sizing.scss b/lms/static/sass/course/old/bourbon/css3/_box-sizing.scss
deleted file mode 100644
index 3f3f7cca9a..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_box-sizing.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-@mixin box-sizing ($box) {
-// content-box | border-box | inherit
- -webkit-box-sizing: $box;
- -moz-box-sizing: $box;
- box-sizing: $box;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_columns.scss b/lms/static/sass/course/old/bourbon/css3/_columns.scss
deleted file mode 100644
index 2896c91d7f..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_columns.scss
+++ /dev/null
@@ -1,67 +0,0 @@
-@mixin columns($arg: auto) {
-// ||
- -webkit-columns: $arg;
- -moz-columns: $arg;
- columns: $arg;
-}
-
-@mixin column-count($int: auto) {
-// auto || integer
- -webkit-column-count: $int;
- -moz-column-count: $int;
- column-count: $int;
-}
-
-@mixin column-gap($length: normal) {
-// normal || length
- -webkit-column-gap: $length;
- -moz-column-gap: $length;
- column-gap: $length;
-}
-
-@mixin column-fill($arg: auto) {
-// auto || length
- -webkit-columns-fill: $arg;
- -moz-columns-fill: $arg;
- columns-fill: $arg;
-}
-
-@mixin column-rule($arg) {
-// || ||
- -webkit-column-rule: $arg;
- -moz-column-rule: $arg;
- column-rule: $arg;
-}
-
-@mixin column-rule-color($color) {
- -webkit-column-rule-color: $color;
- -moz-column-rule-color: $color;
- column-rule-color: $color;
-}
-
-@mixin column-rule-style($style: none) {
-// none | hidden | dashed | dotted | double | groove | inset | inset | outset | ridge | solid
- -webkit-column-rule-style: $style;
- -moz-column-rule-style: $style;
- column-rule-style: $style;
-}
-
-@mixin column-rule-width ($width: none) {
- -webkit-column-rule-width: $width;
- -moz-column-rule-width: $width;
- column-rule-width: $width;
-}
-
-@mixin column-span($arg: none) {
-// none || all
- -webkit-column-span: $arg;
- -moz-column-span: $arg;
- column-span: $arg;
-}
-
-@mixin column-width($length: auto) {
-// auto || length
- -webkit-column-width: $length;
- -moz-column-width: $length;
- column-width: $length;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_flex-box.scss b/lms/static/sass/course/old/bourbon/css3/_flex-box.scss
deleted file mode 100644
index 44c1dfd789..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_flex-box.scss
+++ /dev/null
@@ -1,67 +0,0 @@
-// CSS3 Flexible Box Model and property defaults
-
-// Custom shorthand notation for flexbox
-@mixin box($orient: inline-axis, $pack: start, $align: stretch) {
- @include display-box;
- @include box-orient($orient);
- @include box-pack($pack);
- @include box-align($align);
-}
-
-@mixin display-box {
- display: -webkit-box;
- display: -moz-box;
- display: box;
-}
-
-@mixin box-orient($orient: inline-axis) {
-// horizontal|vertical|inline-axis|block-axis|inherit
- -webkit-box-orient: $orient;
- -moz-box-orient: $orient;
- box-orient: $orient;
-}
-
-@mixin box-pack($pack: start) {
-// start|end|center|justify
- -webkit-box-pack: $pack;
- -moz-box-pack: $pack;
- box-pack: $pack;
-}
-
-@mixin box-align($align: stretch) {
-// start|end|center|baseline|stretch
- -webkit-box-align: $align;
- -moz-box-align: $align;
- box-align: $align;
-}
-
-@mixin box-direction($direction: normal) {
-// normal|reverse|inherit
- -webkit-box-direction: $direction;
- -moz-box-direction: $direction;
- box-direction: $direction;
-}
-@mixin box-lines($lines: single) {
-// single|multiple
- -webkit-box-lines: $lines;
- -moz-box-lines: $lines;
- box-lines: $lines;
-}
-
-@mixin box-ordinal-group($integer: 1) {
- -webkit-box-ordinal-group: $integer;
- -moz-box-ordinal-group: $integer;
- box-ordinal-group: $integer;
-}
-
-@mixin box-flex($value: 0.0) {
- -webkit-box-flex: $value;
- -moz-box-flex: $value;
- box-flex: $value;
-}
-
-@mixin box-flex-group($integer: 1) {
- -webkit-box-flex-group: $integer;
- -moz-box-flex-group: $integer;
- box-flex-group: $integer;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_inline-block.scss b/lms/static/sass/course/old/bourbon/css3/_inline-block.scss
deleted file mode 100644
index d79a13c851..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_inline-block.scss
+++ /dev/null
@@ -1,10 +0,0 @@
-// Legacy support for inline-block in IE7 (maybe IE6)
-@mixin inline-block {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_linear-gradient.scss b/lms/static/sass/course/old/bourbon/css3/_linear-gradient.scss
deleted file mode 100644
index e366a299a9..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_linear-gradient.scss
+++ /dev/null
@@ -1,41 +0,0 @@
-@mixin linear-gradient($pos, $G1, $G2: false,
- $G3: false, $G4: false,
- $G5: false, $G6: false,
- $G7: false, $G8: false,
- $G9: false, $G10: false,
- $fallback: false) {
- // Detect what type of value exists in $pos
- $pos-type: type-of(nth($pos, 1));
-
- // If $pos is missing from mixin, reassign vars and add default position
- @if ($pos-type == color) or (nth($pos, 1) == "transparent") {
- $G10: $G9; $G9: $G8; $G8: $G7; $G7: $G6; $G6: $G5;
- $G5: $G4; $G4: $G3; $G3: $G2; $G2: $G1; $G1: $pos;
- $pos: top; // Default position
- }
-
- $full: compact($G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
-
- // Set $G1 as the default fallback color
- $fallback-color: nth($G1, 1);
-
- // If $fallback is a color use that color as the fallback color
- @if (type-of($fallback) == color) or ($fallback == "transparent") {
- $fallback-color: $fallback;
- }
-
- background-color: $fallback-color;
- background-image: deprecated-webkit-gradient(linear, $full); // Safari <= 5.0
- background-image: -webkit-linear-gradient($pos, $full); // Safari 5.1+, Chrome
- background-image: -moz-linear-gradient($pos, $full);
- background-image: -ms-linear-gradient($pos, $full);
- background-image: -o-linear-gradient($pos, $full);
- background-image: unquote("linear-gradient(#{$pos}, #{$full})");
-}
-
-
-// Usage: Gradient position is optional, default is top. Position can be a degree. Color stops are optional as well.
-// @include linear-gradient(#1e5799, #2989d8);
-// @include linear-gradient(#1e5799, #2989d8, $fallback:#2989d8);
-// @include linear-gradient(top, #1e5799 0%, #2989d8 50%);
-// @include linear-gradient(50deg, rgba(10, 10, 10, 0.5) 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%);
diff --git a/lms/static/sass/course/old/bourbon/css3/_radial-gradient.scss b/lms/static/sass/course/old/bourbon/css3/_radial-gradient.scss
deleted file mode 100644
index e83cab5234..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_radial-gradient.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-// Requires Sass 3.1+
-@mixin radial-gradient($pos, $shape-size,
- $G1, $G2,
- $G3: false, $G4: false,
- $G5: false, $G6: false,
- $G7: false, $G8: false,
- $G9: false, $G10: false,
- $fallback: false) {
-
- $full: compact($G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
-
- // Set $G1 as the default fallback color
- $fallback-color: nth($G1, 1);
-
- // If $fallback is a color use that color as the fallback color
- @if (type-of($fallback) == color) or ($fallback == "transparent") {
- $fallback-color: $fallback;
- }
-
- background-color: $fallback-color;
- background-image: deprecated-webkit-gradient(radial, $full); // Safari <= 5.0
- background-image: -webkit-radial-gradient($pos, $shape-size, $full);
- background-image: -moz-radial-gradient($pos, $shape-size, $full);
- background-image: -ms-radial-gradient($pos, $shape-size, $full);
- background-image: -o-radial-gradient($pos, $shape-size, $full);
- background-image: unquote("radial-gradient(#{$pos}, #{$shape-size}, #{$full})");
-}
-
-// Usage: Gradient position and shape-size are required. Color stops are optional.
-// @include radial-gradient(50% 50%, circle cover, #1e5799, #efefef);
-// @include radial-gradient(50% 50%, circle cover, #eee 10%, #1e5799 30%, #efefef);
diff --git a/lms/static/sass/course/old/bourbon/css3/_transform.scss b/lms/static/sass/course/old/bourbon/css3/_transform.scss
deleted file mode 100644
index 8d19e8b88d..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_transform.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-@mixin transform($property: none) {
-// none |
- -webkit-transform: $property;
- -moz-transform: $property;
- -ms-transform: $property;
- -o-transform: $property;
- transform: $property;
-}
-
-@mixin transform-origin($axes: 50%) {
-// x-axis - left | center | right | length | %
-// y-axis - top | center | bottom | length | %
-// z-axis - length
- -webkit-transform-origin: $axes;
- -moz-transform-origin: $axes;
- -ms-transform-origin: $axes;
- -o-transform-origin: $axes;
- transform-origin: $axes;
-}
diff --git a/lms/static/sass/course/old/bourbon/css3/_transition.scss b/lms/static/sass/course/old/bourbon/css3/_transition.scss
deleted file mode 100644
index 058dbe0e33..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_transition.scss
+++ /dev/null
@@ -1,104 +0,0 @@
-// Shorthand mixin. Supports multiple parentheses-deliminated values for each variable.
-// Example: @include transition (all, 2.0s, ease-in-out);
-// @include transition ((opacity, width), (1.0s, 2.0s), ease-in, (0, 2s));
-// @include transition ($property:(opacity, width), $delay: (1.5s, 2.5s));
-
-@mixin transition ($property: all, $duration: 0.15s, $timing-function: ease-out, $delay: 0) {
-
- // Detect # of args passed into each variable
- $length-of-property: length($property);
- $length-of-duration: length($duration);
- $length-of-timing-function: length($timing-function);
- $length-of-delay: length($delay);
-
- @if $length-of-property > 1 {
- @include transition-property(zip($property)); }
- @else {
- @include transition-property( $property);
- }
-
- @if $length-of-duration > 1 {
- @include transition-duration(zip($duration)); }
- @else {
- @include transition-duration( $duration);
- }
-
- @if $length-of-timing-function > 1 {
- @include transition-timing-function(zip($timing-function)); }
- @else {
- @include transition-timing-function( $timing-function);
- }
-
- @if $length-of-delay > 1 {
- @include transition-delay(zip($delay)); }
- @else {
- @include transition-delay( $delay);
- }
-}
-
-
-@mixin transition-property ($prop-1: all,
- $prop-2: false, $prop-3: false,
- $prop-4: false, $prop-5: false,
- $prop-6: false, $prop-7: false,
- $prop-8: false, $prop-9: false)
- {
- $full: compact($prop-1, $prop-2, $prop-3, $prop-4, $prop-5,
- $prop-6, $prop-7, $prop-8, $prop-9);
-
- -webkit-transition-property: $full;
- -moz-transition-property: $full;
- -ms-transition-property: $full;
- -o-transition-property: $full;
- transition-property: $full;
-}
-
-@mixin transition-duration ($time-1: 0,
- $time-2: false, $time-3: false,
- $time-4: false, $time-5: false,
- $time-6: false, $time-7: false,
- $time-8: false, $time-9: false)
- {
- $full: compact($time-1, $time-2, $time-3, $time-4, $time-5,
- $time-6, $time-7, $time-8, $time-9);
-
- -webkit-transition-duration: $full;
- -moz-transition-duration: $full;
- -ms-transition-duration: $full;
- -o-transition-duration: $full;
- transition-duration: $full;
-}
-
-@mixin transition-timing-function ($motion-1: ease,
- $motion-2: false, $motion-3: false,
- $motion-4: false, $motion-5: false,
- $motion-6: false, $motion-7: false,
- $motion-8: false, $motion-9: false)
- {
- $full: compact($motion-1, $motion-2, $motion-3, $motion-4, $motion-5,
- $motion-6, $motion-7, $motion-8, $motion-9);
-
-// ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier()
- -webkit-transition-timing-function: $full;
- -moz-transition-timing-function: $full;
- -ms-transition-timing-function: $full;
- -o-transition-timing-function: $full;
- transition-timing-function: $full;
-}
-
-@mixin transition-delay ($time-1: 0,
- $time-2: false, $time-3: false,
- $time-4: false, $time-5: false,
- $time-6: false, $time-7: false,
- $time-8: false, $time-9: false)
- {
- $full: compact($time-1, $time-2, $time-3, $time-4, $time-5,
- $time-6, $time-7, $time-8, $time-9);
-
- -webkit-transition-delay: $full;
- -moz-transition-delay: $full;
- -ms-transition-delay: $full;
- -o-transition-delay: $full;
- transition-delay: $full;
-}
-
diff --git a/lms/static/sass/course/old/bourbon/css3/_user-select.scss b/lms/static/sass/course/old/bourbon/css3/_user-select.scss
deleted file mode 100644
index d5f5749431..0000000000
--- a/lms/static/sass/course/old/bourbon/css3/_user-select.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-@mixin user-select($arg: none) {
- -webkit-user-select: $arg;
- -moz-user-select: $arg;
- -ms-user-select: $arg;
- user-select: $arg;
-}
diff --git a/lms/static/sass/course/old/bourbon/functions/_deprecated-webkit-gradient.scss b/lms/static/sass/course/old/bourbon/functions/_deprecated-webkit-gradient.scss
deleted file mode 100644
index 1322f6f60e..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_deprecated-webkit-gradient.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-// Render Deprecated Webkit Gradient - Linear || Radial
-//************************************************************************//
-@function deprecated-webkit-gradient($type, $full) {
- $gradient-list: ();
- $gradient: false;
- $full-length: length($full);
- $percentage: false;
- $gradient-type: $type;
-
- @for $i from 1 through $full-length {
- $gradient: nth($full, $i);
-
- @if length($gradient) == 2 {
- $color-stop: color-stop(nth($gradient, 2), nth($gradient, 1));
- $gradient-list: join($gradient-list, $color-stop, comma);
- }
- @else {
- @if $i == $full-length {
- $percentage: 100%;
- }
- @else {
- $percentage: ($i - 1) * (100 / ($full-length - 1)) + "%";
- }
- $color-stop: color-stop(unquote($percentage), $gradient);
- $gradient-list: join($gradient-list, $color-stop, comma);
- }
- }
-
- @if $type == radial {
- $gradient: -webkit-gradient(radial, center center, 0, center center, 460, $gradient-list);
- }
- @else if $type == linear {
- $gradient: -webkit-gradient(linear, left top, left bottom, $gradient-list);
- }
- @return $gradient;
-}
diff --git a/lms/static/sass/course/old/bourbon/functions/_flex-grid.scss b/lms/static/sass/course/old/bourbon/functions/_flex-grid.scss
deleted file mode 100644
index 707f994e15..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_flex-grid.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-// Flexible grid
-@function flex-grid($columns, $container-columns: $fg-max-columns) {
- $width: $columns * $fg-column + ($columns - 1) * $fg-gutter;
- $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
- @return percentage($width / $container-width);
-}
-
-// Flexible gutter
-@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) {
- $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
- @return percentage($gutter / $container-width);
-}
-
-// The $fg-column, $fg-gutter and $fg-max-columns variables must be defined in your base stylesheet to properly use the flex-grid function.
-// This function takes the fluid grid equation (target / context = result) and uses columns to help define each.
-//
-// $fg-column: 60px; // Column Width
-// $fg-gutter: 25px; // Gutter Width
-// $fg-max-columns: 12; // Total Columns For Main Container
-//
-// div {
-// width: flex-grid(4); // returns (315px / 1020px) = 30.882353%;
-// margin-left: flex-gutter(); // returns (25px / 1020px) = 2.45098%;
-//
-// p {
-// width: flex-grid(2, 4); // returns (145px / 315px) = 46.031746%;
-// float: left;
-// margin: flex-gutter(4); // returns (25px / 315px) = 7.936508%;
-// }
-//
-// blockquote {
-// float: left;
-// width: flex-grid(2, 4); // returns (145px / 315px) = 46.031746%;
-// }
-// }
diff --git a/lms/static/sass/course/old/bourbon/functions/_grid-width.scss b/lms/static/sass/course/old/bourbon/functions/_grid-width.scss
deleted file mode 100644
index 8e63d83d60..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_grid-width.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-@function grid-width($n) {
- @return $n * $gw-column + ($n - 1) * $gw-gutter;
-}
-
-// The $gw-column and $gw-gutter variables must be defined in your base stylesheet to properly use the grid-width function.
-//
-// $gw-column: 100px; // Column Width
-// $gw-gutter: 40px; // Gutter Width
-//
-// div {
-// width: grid-width(4); // returns 520px;
-// margin-left: $gw-gutter; // returns 40px;
-// }
diff --git a/lms/static/sass/course/old/bourbon/functions/_linear-gradient.scss b/lms/static/sass/course/old/bourbon/functions/_linear-gradient.scss
deleted file mode 100644
index 3b10ca82a6..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_linear-gradient.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-@function linear-gradient($pos: top, $G1: false, $G2: false,
- $G3: false, $G4: false,
- $G5: false, $G6: false,
- $G7: false, $G8: false,
- $G9: false, $G10: false) {
-
- // Detect what type of value exists in $pos
- $pos-type: type-of(nth($pos, 1));
-
- // If $pos is missing from mixin, reassign vars and add default position
- @if ($pos-type == color) or (nth($pos, 1) == "transparent") {
- $G10: $G9; $G9: $G8; $G8: $G7; $G7: $G6; $G6: $G5;
- $G5: $G4; $G4: $G3; $G3: $G2; $G2: $G1; $G1: $pos;
- $pos: top; // Default position
- }
-
- $type: linear;
- $gradient: compact($pos, $G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
- $type-gradient: append($type, $gradient, comma);
-
- @return $type-gradient;
-}
-
diff --git a/lms/static/sass/course/old/bourbon/functions/_modular-scale.scss b/lms/static/sass/course/old/bourbon/functions/_modular-scale.scss
deleted file mode 100644
index dddccb5224..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_modular-scale.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-@function modular-scale($value, $increment, $ratio) {
- @if $increment > 0 {
- @for $i from 1 through $increment {
- $value: ($value * $ratio);
- }
- }
-
- @if $increment < 0 {
- $increment: abs($increment);
- @for $i from 1 through $increment {
- $value: ($value / $ratio);
- }
- }
-
- @return $value;
-}
-
-// div {
-// Increment Up GR with positive value
-// font-size: modular-scale(14px, 1, 1.618); // returns: 22.652px
-//
-// Increment Down GR with negative value
-// font-size: modular-scale(14px, -1, 1.618); // returns: 8.653px
-//
-// Can be used with ceil(round up) or floor(round down)
-// font-size: floor( modular-scale(14px, 1, 1.618) ); // returns: 22px
-// font-size: ceil( modular-scale(14px, 1, 1.618) ); // returns: 23px
-// }
-//
-// modularscale.com
-
-@function golden-ratio($value, $increment) {
- @return modular-scale($value, $increment, 1.618)
-}
-
-// div {
-// font-size: golden-ratio(14px, 1); // returns: 22.652px
-// }
-//
-// goldenratiocalculator.com
diff --git a/lms/static/sass/course/old/bourbon/functions/_radial-gradient.scss b/lms/static/sass/course/old/bourbon/functions/_radial-gradient.scss
deleted file mode 100644
index 3d5461ad6e..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_radial-gradient.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-// This function is required and used by the background-image mixin.
-@function radial-gradient($pos, $shape-size,
- $G1, $G2,
- $G3: false, $G4: false,
- $G5: false, $G6: false,
- $G7: false, $G8: false,
- $G9: false, $G10: false) {
-
- $type: radial;
- $gradient: compact($pos, $shape-size, $G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
- $type-gradient: append($type, $gradient, comma);
-
- @return $type-gradient;
-}
-
diff --git a/lms/static/sass/course/old/bourbon/functions/_render-gradients.scss b/lms/static/sass/course/old/bourbon/functions/_render-gradients.scss
deleted file mode 100644
index fe7c799ebe..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_render-gradients.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-// User for linear and radial gradients within background-image or border-image properties
-
-@function render-gradients($gradients, $gradient-type, $vendor: false) {
- $vendor-gradients: false;
- @if $vendor {
- $vendor-gradients: -#{$vendor}-#{$gradient-type}-gradient($gradients);
- }
-
- @else if $vendor == false {
- $vendor-gradients: "#{$gradient-type}-gradient(#{$gradients})";
- $vendor-gradients: unquote($vendor-gradients);
- }
- @return $vendor-gradients;
-}
diff --git a/lms/static/sass/course/old/bourbon/functions/_tint-shade.scss b/lms/static/sass/course/old/bourbon/functions/_tint-shade.scss
deleted file mode 100644
index f7172004ac..0000000000
--- a/lms/static/sass/course/old/bourbon/functions/_tint-shade.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-// Add percentage of white to a color
-@function tint($color, $percent){
- @return mix(white, $color, $percent);
-}
-
-// Add percentage of black to a color
-@function shade($color, $percent){
- @return mix(black, $color, $percent);
-}
diff --git a/lms/static/sass/course/old/bourbon/lib/bourbon.rb b/lms/static/sass/course/old/bourbon/lib/bourbon.rb
deleted file mode 100644
index 1635be836d..0000000000
--- a/lms/static/sass/course/old/bourbon/lib/bourbon.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require "bourbon/generator"
-
-module Bourbon
- if defined?(Rails)
- class Engine < ::Rails::Engine
- require 'bourbon/engine'
- end
-
- module Rails
- class Railtie < ::Rails::Railtie
- rake_tasks do
- load "tasks/install.rake"
- end
- end
- end
- end
-end
-
-require File.join(File.dirname(__FILE__), "/bourbon/sass_extensions")
diff --git a/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions.rb b/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions.rb
deleted file mode 100644
index ad567200e3..0000000000
--- a/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module Bourbon::SassExtensions
-end
-
-require "sass"
-
-require File.join(File.dirname(__FILE__), "/sass_extensions/functions")
diff --git a/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions/functions.rb b/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions/functions.rb
deleted file mode 100644
index daa877650e..0000000000
--- a/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions/functions.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module Bourbon::SassExtensions::Functions
-end
-
-require File.join(File.dirname(__FILE__), "/functions/compact")
-
-module Sass::Script::Functions
- include Bourbon::SassExtensions::Functions::Compact
-end
-
-# Wierd that this has to be re-included to pick up sub-modules. Ruby bug?
-class Sass::Script::Functions::EvaluationContext
- include Sass::Script::Functions
-end
diff --git a/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions/functions/compact.rb b/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions/functions/compact.rb
deleted file mode 100644
index 5192e921e7..0000000000
--- a/lms/static/sass/course/old/bourbon/lib/bourbon/sass_extensions/functions/compact.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# Compact function pulled from compass
-module Bourbon::SassExtensions::Functions::Compact
-
- def compact(*args)
- sep = :comma
- if args.size == 1 && args.first.is_a?(Sass::Script::List)
- args = args.first.value
- sep = args.first.separator
- end
- Sass::Script::List.new(args.reject{|a| !a.to_bool}, sep)
- end
-
-end
diff --git a/lms/static/sass/course/old/layout/_footer.scss b/lms/static/sass/course/old/layout/_footer.scss
deleted file mode 100644
index 8957555e1a..0000000000
--- a/lms/static/sass/course/old/layout/_footer.scss
+++ /dev/null
@@ -1,97 +0,0 @@
-footer {
- @extend .clearfix;
- @extend .wrapper;
- @include box-sizing(border-box);
- color: #777;
- margin-top: $body-line-height;
- padding: 0 $body-line-height;
-
- @media print {
- display: none;
- }
-
- p {
- float: left;
-
- a {
- color: #444;
-
- &:link, &:visited {
- color: #444;
- }
-
- &:hover, &:focus {
- color: #000;
- }
- }
- }
-
- nav {
- float: right;
-
- ul {
- float: left;
-
- li {
- display: inline-block;
- margin-right: 20px;
-
- a {
- color: #444;
-
- &:link, &:visited {
- color: #444;
- }
-
- &:hover, &:focus {
- color: #000;
- }
- }
- }
-
- &.social {
- margin-right: 40px;
- position: relative;
- top: -5px;
-
- @media screen and (max-width: 780px) {
- float: none;
- }
-
- li {
- float: left;
- margin-right: lh(.5);
-
- &:after {
- content: none;
- display: none;
- }
-
- a {
- border-bottom: 0;
- display: block;
- height: 29px;
- text-indent: -9999px;
- width: 28px;
-
- &:hover {
- opacity: .8;
- }
- }
-
- &.twitter a {
- background: url('../images/social/twitter.png') 0 0 no-repeat;
- }
-
- &.facebook a {
- background: url('../images/social/facebook.png') 0 0 no-repeat;
- }
-
- &.linkedin a {
- background: url('../images/social/linkedin.png') 0 0 no-repeat;
- }
- }
- }
- }
- }
-}
diff --git a/lms/static/sass/course/old/layout/_header.scss b/lms/static/sass/course/old/layout/_header.scss
deleted file mode 100644
index fc897df7eb..0000000000
--- a/lms/static/sass/course/old/layout/_header.scss
+++ /dev/null
@@ -1,183 +0,0 @@
-div.header-wrapper {
- background: $mit-red;
- border-bottom: 1px solid #fff;
- @include box-shadow(inset 0 -4px 6px darken($mit-red, 5%));
-
- @media print {
- display: none;
- }
-
- header {
- @extend .clearfix;
- @extend .wrapper;
- @include box-sizing(border-box);
- padding: 0 $body-line-height;
-
- hgroup {
- @extend .clearfix;
- float: left;
- min-width: flex-grid(3);
- padding-top: 13px;
-
- h1 {
- color: darken($mit-red, 25%);
- font-size: 18px;
- font-weight: 800;
- @include inline-block();
- line-height: lh();
- margin: 0;
- padding: 0 lh(.5) 0 0;
- text-shadow: 0 1px 0 lighten($mit-red, 10%);
-
- &:after {
- color: darken($mit-red, 10%);
- content: "•";
- display: inline-block;
- font-size: 10px;
- letter-spacing: -2px;
- padding-left: lh(.5);
- text-shadow: 0;
- }
- }
-
- h2 {
- font-size: 16px;
- @include inline-block();
- letter-spacing: 0;
- margin: 0;
- padding: 0 lh() 0px 0;
- text-shadow: 0 -1px 0 darken($mit-red, 10%);
- text-transform: none;
- -webkit-font-smoothing: antialiased;
-
- a {
- color: #fff;
- border: none;
-
- &:hover {
- color: rgba(#fff, .7);
- }
- }
- }
-
-
- @media screen and (max-width: 900px) {
- display: block;
- float: none;
-
- h1 {
- border: 0;
- float: left;
- }
-
- h2 {
- border: 0;
- float: left;
- margin-right: 0;
- }
- }
- }
-
- nav {
- background: #501016;
- border-bottom: 1px solid darken(#501016, 10%);
- @include border-radius(3px 3px 0 0);
- @include box-shadow(inset 0 0 0 1px darken(#501016, 5%), inset 0 2px 0 lighten(#501016, 5%));
- display: block;
- float: left;
- margin: 5px 0 0;
- padding: 0;
- text-shadow: 0 -1px 0 darken($mit-red, 10%);
- -webkit-font-smoothing: antialiased;
-
- ul {
- @extend .clearfix;
- margin: 0;
-
- li {
- line-height: lh();
- margin-bottom: 0;
- float: left;
-
- a {
- border: none;
- color: #fff;
- display: block;
- font-style: normal;
- font-weight: bold;
- padding: 10px lh() 8px;
-
- @media screen and (max-width: 1020px) {
- padding: 10px lh(.7) 8px;
- }
-
- &:hover {
- color: rgba(#fff, .7);
- background-color: none;
- }
- }
- }
- }
-
- @media screen and (max-width: 900px) {
- width: 100%;
- float: none;
-
- ul {
- li {
- display: table-cell;
- padding: auto;
- text-align: center;
- width: 16.6666666667%;
- }
- }
- }
-
- .active {
- background: #F4F4F4;
- border: 1px solid darken(#501016, 10%);
- border-bottom: 0;
- @include border-radius(3px 3px 0 0);
- @include box-shadow(0 2px 0 #f4f4f4, inset 0 1px 0 #fff);
- color: #333;
- text-shadow: 0 1px 0 #fff;
- }
-
- &.courseware {
- li.courseware a {
- @extend .active;
- }
- }
-
- &.book {
- li.book a {
- @extend .active;
- }
- }
-
- &.info {
- li.info a {
- @extend .active;
- }
- }
-
- &.discussion {
- li.discussion a {
- @extend .active;
- }
- }
-
- &.wiki {
- li.wiki a {
- @extend .active;
- }
- }
-
- &.profile {
- li.profile a {
- @extend .active;
- }
- }
- }
- }
-}
diff --git a/lms/static/sass/course/old/layout/_layout.scss b/lms/static/sass/course/old/layout/_layout.scss
deleted file mode 100644
index 7f4645dd5a..0000000000
--- a/lms/static/sass/course/old/layout/_layout.scss
+++ /dev/null
@@ -1,55 +0,0 @@
-html {
- margin-top: 0;
-
- body {
- background: #f4f4f4; //#f3f1e5
- color: $dark-gray;
- font: $body-font-size $body-font-family;
- margin: 0;
- text-align: center;
-
- section.main-content {
- @extend .clearfix;
- @extend .wrapper;
- background: #fff;
- border: 1px solid #bbb;
- border-bottom: 1px solid #bbb;
- @include box-shadow(0 0 4px #dfdfdf);
- @include box-sizing(border-box);
- margin-top: 3px;
-
- @media print {
- border-bottom: 0;
- @include border-radius(none);
- }
-
- @media screen and (min-width: 1400px) {
- @include border-radius(4px);
- margin-top: lh(.5);
- overflow: hidden;
- }
- }
-
- div.qtip {
- div.ui-tooltip-content {
- background: #000;
- background: rgba(#000, .8);
- border: none;
- color: #fff;
- font: 12px $body-font-family;
- margin-right: -20px;
- margin-top: -30px;
- }
- }
-
- section.outside-app {
- @extend .main-content;
- max-width: 600px;
- padding: lh();
-
- #{$all-text-inputs} {
- display: block;
- }
- }
- }
-}
diff --git a/lms/static/sass/course/old/layout/_leanmodal.scss b/lms/static/sass/course/old/layout/_leanmodal.scss
deleted file mode 100644
index 0c96e6524a..0000000000
--- a/lms/static/sass/course/old/layout/_leanmodal.scss
+++ /dev/null
@@ -1,251 +0,0 @@
-#lean_overlay {
- background: #000;
- display: none;
- height:100%;
- left: 0px;
- position: fixed;
- top: 0px;
- width:100%;
- z-index:100;
-}
-
-div.leanModal_box {
- background: #fff;
- border: none;
- @include border-radius(3px);
- @include box-shadow(0 0 6px #000);
- @include box-sizing(border-box);
- display: none;
- padding: lh(2);
- text-align: left;
-
- a.modal_close {
- color: #aaa;
- display: block;
- font-style: normal;
- height: 14px;
- position: absolute;
- right: 12px;
- top: 12px;
- width: 14px;
- z-index: 2;
-
- &:hover{
- color: $mit-red;
- text-decoration: none;
- }
- }
-
- h1 {
- border-bottom: 1px solid #eee;
- font-size: 24px;
- margin-bottom: lh();
- margin-top: 0;
- padding-bottom: lh();
- text-align: left;
- }
-
- enroll {
- max-width: 600px;
-
- ol {
- @extend .clearfix;
- padding-top: lh();
-
- li {
-
- &.terms, &.honor-code {
- float: none;
- width: auto;
- }
-
- div.tip {
- display: none;
- }
-
- &:hover {
- div.tip {
- background: #333;
- color: #fff;
- display: block;
- font-size: 16px;
- line-height: lh();
- margin: 0 0 0 -10px;
- padding: 10px;
- position: absolute;
- -webkit-font-smoothing: antialiased;
- width: 500px;
- }
- }
- }
- }
- }
-
- form {
- text-align: left;
-
- div#register_error, div#login_error, div#pwd_error {
- $error-color: #333;
- background-color: $error-color;
- border: darken($error-color, 20%);
- color: #fff;
- font-family: "Open sans";
- font-weight: bold;
- letter-spacing: 1px;
- margin: (-(lh())) (-(lh())) lh();
- padding: lh(.5);
- text-shadow: 0 1px 0 darken($error-color, 10%);
- -webkit-font-smoothing: antialiased;
-
- &:empty {
- padding: 0;
- }
- }
-
- ol {
- list-style: none;
- margin-bottom: lh();
-
- li {
- margin-bottom: lh(.5);
-
- &.terms, &.remember {
- border-top: 1px solid #eee;
- clear: both;
- float: none;
- padding-top: lh();
- width: auto;
- }
-
- &.honor-code {
- float: none;
- width: auto;
- }
-
- label {
- display: block;
- font-weight: bold;
- }
-
- #{$all-text-inputs}, textarea {
- @include box-sizing(border-box);
- width: 100%;
- }
-
- input[type="checkbox"] {
- margin-right: 10px;
- }
-
- ul {
- list-style: disc outside none;
- margin: lh(.5) 0 lh() lh();
-
- li {
- color: #666;
- float: none;
- font-size: 14px;
- list-style: disc outside none;
- margin-bottom: lh(.5);
- }
- }
- }
- }
-
- input[type="button"], input[type="submit"] {
- @include button($mit-red);
- font-size: 18px;
- padding: lh(.5);
- }
- }
-}
-
-div#login {
- min-width: 400px;
-
- header {
- border-bottom: 1px solid #ddd;
- margin-bottom: lh();
- padding-bottom: lh();
-
- h1 {
- border-bottom: 0;
- padding-bottom: 0;
- margin-bottom: lh(.25);
- }
- }
-
- ol {
- li {
- float: none;
- width: auto;
- }
- }
-}
-
-div.lost-password {
- margin-top: lh();
- text-align: left;
-
- a {
- color: #999;
-
- &:hover {
- color: #444;
- }
- }
-}
-
-div#pwd_reset {
- p {
- margin-bottom: lh();
- }
-
- input[type="email"] {
- margin-bottom: lh();
- }
-}
-
-div#apply_name_change,
-div#change_email,
-div#unenroll,
-div#deactivate-account {
- max-width: 700px;
-
- ul {
- list-style: none;
-
- li {
- margin-bottom: lh(.5);
-
- textarea, #{$all-text-inputs} {
- @include box-sizing(border-box);
- display: block;
- width: 100%;
- }
-
- textarea {
- height: 60px;
- }
-
- input[type="submit"] {
- white-space: normal;
- }
- }
- }
-}
-
-div#feedback_div{
- form{
- ol {
- li {
- float: none;
- width: 100%;
-
- textarea#feedback_message {
- height: 100px;
- }
- }
- }
- }
-}
-
diff --git a/lms/static/sass/course/old/marketing-ie.scss b/lms/static/sass/course/old/marketing-ie.scss
deleted file mode 100644
index c92fd2f7fb..0000000000
--- a/lms/static/sass/course/old/marketing-ie.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-body {
- margin: 0;
- padding: 0;
-}
-
-.wrapper, .subpage, section.copyright, section.tos, section.privacy-policy, section.honor-code, header.announcement div, section.index-content, footer {
- margin: 0;
- overflow: hidden;
-}
-
-div#enroll {
- form {
- display: none;
- }
-}
diff --git a/lms/static/sass/course/old/marketing.scss b/lms/static/sass/course/old/marketing.scss
deleted file mode 100644
index c0e9488016..0000000000
--- a/lms/static/sass/course/old/marketing.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-@import "bourbon/bourbon";
-@import "base/reset", "base/font-face", "base/functions";
-
-// pages
-@import "marketing/variables", "marketing/extends", "marketing/base", "marketing/header", "marketing/footer", "marketing/index";
-@import "layout/leanmodal";
diff --git a/lms/static/sass/course/old/marketing/_base.scss b/lms/static/sass/course/old/marketing/_base.scss
deleted file mode 100644
index c2a5b9dcc2..0000000000
--- a/lms/static/sass/course/old/marketing/_base.scss
+++ /dev/null
@@ -1,44 +0,0 @@
-body {
- background-color: #fff;
- color: #444;
- font: $body-font-size $body-font-family;
-
- :focus {
- outline-color: #ccc;
- }
-
- h1 {
- font: 800 24px $header-font-family;
- }
-
- li {
- margin-bottom: lh();
- }
-
- em {
- font-style: italic;
- }
-
- a {
- color: $mit-red;
- font-style: italic;
- text-decoration: none;
-
- &:hover, &:focus {
- color: darken($mit-red, 10%);
- }
- }
-
- #{$all-text-inputs}, textarea {
- @include box-shadow(0 -1px 0 #fff);
- @include linear-gradient(#eee, #fff);
- border: 1px solid #999;
- font: $body-font-size $body-font-family;
- padding: 4px;
- width: 100%;
-
- &:focus {
- border-color: $mit-red;
- }
- }
-}
diff --git a/lms/static/sass/course/old/marketing/_extends.scss b/lms/static/sass/course/old/marketing/_extends.scss
deleted file mode 100644
index 04bd5b83b6..0000000000
--- a/lms/static/sass/course/old/marketing/_extends.scss
+++ /dev/null
@@ -1,94 +0,0 @@
-.wrapper {
- @include box-sizing(border-box);
- margin: 0 auto;
- max-width: $fg-max-width;
- // min-width: $fg-min-width;
- padding: lh();
- width: flex-grid(12);
-}
-
-.subpage {
- @extend .clearfix;
- @extend .wrapper;
-
- > div {
- padding-left: flex-grid(4) + flex-gutter();
-
- @media screen and (max-width: 940px) {
- padding-left: 0;
- }
-
- p {
- margin-bottom: lh();
- line-height: lh();
- }
-
- h1 {
- margin-bottom: lh(.5);
- }
-
- h2 {
- font: 18px $header-font-family;
- color: #000;
- margin-bottom: lh(.5);
- }
-
- ul {
- list-style: disc outside none;
-
- li {
- list-style: disc outside none;
- line-height: lh();
- }
- }
-
- dl {
- margin-bottom: lh();
-
- dd {
- margin-bottom: lh(.5);
- }
- }
- }
-}
-
-.clearfix:after {
- content: ".";
- display: block;
- height: 0;
- clear: both;
- visibility: hidden;
-}
-
-.button {
- @include border-radius(3px);
- @include inline-block();
- @include transition();
- background-color: $mit-red;
- border: 1px solid darken($mit-red, 10%);
- color: #fff;
- margin: lh() 0 lh(.5);
- padding: lh(.25) lh(.5);
- text-decoration: none;
- font-style: normal;
- @include box-shadow(inset 0 1px 0 lighten($mit-red, 8%));
- -webkit-font-smoothing: antialiased;
-
- &:hover {
- background-color: darken($mit-red, 10%);
- border-color: darken($mit-red, 20%);
- }
-
- span {
- font-family: Garamond, Baskerville, "Baskerville Old Face", "Hoefler Text", "Times New Roman", serif;
- font-style: italic;
- }
-}
-
-p.ie-warning {
- display: block !important;
- line-height: 1.3em;
- background: yellow;
- margin-bottom: lh();
- padding: lh();
-}
diff --git a/lms/static/sass/course/old/marketing/_footer.scss b/lms/static/sass/course/old/marketing/_footer.scss
deleted file mode 100644
index 6fddb8ca91..0000000000
--- a/lms/static/sass/course/old/marketing/_footer.scss
+++ /dev/null
@@ -1,101 +0,0 @@
-footer {
- @extend .wrapper;
- @extend .clearfix;
- padding-top: 0;
-
- div.footer-wrapper {
- border-top: 1px solid #e5e5e5;
- padding: lh() 0;
- background: url('../images/marketing/mit-logo.png') right center no-repeat;
-
- @media screen and (max-width: 780px) {
- background-position: left bottom;
- padding-bottom: lh(3);
- }
-
- a {
- color: #888;
- text-decoration: none;
- @include transition();
-
- &:hover, &:focus {
- color: #666;
- }
- }
-
- p {
- @include inline-block();
- margin-right: lh();
- }
-
- ul {
- @include inline-block();
-
- @media screen and (max-width: 780px) {
- margin-top: lh();
- }
-
- li {
- @include inline-block();
- margin-bottom: 0;
-
- &:after {
- content: ' |';
- display: inline;
- color: #ccc;
- }
-
- &:last-child {
- &:after {
- content: none;
- }
- }
-
- }
-
- &.social {
- float: right;
- margin-right: 60px;
- position: relative;
- top: -5px;
-
- @media screen and (max-width: 780px) {
- float: none;
- }
-
- li {
- float: left;
- margin-right: lh(.5);
-
- &:after {
- content: none;
- display: none;
- }
-
- a {
- display: block;
- height: 29px;
- width: 28px;
- text-indent: -9999px;
-
- &:hover {
- opacity: .8;
- }
- }
-
- &.twitter a {
- background: url('../images/marketing/twitter.png') 0 0 no-repeat;
- }
-
- &.facebook a {
- background: url('../images/marketing/facebook.png') 0 0 no-repeat;
- }
-
- &.linkedin a {
- background: url('../images/marketing/linkedin.png') 0 0 no-repeat;
- }
- }
- }
- }
- }
-}
diff --git a/lms/static/sass/course/old/marketing/_header.scss b/lms/static/sass/course/old/marketing/_header.scss
deleted file mode 100644
index 9ea3bed0d5..0000000000
--- a/lms/static/sass/course/old/marketing/_header.scss
+++ /dev/null
@@ -1,169 +0,0 @@
-header.announcement {
- @include background-size(cover);
- background: #333;
- border-bottom: 1px solid #000;
- color: #fff;
- -webkit-font-smoothing: antialiased;
-
- &.home {
- background: #e3e3e3 url("../images/marketing/shot-5-medium.jpg");
-
- @media screen and (min-width: 1200px) {
- background: #e3e3e3 url("../images/marketing/shot-5-large.jpg");
- }
-
- div {
- padding: lh(10) lh() lh(3);
-
- @media screen and (max-width:780px) {
- padding: lh(2.5) lh() lh(2);
- }
-
- //hide login link for homepage
- nav {
- h1 {
- margin-right: 0;
- }
-
- a.login {
- display: none;
- }
- }
- }
- }
-
- &.course {
- background: #e3e3e3 url("../images/marketing/course-bg-small.jpg");
-
- @media screen and (min-width: 1200px) {
- background: #e3e3e3 url("../images/marketing/course-bg-large.jpg");
- }
-
- @media screen and (max-width: 1199px) and (min-width: 700px) {
- background: #e3e3e3 url("../images/marketing/course-bg-medium.jpg");
- }
-
- div {
- padding: lh(4) lh() lh(2);
-
- @media screen and (max-width:780px) {
- padding: lh(2.5) lh() lh(2);
- }
- }
-
- }
-
- div {
- @extend .wrapper;
- position: relative;
-
- nav {
- position: absolute;
- top: 0;
- right: lh();
- @include border-radius(0 0 3px 3px);
- background: #333;
- background: rgba(#000, .7);
- padding: lh(.5) lh();
-
- h1 {
- @include inline-block();
- margin-right: lh(.5);
-
-
- a {
- font: italic 800 18px $header-font-family;
- color: #fff;
- text-decoration: none;
-
- &:hover, &:focus {
- color: #999;
- }
- }
- }
-
- a.login {
- text-decoration: none;
- color: #fff;
- font-size: 12px;
- font-style: normal;
- font-family: $header-font-family;
-
- &:hover, &:focus {
- color: #999;
- }
- }
- }
-
- section {
- @extend .clearfix;
- background: $mit-red;
- @include inline-block();
- margin-left: flex-grid(4) + flex-gutter();
- padding: lh() lh(1.5);
-
- @media screen and (max-width: 780px) {
- margin-left: 0;
- }
-
- h1 {
- font-family: "Open Sans";
- font-size: 30px;
- font-weight: 800;
- @include inline-block();
- line-height: 1.2em;
- margin: 0 lh() 0 0;
- }
-
- h2 {
- font-family: "Open Sans";
- font-size: 24px;
- font-weight: 400;
- @include inline-block();
- line-height: 1.2em;
- }
-
- &.course {
- section {
- float: left;
- margin-left: 0;
- margin-right: flex-gutter(8);
- padding: 0;
- width: flex-grid(4, 8);
-
- @media screen and (max-width: 780px) {
- float: none;
- width: 100%;
- margin-right: 0;
- }
-
- a {
- @extend .button;
- background-color: darken($mit-red, 20%);
- border-color: darken($mit-red, 30%);
- @include box-shadow(inset 0 1px 0 darken($mit-red, 10%), 0 1px 0 lighten($mit-red, 5%));
- display: block;
- padding: lh(.5) lh();
- text-align: center;
-
- &:hover {
- background-color: darken($mit-red, 10%);
- border-color: darken($mit-red, 20%);
- }
- }
- }
-
- p {
- width: flex-grid(4, 8);
- line-height: lh();
- float: left;
-
- @media screen and (max-width: 780px) {
- float: none;
- width: 100%;
- }
- }
- }
- }
- }
-}
diff --git a/lms/static/sass/course/old/marketing/_index.scss b/lms/static/sass/course/old/marketing/_index.scss
deleted file mode 100644
index 1b84b51536..0000000000
--- a/lms/static/sass/course/old/marketing/_index.scss
+++ /dev/null
@@ -1,337 +0,0 @@
-section.index-content {
- @extend .wrapper;
- @extend .clearfix;
-
- section {
- @extend .clearfix;
- float: left;
-
- @media screen and (max-width: 780px) {
- float: none;
- width: auto;
- margin-right: 0;
- }
-
- h1 {
- font-size: 800 24px "Open Sans";
- margin-bottom: lh();
- }
-
- p {
- line-height: lh();
- margin-bottom: lh();
-
- }
-
- ul {
- margin: 0;
- }
-
- &.about {
- @include box-sizing(border-box);
- border-right: 1px solid #e5e5e5;
- margin-right: flex-gutter();
- padding-right: flex-gutter() / 2;
- width: flex-grid(8);
-
- @media screen and (max-width: 780px) {
- width: 100%;
- border-right: 0;
- margin-right: 0;
- padding-right: 0;
- }
-
- section {
- @extend .clearfix;
- margin-bottom: lh();
-
- p {
- width: flex-grid(4, 8);
- float: left;
-
- @media screen and (max-width: 780px) {
- float: none;
- width: auto;
- }
-
- &:nth-child(odd) {
- margin-right: flex-gutter(8);
-
- @media screen and (max-width: 780px) {
- margin-right: 0;
- }
- }
- }
-
- &.intro {
- section {
- margin-bottom: 0;
-
- &.intro-text {
- margin-right: flex-gutter(8);
- width: flex-grid(4, 8);
-
- @media screen and (max-width: 780px) {
- margin-right: 0;
- width: auto;
- }
-
- p {
- margin-right: 0;
- width: auto;
- float: none;
- }
- }
-
- &.intro-video {
- width: flex-grid(4, 8);
-
- @media screen and (max-width: 780px) {
- width: auto;
- }
-
- a {
- display: block;
- width: 100%;
-
- img {
- width: 100%;
- }
-
- span {
- display: none;
- }
- }
- }
- }
- }
-
- &.features {
- border-top: 1px solid #E5E5E5;
- padding-top: lh();
- margin-bottom: 0;
-
- h2 {
- text-transform: uppercase;
- letter-spacing: 1px;
- color: #888;
- margin-bottom: lh();
- font-weight: normal;
- font-size: 14px;
-
- span {
- text-transform: none;
-
- }
- }
-
- p {
- width: auto;
- clear: both;
-
- strong {
- font-family: "Open sans";
- font-weight: 800;
- }
-
- a {
- color: $mit-red;
- text-decoration: none;
- @include transition();
-
- &:hover, &:focus {
- color: darken($mit-red, 15%);
- }
- }
- }
-
- ul {
- margin-bottom: 0;
-
- li {
- line-height: lh();
- width: flex-grid(4, 8);
- float: left;
- margin-bottom: lh(.5);
-
- @media screen and (max-width: 780px) {
- width: auto;
- float: none;
- }
-
- &:nth-child(odd) {
- margin-right: flex-gutter(8);
-
- @media screen and (max-width: 780px) {
- margin-right: 0;
- }
- }
- }
- }
- }
- }
- }
-
- &.course, &.staff {
- width: flex-grid(4);
-
- @media screen and (max-width: 780px) {
- width: auto;
- }
-
- h1 {
- color: #888;
- font: normal $body-font-size $body-font-family;
- font-size: 14px;
- letter-spacing: 1px;
- margin-bottom: lh();
- text-transform: uppercase;
- }
-
- h2 {
- font: 800 24px $header-font-family;
- }
-
- h3 {
- font: 400 18px $header-font-family;
- }
-
- a {
- @extend .button;
-
- span.arrow {
- color: rgba(#fff, .6);
- font-style: normal;
- @include inline-block();
- padding-left: 10px;
- }
- }
-
- ul {
- list-style: none;
-
- li {
- img {
- float: left;
- margin-right: lh(.5);
- }
- }
- }
- }
-
- &.course {
- h2 {
- padding-top: lh(5);
- background: url('../images/marketing/circuits-bg.jpg') 0 0 no-repeat;
- @include background-size(contain);
-
- @media screen and (max-width: 998px) and (min-width: 781px){
- background: url('../images/marketing/circuits-medium-bg.jpg') 0 0 no-repeat;
- }
-
- @media screen and (max-width: 780px) {
- padding-top: lh(5);
- background: url('../images/marketing/circuits-bg.jpg') 0 0 no-repeat;
- }
-
- @media screen and (min-width: 500px) and (max-width: 781px) {
- padding-top: lh(8);
- }
- }
-
- div.announcement {
- p.announcement-button {
- a {
- margin-top: 0;
- }
- }
-
- img {
- max-width: 100%;
- margin-bottom: lh();
- }
- }
- }
-
-
- // index
- //---------------------------------------- //
- &.about-course {
- @include box-sizing(border-box);
- border-right: 1px solid #e5e5e5;
- margin-right: flex-gutter();
- padding-right: flex-gutter() / 2;
- width: flex-grid(8);
-
- @media screen and (max-width: 780px) {
- width: auto;
- border-right: 0;
- margin-right: 0;
- padding-right: 0;
- }
-
- section {
- width: flex-grid(4, 8);
-
- @media screen and (max-width: 780px) {
- width: auto;
- }
-
- &.about-info {
- margin-right: flex-gutter(8);
-
- @media screen and (max-width: 780px) {
- margin-right: 0;
- }
- }
-
- &.requirements {
- clear: both;
- width: 100%;
- border-top: 1px solid #E5E5E5;
- padding-top: lh();
- margin-bottom: 0;
-
- p {
- float: left;
- width: flex-grid(4, 8);
- margin-right: flex-gutter(8);
-
- @media screen and (max-width: 780px) {
- margin-right: 0;
- float: none;
- width: auto;
- }
-
- &:nth-child(odd) {
- margin-right: 0;
- }
- }
- }
-
- &.cta {
- width: 100%;
- text-align: center;
-
- a.enroll {
- @extend .button;
- padding: lh(.5) lh(2);
- @include inline-block();
- text-align: center;
- font: 800 18px $header-font-family;
- }
- }
- }
- }
-
- &.staff {
- h1 {
- margin-top: lh(1);
- }
- }
- }
-}
-
-section.copyright, section.tos, section.privacy-policy, section.honor-code {
- @extend .subpage;
-}
diff --git a/lms/static/sass/course/old/marketing/_variables.scss b/lms/static/sass/course/old/marketing/_variables.scss
deleted file mode 100644
index 6d9730b9db..0000000000
--- a/lms/static/sass/course/old/marketing/_variables.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-// Variables
-//---------------------------------------- //
-// // grid
-$fg-column: 60px;
-$fg-gutter: 25px;
-$fg-max-columns: 12;
-$fg-max-width: 1400px;
-$fg-min-width: 781px;
-
-$gw-column: 60px;
-$gw-gutter: 25px;
-
-$body-font-family: Georgia, serif;
-$header-font-family: "Open Sans", Helvetica, Arial, sans-serif;
-
-$body-font-size: 16px;
-$body-line-height: golden-ratio($body-font-size, 1);
-
-// Colors
-$mit-red: #933;
-$cream: #F6EFD4;
diff --git a/lms/static/sass/course/old/wiki/_basic-html.scss b/lms/static/sass/course/wiki/_basic-html.scss
similarity index 100%
rename from lms/static/sass/course/old/wiki/_basic-html.scss
rename to lms/static/sass/course/wiki/_basic-html.scss
diff --git a/lms/static/sass/course/old/wiki/_create.scss b/lms/static/sass/course/wiki/_create.scss
similarity index 100%
rename from lms/static/sass/course/old/wiki/_create.scss
rename to lms/static/sass/course/wiki/_create.scss
diff --git a/lms/static/sass/course/old/wiki/_sidebar.scss b/lms/static/sass/course/wiki/_sidebar.scss
similarity index 100%
rename from lms/static/sass/course/old/wiki/_sidebar.scss
rename to lms/static/sass/course/wiki/_sidebar.scss
diff --git a/lms/static/sass/course/old/wiki/_table.scss b/lms/static/sass/course/wiki/_table.scss
similarity index 100%
rename from lms/static/sass/course/old/wiki/_table.scss
rename to lms/static/sass/course/wiki/_table.scss
diff --git a/lms/static/sass/course/old/wiki/_wiki.scss b/lms/static/sass/course/wiki/_wiki.scss
similarity index 100%
rename from lms/static/sass/course/old/wiki/_wiki.scss
rename to lms/static/sass/course/wiki/_wiki.scss
diff --git a/lms/static/sass/shared/_modal.scss b/lms/static/sass/shared/_modal.scss
index 7e90eeb01d..f580b034cb 100644
--- a/lms/static/sass/shared/_modal.scss
+++ b/lms/static/sass/shared/_modal.scss
@@ -148,6 +148,16 @@
label {
display: none;
+
+ &.field-error {
+ display: block;
+ color: #8F0E0E;
+
+ + input {
+ border: 1px solid #CA1111;
+ color: #8F0E0E;
+ }
+ }
}
input[type="checkbox"] {
@@ -187,6 +197,10 @@
background: rgb(230,230,230);
}
+ &.field-error {
+ border: 1px solid #CA1111;
+ }
+
a {
font-family: $serif;
font-style: italic;
diff --git a/lms/templates/accordion.html b/lms/templates/accordion.html
index d9e6cee61e..defb424a29 100644
--- a/lms/templates/accordion.html
+++ b/lms/templates/accordion.html
@@ -3,8 +3,8 @@
<%def name="make_chapter(chapter)">
-
- % for section in chapter['sections']:
+
- %def>
+
+ % endfor
+
+%def>
% for chapter in toc:
${make_chapter(chapter)}
diff --git a/lms/templates/courseware-error.html b/lms/templates/courseware-error.html
index 5711d05e3d..3c26ae8aeb 100644
--- a/lms/templates/courseware-error.html
+++ b/lms/templates/courseware-error.html
@@ -4,7 +4,7 @@
<%include file="course_navigation.html" args="active_page='courseware'" />
-
+
There has been an error on the edX servers
We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible. Please email us at technical@mitx.mit.edu to report any problems or downtime.
diff --git a/lms/templates/gradebook.html b/lms/templates/gradebook.html
index 7c2908dc77..bcc0456711 100644
--- a/lms/templates/gradebook.html
+++ b/lms/templates/gradebook.html
@@ -20,7 +20,7 @@
%block>
<%include file="navigation.html" args="active_page=''" />
-
+
Gradebook
diff --git a/lms/templates/gradebook_profilegraphs.html b/lms/templates/gradebook_profilegraphs.html
index 18995cbb4c..fc36c84fb8 100644
--- a/lms/templates/gradebook_profilegraphs.html
+++ b/lms/templates/gradebook_profilegraphs.html
@@ -14,7 +14,7 @@
%block>
<%include file="navigation.html" args="active_page=''" />
-
+
Gradebook
diff --git a/lms/templates/info.html b/lms/templates/info.html
index 9365b9e76a..25ad4f9184 100644
--- a/lms/templates/info.html
+++ b/lms/templates/info.html
@@ -10,26 +10,33 @@
from courseware.courses import get_course_info_section
%>
+<%block name="js_extra">
+
+
+%block>
+
-
-
-
- % if user.is_authenticated():
-
- ${get_course_info_section(course, 'updates')}
-
-
- ${get_course_info_section(course, 'handouts')}
-
- % else:
-
- ${get_course_info_section(course, 'guest_updates')}
-
-
- ${get_course_info_section(course, 'guest_handouts')}
-
- % endif
-
-
+
+
+ % if user.is_authenticated():
+
+ ${get_course_info_section(course, 'updates')}
+
+
+ ${get_course_info_section(course, 'handouts')}
+
+ % else:
+
+ ${get_course_info_section(course, 'guest_updates')}
+
+
+ ${get_course_info_section(course, 'guest_handouts')}
+
+ % endif
+
diff --git a/lms/templates/mitxhome.html b/lms/templates/mitxhome.html
deleted file mode 100644
index cf2c8fab27..0000000000
--- a/lms/templates/mitxhome.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<%inherit file="main.html" />
-
-<%block name="js_extra">
-
-%block>
-
-<%block name="title">MITx Home %block>
-
-<%include file="navigation.html" args="active_page='info'" />
-
-
-
-
- Welcome to MITx
-
- Courses available:
-
- % for coursename, info in courseinfo.items():
- % if info['active']:
- ${info['title']} (${coursename})
- % endif
- % endfor
-
-
-
-
diff --git a/lms/templates/name_changes.html b/lms/templates/name_changes.html
index 1316084c34..92c9ec1d61 100644
--- a/lms/templates/name_changes.html
+++ b/lms/templates/name_changes.html
@@ -1,6 +1,5 @@
<%inherit file="main.html" />
<%include file="navigation.html" args="active_page=''" />
-