Commit 6b10c076 by Calen Pennington

Merge branch 'master' into anonymous_user

Conflicts:
	djangoapps/student/views.py
parents 261ff838 1e736345
......@@ -43,8 +43,9 @@ def grade_histogram(module_id):
cursor.execute("select courseware_studentmodule.grade,COUNT(courseware_studentmodule.student_id) from courseware_studentmodule where courseware_studentmodule.module_id=%s group by courseware_studentmodule.grade", [module_id])
grades = list(cursor.fetchall())
print grades
grades.sort(key=lambda x:x[0]) # Probably not necessary
if (len(grades) == 1 and grades[0][0] == None):
return []
return grades
def render_x_module(user, request, xml_module, module_object_preload):
......@@ -85,12 +86,21 @@ def render_x_module(user, request, xml_module, module_object_preload):
module_object_preload.append(smod)
# Grab content
content = instance.get_html()
init_js = instance.get_init_js()
destory_js = instance.get_destroy_js()
if user.is_staff:
histogram = grade_histogram(module_id)
render_histogram = len(histogram) > 0
content=content+render_to_string("staff_problem_info.html", {'xml':etree.tostring(xml_module),
'histogram':grade_histogram(module_id)})
'module_id' : module_id,
'render_histogram' : render_histogram})
if render_histogram:
init_js = init_js+render_to_string("staff_problem_histogram.js", {'histogram' : histogram,
'module_id' : module_id})
content = {'content':content,
"destroy_js":instance.get_destroy_js(),
'init_js':instance.get_init_js(),
"destroy_js":destory_js,
'init_js':init_js,
'type':module_type}
return content
......
......@@ -42,7 +42,8 @@ class Module(XModule):
return render_to_string('video.html',{'streams':self.video_list(),
'id':self.item_id,
'position':self.position,
'name':self.name})
'name':self.name,
'annotations':self.annotations})
def get_init_js(self):
'''JavaScript code to be run when problem is shown. Be aware
......@@ -52,19 +53,23 @@ class Module(XModule):
log.debug(u"INIT POSITION {0}".format(self.position))
return render_to_string('video_init.js',{'streams':self.video_list(),
'id':self.item_id,
'position':self.position})
'position':self.position})+self.annotations_init
def get_destroy_js(self):
return "videoDestroy(\"{0}\");".format(self.item_id)
return "videoDestroy(\"{0}\");".format(self.item_id)+self.annotations_destroy
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
self.youtube = etree.XML(xml).get('youtube')
self.name = etree.XML(xml).get('name')
xmltree=etree.fromstring(xml)
self.youtube = xmltree.get('youtube')
self.name = xmltree.get('name')
self.position = 0
if state != None:
state = json.loads(state)
if 'position' in state:
self.position = int(float(state['position']))
#log.debug("POSITION IN STATE")
#log.debug(u"LOAD POSITION {0}".format(self.position))
self.annotations=[(e.get("name"),self.render_function(e)) \
for e in xmltree]
self.annotations_init="".join([e[1]['init_js'] for e in self.annotations if 'init_js' in e[1]])
self.annotations_destroy="".join([e[1]['destroy_js'] for e in self.annotations if 'destroy_js' in e[1]])
......@@ -76,7 +76,7 @@ def render_accordion(request,course,chapter,section):
parameter. Returns (initialization_javascript, content)'''
if not course:
course = "6.002 Spring 2012"
toc=content_parser.toc_from_xml(content_parser.course_file(request.user), chapter, section)
active_chapter=1
for i in range(len(toc)):
......@@ -88,8 +88,7 @@ def render_accordion(request,course,chapter,section):
['format_url_params',content_parser.format_url_params],
['csrf',csrf(request)['csrf_token']]] + \
template_imports.items())
return {'init_js':render_to_string('accordion_init.js',context),
'content':render_to_string('accordion.html',context)}
return render_to_string('accordion.html',context)
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def render_section(request, section):
......@@ -119,8 +118,8 @@ def render_section(request, section):
if 'init_js' not in module:
module['init_js']=''
context={'init':accordion['init_js']+module['init_js'],
'accordion':accordion['content'],
context={'init':module['init_js'],
'accordion':accordion,
'content':module['content'],
'csrf':csrf(request)['csrf_token']}
......@@ -177,8 +176,8 @@ def index(request, course="6.002 Spring 2012", chapter="Using the System", secti
if 'init_js' not in module:
module['init_js']=''
context={'init':accordion['init_js']+module['init_js'],
'accordion':accordion['content'],
context={'init':module['init_js'],
'accordion':accordion,
'content':module['content'],
'csrf':csrf(request)['csrf_token']}
......
......@@ -14,6 +14,7 @@ from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf
from django.core.mail import send_mail
from django.core.validators import validate_email, validate_slug, ValidationError
from django.db import IntegrityError
from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string
......@@ -160,15 +161,6 @@ def create_account(request, post_override=None):
# Confirm username and e-mail are unique. TODO: This should be in a transaction
if len(User.objects.filter(username=post_vars['username']))>0:
js['value']="An account with this username already exists."
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."
return HttpResponse(json.dumps(js))
u=User(username=post_vars['username'],
email=post_vars['email'],
is_active=False)
......@@ -176,7 +168,20 @@ def create_account(request, post_override=None):
r=Registration()
# TODO: Rearrange so that if part of the process fails, the whole process fails.
# Right now, we can have e.g. no registration e-mail sent out and a zombie account
u.save()
try:
u.save()
except IntegrityError:
# 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."
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."
return HttpResponse(json.dumps(js))
raise
r.register(u)
up = UserProfile(user=u)
......
......@@ -24,7 +24,6 @@ with open(ENV_ROOT / "env.json") as env_file:
ENV_TOKENS = json.load(env_file)
SITE_NAME = ENV_TOKENS['SITE_NAME']
CSRF_COOKIE_DOMAIN = ENV_TOKENS['CSRF_COOKIE_DOMAIN']
BOOK_URL = ENV_TOKENS['BOOK_URL']
MEDIA_URL = ENV_TOKENS['MEDIA_URL']
......@@ -47,4 +46,4 @@ SECRET_KEY = AUTH_TOKENS['SECRET_KEY']
AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"]
AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"]
DATABASES = AUTH_TOKENS['DATABASES']
\ No newline at end of file
DATABASES = AUTH_TOKENS['DATABASES']
......@@ -114,7 +114,6 @@ TEMPLATE_DEBUG = False
# Site info
SITE_ID = 1
SITE_NAME = "localhost:8000"
CSRF_COOKIE_DOMAIN = '127.0.0.1'
HTTPS = 'on'
ROOT_URLCONF = 'mitx.urls'
IGNORABLE_404_ENDS = ('favicon.ico')
......@@ -135,13 +134,13 @@ STATIC_ROOT = ENV_ROOT / "staticfiles" # We don't run collectstatic -- this is t
# FIXME: We should iterate through the courses we have, adding the static
# contents for each of them. (Right now we just use symlinks.)
STATICFILES_DIRS = (
STATICFILES_DIRS = [
PROJECT_ROOT / "static",
ASKBOT_ROOT / "askbot" / "skins",
# This is how you would use the textbook images locally
# ("book", ENV_ROOT / "book_images")
)
]
# Locale/Internationalization
TIME_ZONE = 'America/New_York' # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
......
......@@ -73,7 +73,8 @@ DEBUG_TOOLBAR_PANELS = (
############################ FILE UPLOADS (ASKBOT) #############################
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
MEDIA_ROOT = ENV_ROOT / "uploads"
MEDIA_URL = "/discussion/upfiles/"
MEDIA_URL = "/static/uploads/"
STATICFILES_DIRS.append(("uploads", MEDIA_ROOT))
FILE_UPLOAD_TEMP_DIR = ENV_ROOT / "uploads"
FILE_UPLOAD_HANDLERS = (
'django.core.files.uploadhandler.MemoryFileUploadHandler',
......
"""
This config file runs the simplest dev environment using sqlite, and db-based
sessions. Assumes structure:
/envroot/
/db # This is where it'll write the database file
/mitx # The location of this repo
/log # Where we're going to write log files
"""
from common import *
STATIC_GRAB = True
LOGGING = logsettings.get_logger_config(ENV_ROOT / "log",
logging_env="dev",
tracking_filename="tracking.log",
debug=False)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ENV_ROOT / "db" / "mitx.db",
}
}
CACHES = {
# 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': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'mitx_loc_mem_cache'
},
# The general cache is what you get if you use our util.cache. It's used for
# things like caching the course.xml file for different A/B test groups.
# We set it to be a DummyCache to force reloading of course.xml in dev.
# In staging environments, we would grab VERSION from data uploaded by the
# push process.
'general': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'KEY_PREFIX': 'general',
'VERSION': 4,
}
}
# Dummy secret key for dev
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
############################ FILE UPLOADS (ASKBOT) #############################
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
MEDIA_ROOT = ENV_ROOT / "uploads"
MEDIA_URL = "/discussion/upfiles/"
FILE_UPLOAD_TEMP_DIR = ENV_ROOT / "uploads"
FILE_UPLOAD_HANDLERS = (
'django.core.files.uploadhandler.MemoryFileUploadHandler',
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
)
#! /usr/bin/env python
import sys
import json
import random
import copy
from collections import defaultdict
from argparse import ArgumentParser, FileType
from datetime import datetime
def generate_user(user_number):
return {
......@@ -51,7 +54,6 @@ def generate_user(user_number):
}
def parse_args(args=sys.argv[1:]):
parser = ArgumentParser()
parser.add_argument('-d', '--data', type=FileType('r'), default=sys.stdin)
......@@ -59,6 +61,7 @@ def parse_args(args=sys.argv[1:]):
parser.add_argument('count', type=int)
return parser.parse_args(args)
def main(args=sys.argv[1:]):
args = parse_args(args)
......@@ -79,6 +82,8 @@ def main(args=sys.argv[1:]):
sample = random.choice(answers)
data = copy.deepcopy(sample)
data["fields"]["student"] = student_id + 1
data["fields"]["created"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
data["fields"]["modified"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
data["pk"] = out_pk
out_pk += 1
out_data.append(data)
......
......@@ -28,7 +28,6 @@ sys.path.append(BASE_DIR + "/mitx/lib")
COURSEWARE_ENABLED = True
ASKBOT_ENABLED = True
CSRF_COOKIE_DOMAIN = '127.0.0.1'
# Defaults to be overridden
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
......@@ -116,6 +115,7 @@ MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware',
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
'masquerade.middleware.MasqueradeMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware',
'mitxmako.middleware.MakoMiddleware',
......@@ -146,6 +146,8 @@ INSTALLED_APPS = (
'circuit',
'perfstats',
'util',
'masquerade',
'django_jasmine',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
......@@ -346,6 +348,7 @@ PROJECT_ROOT = os.path.dirname(__file__)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.core.context_processors.static',
'askbot.context.application_settings',
#'django.core.context_processors.i18n',
'askbot.user_messages.context_processors.user_messages',#must be before auth
......@@ -682,3 +685,5 @@ if MAKO_MODULE_DIR == None:
djcelery.setup_loader()
# Jasmine Settings
JASMINE_TEST_DIRECTORY = PROJECT_DIR+'/templates/coffee'
/* line 1, sass/marketing-ie.scss */
body {
margin: 0;
padding: 0; }
/* line 6, sass/marketing-ie.scss */
.wrapper, .subpage, section.copyright, section.tos, section.privacy-policy, section.honor-code, header.announcement div, section.index-content, footer {
margin: 0;
overflow: hidden; }
/* line 12, sass/marketing-ie.scss */
div#enroll form {
display: none; }
// Generated by CoffeeScript 1.3.2-pre
(function() {
window.Calculator = (function() {
function Calculator() {}
Calculator.bind = function() {
var calculator;
calculator = new Calculator;
$('.calc').click(calculator.toggle);
$('form#calculator').submit(calculator.calculate).submit(function(e) {
return e.preventDefault();
});
return $('div.help-wrapper a').hover(calculator.helpToggle).click(function(e) {
return e.preventDefault();
});
};
Calculator.prototype.toggle = function() {
$('li.calc-main').toggleClass('open');
$('#calculator_wrapper #calculator_input').focus();
return $('.calc').toggleClass('closed');
};
Calculator.prototype.helpToggle = function() {
return $('.help').toggleClass('shown');
};
Calculator.prototype.calculate = function() {
return $.getJSON('/calculate', {
equation: $('#calculator_input').val()
}, function(data) {
return $('#calculator_output').val(data.result);
});
};
return Calculator;
})();
window.Courseware = (function() {
function Courseware() {}
Courseware.bind = function() {
return this.Navigation.bind();
};
Courseware.Navigation = (function() {
function Navigation() {}
Navigation.bind = function() {
var active, navigation;
if ($('#accordion').length) {
navigation = new Navigation;
active = $('#accordion ul:has(li.active)').index('#accordion ul');
$('#accordion').bind('accordionchange', navigation.log).accordion({
active: active >= 0 ? active : 1,
header: 'h3',
autoHeight: false
});
return $('#open_close_accordion a').click(navigation.toggle);
}
};
Navigation.prototype.log = function(event, ui) {
return log_event('accordion', {
newheader: ui.newHeader.text(),
oldheader: ui.oldHeader.text()
});
};
Navigation.prototype.toggle = function() {
return $('.course-wrapper').toggleClass('closed');
};
return Navigation;
})();
return Courseware;
}).call(this);
window.FeedbackForm = (function() {
function FeedbackForm() {}
FeedbackForm.bind = function() {
return $('#feedback_button').click(function() {
var data;
data = {
subject: $('#feedback_subject').val(),
message: $('#feedback_message').val(),
url: window.location.href
};
return $.post('/send_feedback', data, function() {
return $('#feedback_div').html('Feedback submitted. Thank you');
}, 'json');
});
};
return FeedbackForm;
})();
$(function() {
$.ajaxSetup({
headers: {
'X-CSRFToken': $.cookie('csrftoken')
}
});
Calculator.bind();
Courseware.bind();
FeedbackForm.bind();
return $("a[rel*=leanModal]").leanModal();
});
}).call(this);
......@@ -7,21 +7,12 @@
<ul>
% for section in chapter['sections']:
<li
% if 'active' in section and section['active']:
class="active"
% endif
>
<li${' class="active"' if 'active' in section and section['active'] else ''}>
<a href="${reverse('courseware_section', args=format_url_params([course_name, chapter['name'], section['name']]))}">
<p>${section['name']}</p>
<p class="subtitle">
${section['format']}
% if 'due' in section and section['due']!="":
due ${section['due']}
% endif
${section['format']} ${"due " + section['due'] if 'due' in section and section['due'] != '' else ''}
</p>
</a>
% endfor
......
$("#accordion").accordion({
active: ${ active_chapter },
header: 'h3',
autoHeight: false,
});
$("#open_close_accordion a").click(function(){
if ($(".course-wrapper").hasClass("closed")){
$(".course-wrapper").removeClass("closed");
} else {
$(".course-wrapper").addClass("closed");
}
});
$('.ui-accordion').bind('accordionchange', function(event, ui) {
var event_data = {'newheader':ui.newHeader.text(),
'oldheader':ui.oldHeader.text()};
log_event('accordion', event_data);
});
CoffeeScript
============
This folder contains the CoffeeScript file that will be compiled to the static
directory. By default, we're compile and merge all the files ending `.coffee`
into `static/js/application.js`.
Install the Compiler
--------------------
CoffeeScript compiler are written in JavaScript. You'll need to install Node and
npm (Node Package Manager) to be able to install the CoffeeScript compiler.
### Mac OS X
Install Node via Homebrew, then use npm:
brew install node
curl http://npmjs.org/install.sh | sh
npm install -g git://github.com/jashkenas/coffee-script.git
(Note that we're using the edge version of CoffeeScript for now, as there was
some issue with directory watching in 1.3.1.)
Try to run `coffee` and make sure you get a coffee prompt.
### Debian/Ubuntu
Conveniently, you can install Node via `apt-get`, then use npm:
sudo apt-get install nodejs npm &&
sudo npm install -g git://github.com/jashkenas/coffee-script.git
Compiling
---------
Run this command in the `mitx` directory to easily make the compiler watch for
changes in your file, and join the result into `application.js`:
coffee -j static/js/application.js -cw templates/coffee/src
Please note that the compiler will not be able to detect the file that get added
after you've ran the command, so you'll need to restart the compiler if there's
a new CoffeeScript file.
Testing
=======
We're also using Jasmine to unit-testing the JavaScript files. All the specs are
written in CoffeeScript for the consistency. Because of the limitation of
`django-jasmine` plugin, we'll need to also running another compiler to compile
the test file.
Using this command to compile the test files:
coffee -cw templates/coffee/spec/*.coffee
Then start the server in debug mode, navigate to http://127.0.0.1:8000/_jasmine
to see the test result.
{
"js_files": [
"/static/js/jquery-1.6.2.min.js",
"/static/js/jquery-ui-1.8.16.custom.min.js",
"/static/js/jquery.leanModal.js"
],
"static_files": [
"js/application.js"
]
}
<div class="course-wrapper">
<header id="open_close_accordion">
<a href="#">close</a>
</header>
<div id="accordion"></div>
</div>
<ul>
<li class="calc-main">
<a href="#" class="calc">Calculator</a>
<div id="calculator_wrapper">
<form id="calculator">
<div class="input-wrapper">
<input type="text" id="calculator_input" />
<div class="help-wrapper">
<a href="#">Hints</a>
<dl class="help"></dl>
</div>
</div>
<input id="calculator_button" type="submit" value="="/>
<input type="text" id="calculator_output" readonly />
</form>
</div>
</li>
</ul>
<div id="feedback_div">
<form>
<label>Subject:</label> <input type="text" id="feedback_subject">
<label>Feedback: </label><textarea id="feedback_message"></textarea>
<input id="feedback_button" type="button" value="Submit">
</form>
</div>
describe 'Calculator', ->
beforeEach ->
loadFixtures 'calculator.html'
@calculator = new Calculator
describe 'bind', ->
beforeEach ->
Calculator.bind()
it 'bind the calculator button', ->
expect($('.calc')).toHandleWith 'click', @calculator.toggle
it 'bind the help button', ->
# These events are bind by $.hover()
expect($('div.help-wrapper a')).toHandleWith 'mouseenter', @calculator.helpToggle
expect($('div.help-wrapper a')).toHandleWith 'mouseleave', @calculator.helpToggle
it 'prevent default behavior on help button', ->
$('div.help-wrapper a').click (e) ->
expect(e.isDefaultPrevented()).toBeTruthy()
$('div.help-wrapper a').click()
it 'bind the calculator submit', ->
expect($('form#calculator')).toHandleWith 'submit', @calculator.calculate
it 'prevent default behavior on form submit', ->
$('form#calculator').submit (e) ->
expect(e.isDefaultPrevented()).toBeTruthy()
e.preventDefault()
$('form#calculator').submit()
describe 'toggle', ->
it 'toggle the calculator and focus the input', ->
spyOn $.fn, 'focus'
@calculator.toggle()
expect($('li.calc-main')).toHaveClass('open')
expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled()
it 'toggle the close button on the calculator button', ->
@calculator.toggle()
expect($('.calc')).toHaveClass('closed')
@calculator.toggle()
expect($('.calc')).not.toHaveClass('closed')
describe 'helpToggle', ->
it 'toggle the help overlay', ->
@calculator.helpToggle()
expect($('.help')).toHaveClass('shown')
@calculator.helpToggle()
expect($('.help')).not.toHaveClass('shown')
describe 'calculate', ->
beforeEach ->
$('#calculator_input').val '1+2'
spyOn($, 'getJSON').andCallFake (url, data, callback) ->
callback({ result: 3 })
@calculator.calculate()
it 'send data to /calculate', ->
expect($.getJSON).toHaveBeenCalledWith '/calculate',
equation: '1+2'
, jasmine.any(Function)
it 'update the calculator output', ->
expect($('#calculator_output').val()).toEqual('3')
// Generated by CoffeeScript 1.3.2-pre
(function() {
describe('Calculator', function() {
beforeEach(function() {
loadFixtures('calculator.html');
return this.calculator = new Calculator;
});
describe('bind', function() {
beforeEach(function() {
return Calculator.bind();
});
it('bind the calculator button', function() {
return expect($('.calc')).toHandleWith('click', this.calculator.toggle);
});
it('bind the help button', function() {
expect($('div.help-wrapper a')).toHandleWith('mouseenter', this.calculator.helpToggle);
return expect($('div.help-wrapper a')).toHandleWith('mouseleave', this.calculator.helpToggle);
});
it('prevent default behavior on help button', function() {
$('div.help-wrapper a').click(function(e) {
return expect(e.isDefaultPrevented()).toBeTruthy();
});
return $('div.help-wrapper a').click();
});
it('bind the calculator submit', function() {
return expect($('form#calculator')).toHandleWith('submit', this.calculator.calculate);
});
return it('prevent default behavior on form submit', function() {
$('form#calculator').submit(function(e) {
expect(e.isDefaultPrevented()).toBeTruthy();
return e.preventDefault();
});
return $('form#calculator').submit();
});
});
describe('toggle', function() {
it('toggle the calculator and focus the input', function() {
spyOn($.fn, 'focus');
this.calculator.toggle();
expect($('li.calc-main')).toHaveClass('open');
return expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled();
});
return it('toggle the close button on the calculator button', function() {
this.calculator.toggle();
expect($('.calc')).toHaveClass('closed');
this.calculator.toggle();
return expect($('.calc')).not.toHaveClass('closed');
});
});
describe('helpToggle', function() {
return it('toggle the help overlay', function() {
this.calculator.helpToggle();
expect($('.help')).toHaveClass('shown');
this.calculator.helpToggle();
return expect($('.help')).not.toHaveClass('shown');
});
});
return describe('calculate', function() {
beforeEach(function() {
$('#calculator_input').val('1+2');
spyOn($, 'getJSON').andCallFake(function(url, data, callback) {
return callback({
result: 3
});
});
return this.calculator.calculate();
});
it('send data to /calculate', function() {
return expect($.getJSON).toHaveBeenCalledWith('/calculate', {
equation: '1+2'
}, jasmine.any(Function));
});
return it('update the calculator output', function() {
return expect($('#calculator_output').val()).toEqual('3');
});
});
});
}).call(this);
describe 'Courseware', ->
describe 'bind', ->
it 'bind the navigation', ->
spyOn Courseware.Navigation, 'bind'
Courseware.bind()
expect(Courseware.Navigation.bind).toHaveBeenCalled()
describe 'Navigation', ->
beforeEach ->
loadFixtures 'accordion.html'
@navigation = new Courseware.Navigation
describe 'bind', ->
describe 'when the #accordion exists', ->
describe 'when there is an active section', ->
it 'activate the accordion with correct active section', ->
spyOn $.fn, 'accordion'
$('#accordion').append('<ul><li></li></ul><ul><li class="active"></li></ul>')
Courseware.Navigation.bind()
expect($('#accordion').accordion).toHaveBeenCalledWith
active: 1
header: 'h3'
autoHeight: false
describe 'when there is no active section', ->
it 'activate the accordian with section 1 as active', ->
spyOn $.fn, 'accordion'
$('#accordion').append('<ul><li></li></ul><ul><li></li></ul>')
Courseware.Navigation.bind()
expect($('#accordion').accordion).toHaveBeenCalledWith
active: 1
header: 'h3'
autoHeight: false
it 'binds the accordionchange event', ->
Courseware.Navigation.bind()
expect($('#accordion')).toHandleWith 'accordionchange', @navigation.log
it 'bind the navigation toggle', ->
Courseware.Navigation.bind()
expect($('#open_close_accordion a')).toHandleWith 'click', @navigation.toggle
describe 'when the #accordion does not exists', ->
beforeEach ->
$('#accordion').remove()
it 'does not activate the accordion', ->
spyOn $.fn, 'accordion'
Courseware.Navigation.bind()
expect($('#accordion').accordion).wasNotCalled()
describe 'toggle', ->
it 'toggle closed class on the wrapper', ->
$('.course-wrapper').removeClass('closed')
@navigation.toggle()
expect($('.course-wrapper')).toHaveClass('closed')
@navigation.toggle()
expect($('.course-wrapper')).not.toHaveClass('closed')
describe 'log', ->
beforeEach ->
window.log_event = ->
spyOn window, 'log_event'
it 'submit event log', ->
@navigation.log {}, {
newHeader:
text: -> "new"
oldHeader:
text: -> "old"
}
expect(window.log_event).toHaveBeenCalledWith 'accordion',
newheader: 'new'
oldheader: 'old'
// Generated by CoffeeScript 1.3.2-pre
(function() {
describe('Courseware', function() {
describe('bind', function() {
return it('bind the navigation', function() {
spyOn(Courseware.Navigation, 'bind');
Courseware.bind();
return expect(Courseware.Navigation.bind).toHaveBeenCalled();
});
});
return describe('Navigation', function() {
beforeEach(function() {
loadFixtures('accordion.html');
return this.navigation = new Courseware.Navigation;
});
describe('bind', function() {
describe('when the #accordion exists', function() {
describe('when there is an active section', function() {
return it('activate the accordion with correct active section', function() {
spyOn($.fn, 'accordion');
$('#accordion').append('<ul><li></li></ul><ul><li class="active"></li></ul>');
Courseware.Navigation.bind();
return expect($('#accordion').accordion).toHaveBeenCalledWith({
active: 1,
header: 'h3',
autoHeight: false
});
});
});
describe('when there is no active section', function() {
return it('activate the accordian with section 1 as active', function() {
spyOn($.fn, 'accordion');
$('#accordion').append('<ul><li></li></ul><ul><li></li></ul>');
Courseware.Navigation.bind();
return expect($('#accordion').accordion).toHaveBeenCalledWith({
active: 1,
header: 'h3',
autoHeight: false
});
});
});
it('binds the accordionchange event', function() {
Courseware.Navigation.bind();
return expect($('#accordion')).toHandleWith('accordionchange', this.navigation.log);
});
return it('bind the navigation toggle', function() {
Courseware.Navigation.bind();
return expect($('#open_close_accordion a')).toHandleWith('click', this.navigation.toggle);
});
});
return describe('when the #accordion does not exists', function() {
beforeEach(function() {
return $('#accordion').remove();
});
return it('does not activate the accordion', function() {
spyOn($.fn, 'accordion');
Courseware.Navigation.bind();
return expect($('#accordion').accordion).wasNotCalled();
});
});
});
describe('toggle', function() {
return it('toggle closed class on the wrapper', function() {
$('.course-wrapper').removeClass('closed');
this.navigation.toggle();
expect($('.course-wrapper')).toHaveClass('closed');
this.navigation.toggle();
return expect($('.course-wrapper')).not.toHaveClass('closed');
});
});
return describe('log', function() {
beforeEach(function() {
window.log_event = function() {};
return spyOn(window, 'log_event');
});
return it('submit event log', function() {
this.navigation.log({}, {
newHeader: {
text: function() {
return "new";
}
},
oldHeader: {
text: function() {
return "old";
}
}
});
return expect(window.log_event).toHaveBeenCalledWith('accordion', {
newheader: 'new',
oldheader: 'old'
});
});
});
});
});
}).call(this);
describe 'FeedbackForm', ->
beforeEach ->
loadFixtures 'feedback_form.html'
describe 'bind', ->
beforeEach ->
FeedbackForm.bind()
spyOn($, 'post').andCallFake (url, data, callback, format) ->
callback()
it 'binds to the #feedback_button', ->
expect($('#feedback_button')).toHandle 'click'
it 'post data to /send_feedback on click', ->
$('#feedback_subject').val 'Awesome!'
$('#feedback_message').val 'This site is really good.'
$('#feedback_button').click()
expect($.post).toHaveBeenCalledWith '/send_feedback', {
subject: 'Awesome!'
message: 'This site is really good.'
url: window.location.href
}, jasmine.any(Function), 'json'
it 'replace the form with a thank you message', ->
$('#feedback_button').click()
expect($('#feedback_div').html()).toEqual 'Feedback submitted. Thank you'
// Generated by CoffeeScript 1.3.2-pre
(function() {
describe('FeedbackForm', function() {
beforeEach(function() {
return loadFixtures('feedback_form.html');
});
return describe('bind', function() {
beforeEach(function() {
FeedbackForm.bind();
return spyOn($, 'post').andCallFake(function(url, data, callback, format) {
return callback();
});
});
it('binds to the #feedback_button', function() {
return expect($('#feedback_button')).toHandle('click');
});
it('post data to /send_feedback on click', function() {
$('#feedback_subject').val('Awesome!');
$('#feedback_message').val('This site is really good.');
$('#feedback_button').click();
return expect($.post).toHaveBeenCalledWith('/send_feedback', {
subject: 'Awesome!',
message: 'This site is really good.',
url: window.location.href
}, jasmine.any(Function), 'json');
});
return it('replace the form with a thank you message', function() {
$('#feedback_button').click();
return expect($('#feedback_div').html()).toEqual('Feedback submitted. Thank you');
});
});
});
}).call(this);
jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/"
// Generated by CoffeeScript 1.3.2-pre
(function() {
jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/";
}).call(this);
class window.Calculator
@bind: ->
calculator = new Calculator
$('.calc').click calculator.toggle
$('form#calculator').submit(calculator.calculate).submit (e) ->
e.preventDefault()
$('div.help-wrapper a').hover(calculator.helpToggle).click (e) ->
e.preventDefault()
toggle: ->
$('li.calc-main').toggleClass 'open'
$('#calculator_wrapper #calculator_input').focus()
$('.calc').toggleClass 'closed'
helpToggle: ->
$('.help').toggleClass 'shown'
calculate: ->
$.getJSON '/calculate', { equation: $('#calculator_input').val() }, (data) ->
$('#calculator_output').val(data.result)
class window.Courseware
@bind: ->
@Navigation.bind()
class @Navigation
@bind: ->
if $('#accordion').length
navigation = new Navigation
active = $('#accordion ul:has(li.active)').index('#accordion ul')
$('#accordion').bind('accordionchange', navigation.log).accordion
active: if active >= 0 then active else 1
header: 'h3'
autoHeight: false
$('#open_close_accordion a').click navigation.toggle
log: (event, ui) ->
log_event 'accordion',
newheader: ui.newHeader.text()
oldheader: ui.oldHeader.text()
toggle: ->
$('.course-wrapper').toggleClass('closed')
class window.FeedbackForm
@bind: ->
$('#feedback_button').click ->
data =
subject: $('#feedback_subject').val()
message: $('#feedback_message').val()
url: window.location.href
$.post '/send_feedback', data, ->
$('#feedback_div').html 'Feedback submitted. Thank you'
,'json'
$ ->
$.ajaxSetup
headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
Calculator.bind()
Courseware.bind()
FeedbackForm.bind()
$("a[rel*=leanModal]").leanModal()
......@@ -2,7 +2,12 @@
<%block name="bodyclass">courseware</%block>
<%block name="title"><title>Courseware – MITx 6.002x</title></%block>
<%block name="headextra">
<script type="text/javascript" src="/static/js/flot/jquery.flot.js"></script>
</%block>
<%block name="js_extra">
##Is there a reason this isn't in header_extra? Is it important that the javascript is at the bottom of the generated document?
<!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<script type="text/javascript">
$(function() {
......
......@@ -6,9 +6,7 @@
<p class="ie-warning"> Enrollment requires a modern web browser with JavaScript enabled. You don't have this. You can&rsquo;t enroll without upgrading, since you couldn&rsquo;t take the course without upgrading. Feel free to download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Mozilla Firefox</a> or <a href="http://support.google.com/chrome/bin/answer.py?hl=en&answer=95346">Google Chrome</a>, for free, to enroll and take this course.</p>
<![endif]-->
<p class="disclaimer">
Please note that 6.002x has already started.
Several assignment due dates for 6.002x have already passed. It is now impossible for newly enrolled students to get 100% of the points in the course, although new students can still earn points for assignments whose due dates have not passed, and students have access to all of the course material that has been released for the course.
</p>
Please note that 6.002x has now passed its half-way point. The midterm exam and several assignment due dates for 6.002x have already passed. It is now impossible for newly enrolled students to earn a passing grade and a completion certificate for the course. However, new students have access to all of the course material that has been released for the course, so you are welcome to enroll and browse the course. </p>
<form name="enroll" id="enroll_form" method="get">
<fieldset><% if 'error' in locals(): e = error %>
......
MITx's prototype offering, 6.002x, is now open. To log in, visit
MITx's prototype offering, 6.002x, is open. To log in, visit
% if is_secure:
https://6002x.mitx.mit.edu
......@@ -16,7 +16,7 @@ place to reset it.
Once you log in, we recommend that you start the course by reviewing
the "System Usage Sequence" in the Overview section, and the "6.002x
At-a-Glance (Calendar)" handout under the Course Info tab. After you
familiarize yourself with the various features of the MITx platform,
familiarize yourself with the features of the MITx platform,
you can jump right into the coursework by working on "Administrivia
and Circuit Elements", the first Lecture Sequence in Week 1.
......
......@@ -11,7 +11,7 @@
<h2>6.002x</h2>
<a class="enroll" rel="leanModal" href="/info">View 6.002x Circuits <span>&amp;</span> Electronics as a guest</a>
</section>
<p>6.002x (Circuits and Electronics) is an experimental on-line adaptation of MIT&rsquo;s first undergraduate analog design course: 6.002. This course will run, free of charge, for students worldwide from March 5, 2012 through June 8, 2012.</p>
<p>6.002x (Circuits and Electronics) is an experimental on-line adaptation of MIT&rsquo;s first undergraduate analog design course: 6.002. This course is running, free of charge, for students worldwide from March 5, 2012 through June 8, 2012.</p>
</section>
</%block>
......
......@@ -4,11 +4,12 @@
<%block name="title"><title>MITx 6.002x</title></%block>
<link rel="stylesheet" href="${ settings.LIB_URL }jquery.treeview.css" type="text/css" media="all" />
<link rel="stylesheet" href="/static/css/application.css?v2" type="text/css" media="all" />
<link rel="stylesheet" href="/static/css/application.css?v3" type="text/css" media="all" />
<script type="text/javascript" src="${ settings.LIB_URL }jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="${ settings.LIB_URL }jquery-ui-1.8.16.custom.min.js"></script>
<script type="text/javascript" src="${ settings.LIB_URL }swfobject/swfobject.js"></script>
<script type="text/javascript" src="/static/js/application.js"></script>
<!--[if lt IE 9]>
<script src="/static/js/html5shiv.js"></script>
......@@ -92,20 +93,18 @@
</nav>
</footer>
<div id="feedback_div" class="leanModal_box">
<h1>Feedback for MITx</h1>
<p>Found a bug? Got an idea for improving our system? Let us know.</p>
<form>
<ol>
<li><label>Subject:</label> <input type="text" id="feedback_subject"></li>
<li><label>Feedback: </label><textarea id="feedback_message"></textarea></li>
<li><input id="feedback_button" type="button" value="Submit"></li>
</ol>
</form>
</div>
<div id="feedback_div" class="leanModal_box">
<h1>Feedback for MITx</h1>
<p>Found a bug? Got an idea for improving our system? Let us know.</p>
<form>
<ol>
<li><label>Subject:</label> <input type="text" id="feedback_subject"></li>
<li><label>Feedback: </label><textarea id="feedback_message"></textarea></li>
<li><input id="feedback_button" type="button" value="Submit"></li>
</ol>
</form>
</div>
<script type="text/javascript" src="${ settings.LIB_URL }jquery.treeview.js"></script>
<script type="text/javascript" src="/static/js/jquery.leanModal.min.js"></script>
......@@ -114,57 +113,7 @@
<script type="text/javascript" src="/static/js/video_player.js"></script>
<script type="text/javascript" src="/static/js/schematic.js"></script>
<script type="text/javascript" src="/static/js/cktsim.js"></script>
<script>
// Feedback form
$(function() {
$("#feedback_button").click(function(){
postJSON("/send_feedback", {"subject":$("#feedback_subject").attr("value"),
"url":document.URL,
"message":$("#feedback_message").attr("value")},
function(data){
$("#feedback_subject").attr("value","");
$("#feedback_message").attr("value","");
$("#feedback_div").html("Feedback submitted. Thank you");
});
});
});
// Calculator
$(function() {
$("#calculator_wrapper").hide();
$(".calc").click(function(){
$("#calculator_wrapper").slideToggle("fast");
$("#calculator_wrapper #calculator_input").focus();
$(this).toggleClass("closed");
return false;
});
$("div.help-wrapper a").hover(function(){
$(".help").toggleClass("shown");
});
$("div.help-wrapper a").click(function(){
return false;
});
$("form#calculator").submit(function(e){
e.preventDefault();
$.getJSON("/calculate", {"equation":$("#calculator_input").attr("value")},
function(data){
$("#calculator_output").attr("value",data.result);
});
});
});
$(function(){
$("a[rel*=leanModal]").leanModal();
});
</script>
<%block name="js_extra"/>
<%block name="js_extra"/>
</body>
</html>
......@@ -8,7 +8,7 @@
<section class="intro">
<section class="intro-text">
<p><em>MITx</em> will offer a portfolio of MIT courses for free to a virtual community of learners around the world. It will also enhance the educational experience of its on-campus students, offering them online tools that supplement and enrich their classroom and laboratory experiences.</p>
<p>The first <em>MITx</em> course, 6.002x (Circuits and Electronics), will be launched in an experimental prototype form. Watch this space for further upcoming courses, which will become available in Fall 2012.</p>
<p>The first <em>MITx</em> course, 6.002x (Circuits and Electronics), was launched in an experimental prototype form. Watch this space for further upcoming courses, which will become available in Fall 2012.</p>
</section>
<section class="intro-video">
......@@ -33,17 +33,29 @@
</section>
<section class="course">
<hgroup>
<h1>Spring 2012 Course offering</h1>
<h2>Circuits and Electronics</h2>
<h3>6.002x</h3>
</hgroup>
<div class="announcement">
<h1> Announcement </h1>
<img src="/static/images/marketing/edx-logo.png" alt="" />
<p>
On May 2, it was announced that Harvard University will join MIT as a partner in edX. MITx, which offers online versions of MIT courses, will be a core offering of edX, as will Harvardx, a set of course offerings from Harvard.
</p>
<p class="announcement-button">
<a href="http://edxonline.org">Read more details here <span class="arrow">&#8227;</span></a>
</p>
</div>
<hgroup>
<h1>Spring 2012 Course offering</h1>
<h2>Circuits and Electronics</h2>
<h3>6.002x</h3>
</hgroup>
<p>
<a href="http://6002x.mitx.mit.edu/" class="more-info">More information <span>&amp;</span> Enroll <span class="arrow">&#8227;</span></a>
</p>
<p>Taught by Anant Agarwal, with Gerald Sussman and Piotr Mitros, 6.002x (Circuits and Electronics) is an on-line adaption of 6.002, MIT&rsquo;s first undergraduate analog design course. This prototype course will run, free of charge, for students worldwide from March 5, 2012 through June 8, 2012. Students will be given the opportunity to demonstrate their mastery of the material and earn a certificate from <em>MITx</em>.</p>
<p>Taught by Anant Agarwal, with Gerald Sussman and Piotr Mitros, 6.002x (Circuits and Electronics) is an on-line adaption of 6.002, MIT&rsquo;s first undergraduate analog design course. This prototype course is running, free of charge, for students worldwide from March 5, 2012 through June 8, 2012. Students are given the opportunity to demonstrate their mastery of the material and earn a certificate from <em>MITx</em>.</p>
</section>
</section>
......
// JM MOSFET AMPLIFIER
div#graph-container {
section.tool-wrapper {
background: #073642;
border-top: 1px solid darken(#002b36, 10%);
border-bottom: 1px solid darken(#002b36, 10%);
@include box-shadow(inset 0 0 0 4px darken(#094959, 2%));
margin: lh() (-(lh())) 0;
color: #839496;
@extend .clearfix;
border-top: 1px solid #ddd;
padding-top: lh(1.0);
canvas#graph {
width: flex-grid(4.5, 9);
float: left;
margin-right: flex-gutter(9);
}
div.graph-controls {
width: flex-grid(4.5, 9);
float: left;
display: table;
div#graph-container {
background: none;
@include box-sizing(border-box);
display: table-cell;
padding: lh();
vertical-align: top;
width: flex-grid(4.5, 9) + flex-gutter(9);
.ui-widget-content {
background: none;
border: none;
@include border-radius(0);
}
select#musicTypeSelect {
display: block;
margin-bottom: lh();
canvas {
width: 100%;
}
div#graph-output {
display: block;
margin-bottom: lh();
ul.ui-tabs-nav {
background: darken(#073642, 2%);
margin: (-(lh())) (-(lh())) 0;
padding: 0;
position: relative;
width: 110%;
@include border-radius(0);
border-bottom: 1px solid darken(#073642, 8%);
li {
margin-bottom: 0;
background: none;
color: #fff;
border: none;
@include border-radius(0);
&.ui-tabs-selected {
border-right: 1px solid darken(#073642, 8%);
border-left: 1px solid darken(#073642, 8%);
background-color: #073642;
&:first-child {
border-left: none;
}
a {
color: #eee8d5;
}
}
a {
border: none;
font: bold 12px $body-font-family;
text-transform: uppercase;
letter-spacing: 1px;
color: #839496;
&:hover {
color: #eee8d5;
}
}
}
}
}
div#controlls-container {
@extend .clearfix;
background: darken(#073642, 2%);
border-right: 1px solid darken(#002b36, 6%);
@include box-shadow(1px 0 0 lighten(#002b36, 6%), inset 0 0 0 4px darken(#094959, 6%));
@include box-sizing(border-box);
display: table-cell;
padding: lh();
vertical-align: top;
width: flex-grid(4.5, 9);
div#graph-listen {
display: block;
div.graph-controls {
padding: 0 0 lh();
margin-bottom: lh();
border-bottom: 1px solid darken(#073642, 5%);
@include box-shadow(0 1px 0 lighten(#073642, 2%));
@extend .clearfix;
div.music-wrapper {
margin-right: flex-gutter(4.5);
width: flex-grid(1.5, 4.5);
float: left;
}
div.inputs-wrapper {
padding-top: lh(.5);
width: flex-grid(3, 4.5);
float: left;
}
select#musicTypeSelect {
display: block;
margin-bottom: lh(.5);
font: 16px $body-font-family;
width: 100%;
}
div#graph-output, div#graph-listen {
display: block;
margin-bottom: lh(.5);
text-align: right;
p {
@include inline-block();
margin: 0;
}
ul {
@include inline-block();
margin-bottom: 0;
li {
@include inline-block();
margin-bottom: 0;
input {
margin-right: 5px;
}
}
}
}
input#playButton {
display: block;
@include button(simple, #dc322f);
font: bold 14px $body-font-family;
color: #47221a;
text-shadow: 0 1px 0 lighten(#dc322f, 5%);
@include box-shadow(inset 0 1px 0 lighten(#dc322f, 10%));
&:active {
@include box-shadow(none);
}
&[value="Stop"] {
@include button(simple, darken(#268bd2, 30%));
font: bold 14px $body-font-family;
&:active {
@include box-shadow(none);
}
}
}
}
p {
margin-bottom: lh(.5);
label {
@include border-radius(2px);
font-weight: bold;
padding: 3px;
color: #fff;
-webkit-font-smoothing: antialiased;
}
div#label {
display: inline-block;
//MOSFET AMPLIFIER
label[for="vinCheckbox"], label[for="vinRadioButton"]{
color: desaturate(#00bfff, 50%);
}
input#playButton {
display: block;
label[for="voutCheckbox"], label[for="voutRadioButton"]{
color: darken(#ffcf48, 20%);
}
}
}
div#schematic-container {
@extend .clearfix;
canvas {
width: flex-grid(4.5, 9);
float: left;
margin-right: flex-gutter(9);
}
div.schematic-sliders {
width: flex-grid(4.5, 9);
float: left;
label[for="vrCheckbox"], label[for="vrRadioButton"]{
color: desaturate(#1df914, 40%);
}
div.slider-label#vs {
margin-top: lh(2.0);
//RC Filters
label[for="vcCheckbox"], label[for="vcRadioButton"]{
color: darken(#ffcf48, 20%);
}
div.slider-label {
margin-bottom: lh(0.5);
//RLC Series
label[for="vlCheckbox"], label[for="vlRadioButton"]{
color: desaturate(#d33682, 40%);
}
div.slider {
margin-bottom: lh(1);
div.schematic-sliders {
div.slider-label {
margin-bottom: lh(0.5);
font-weight: bold;
text-shadow: 0 -1px 0 darken(#073642, 10%);
-webkit-font-smoothing: antialiased;
}
div.slider {
margin-bottom: lh(1);
&.ui-slider-horizontal {
height: 0.4em;
background: darken(#002b36, 2%);
border: 1px solid darken(#002b36, 8%);
@include box-shadow(none);
}
.ui-slider-handle {
background-color: #dc322f;
margin-top: -.3em;
&:hover, &:active {
background-color: lighten(#dc322f, 5%);
}
}
}
}
}
}
//End JM MOSFET AMPLIFIER
// Labels
div.graph-controls, div#graph-listen {
label {
@include border-radius(2px);
font-weight: bold;
padding: 3px;
}
//MOSFET AMPLIFIER
label[for="vinCheckbox"], label[for="vinRadioButton"]{
color: desaturate(#00bfff, 50%);
}
label[for="voutCheckbox"], label[for="voutRadioButton"]{
color: darken(#ffcf48, 20%);
}
label[for="vrCheckbox"], label[for="vrRadioButton"]{
color: desaturate(#1df914, 40%);
}
//RC Filters
label[for="vcCheckbox"], label[for="vcRadioButton"]{
color: darken(#ffcf48, 20%);
}
//RLC Series
label[for="vlCheckbox"], label[for="vlRadioButton"]{
color: desaturate(#d33682, 40%);
}
}
html {
html {
height: 100%;
max-height: 100%;
}
......@@ -172,7 +172,7 @@ div.course-wrapper {
header {
@extend h1.top-header;
margin-bottom: 0;
margin-bottom: -16px;
h1 {
margin: 0;
......@@ -193,10 +193,18 @@ div.course-wrapper {
padding-bottom: 0;
}
ul {
list-style: disc outside none;
padding-left: 1em;
}
nav.sequence-bottom {
ul {
list-style: none;
padding: 0;
}
}
}
}
......@@ -258,6 +266,24 @@ div.course-wrapper {
}
}
}
div.ui-tabs {
border: 0;
@include border-radius(0);
margin: 0;
padding: 0;
.ui-tabs-nav {
background: none;
border: 0;
margin-bottom: lh(.5);
}
.ui-tabs-panel {
@include border-radius(0);
padding: 0;
}
}
}
&.closed {
......
......@@ -235,26 +235,20 @@ nav.sequence-nav {
section.course-content {
div#seq_content {
margin-bottom: 60px;
}
position: relative;
nav.sequence-bottom {
bottom: (-(lh()));
position: relative;
margin: lh(2) 0 0;
text-align: center;
ul {
@extend .clearfix;
background-color: darken(#F6EFD4, 5%);
background-color: darken($cream, 5%);
border: 1px solid darken(#f6efd4, 20%);
border-bottom: 0;
@include border-radius(3px 3px 0 0);
@include border-radius(3px);
@include box-shadow(inset 0 0 0 1px lighten(#f6efd4, 5%));
margin: 0 auto;
overflow: hidden;
width: 106px;
@include inline-block();
li {
float: left;
......@@ -267,15 +261,13 @@ section.course-content {
background-repeat: no-repeat;
border-bottom: none;
display: block;
display: block;
padding: lh(.75) 4px;
padding: lh(.5) 4px;
text-indent: -9999px;
@include transition(all, .4s, $ease-in-out-quad);
width: 45px;
&:hover {
background-color: darken($cream, 10%);
color: darken(#F6EFD4, 60%);
color: darken($cream, 60%);
opacity: .5;
text-decoration: none;
......@@ -291,6 +283,7 @@ section.course-content {
&.prev {
a {
background-image: url('/static/images/sequence-nav/previous-icon.png');
border-right: 1px solid darken(#f6efd4, 20%);
&:hover {
background-color: none;
......
......@@ -143,6 +143,8 @@ section.course-content {
float: left;
margin-right: lh();
@extend .dullify;
list-style: none;
padding: 0;
li {
float: left;
......
......@@ -20,6 +20,7 @@ section.index-content {
p {
line-height: lh();
margin-bottom: lh();
}
ul {
......@@ -237,6 +238,19 @@ section.index-content {
padding-top: lh(8);
}
}
div.announcement {
p.announcement-button {
a {
margin-top: 0;
}
}
img {
max-width: 100%;
margin-bottom: lh();
}
}
}
......
li.calc-main {
bottom: -36px;
bottom: -126px;
left: 0;
position: fixed;
width: 100%;
@include transition(bottom);
z-index: 99;
-webkit-appearance: none;
&.open {
bottom: -36px;
div#calculator_wrapper form div.input-wrapper div.help-wrapper dl {
display: block;
}
}
a.calc {
@include hide-text;
......@@ -33,11 +44,12 @@ li.calc-main {
position: relative;
top: -36px;
clear: both;
max-height: 90px;
form {
padding: lh();
@extend .clearfix;
@include box-sizing(border-box);
input#calculator_button {
background: #111;
......@@ -46,13 +58,14 @@ li.calc-main {
@include box-shadow(none);
@include box-sizing(border-box);
color: #fff;
float: left;
font-size: 30px;
font-weight: bold;
margin: 0 (flex-gutter() / 2);
padding: 0;
text-shadow: none;
-webkit-appearance: none;
width: flex-grid(.5) + flex-gutter();
float: left;
margin: 0 (flex-gutter() / 2);
&:hover {
color: #333;
......@@ -70,15 +83,16 @@ li.calc-main {
font-weight: bold;
margin: 1px 0 0;
padding: 10px;
-webkit-appearance: none;
width: flex-grid(4);
}
div.input-wrapper {
position: relative;
@extend .clearfix;
width: flex-grid(7.5);
margin: 0;
float: left;
margin: 0;
position: relative;
width: flex-grid(7.5);
input#calculator_input {
border: none;
......@@ -86,6 +100,7 @@ li.calc-main {
@include box-sizing(border-box);
font-size: 16px;
padding: 10px;
-webkit-appearance: none;
width: 100%;
&:focus {
......@@ -117,6 +132,7 @@ li.calc-main {
right: -40px;
top: -110px;
width: 500px;
display: none;
@include transition();
&.shown {
......
<%!
import json
import math
%>
var rawData = ${json.dumps(histogram)};
var maxx = 1;
var maxy = 1.5;
var xticks = Array();
var yticks = Array();
var data = Array();
for (var i = 0; i < rawData.length; i++) {
var score = rawData[i][0];
var count = rawData[i][1];
var log_count = Math.log(count + 1);
data.push( [score, log_count] );
xticks.push( [score, score.toString()] );
yticks.push( [log_count, count.toString()] );
maxx = Math.max( score + 1, maxx );
maxy = Math.max(log_count*1.1, maxy );
}
$.plot($("#histogram_${module_id}"), [{
data: data,
bars: { show: true,
align: 'center',
lineWidth: 0,
fill: 1.0 },
color: "#b72121",
}],
{
xaxis: {min: -1, max: maxx, ticks: xticks, tickLength: 0},
yaxis: {min: 0.0, max: maxy, ticks: yticks, labelWidth: 50},
}
);
<div class="staff_info">
${xml | h}
</div>
<div>
${ str(histogram) }
</div>
%if render_histogram:
<div id="histogram_${module_id}" style="width:200px;height:150px"></div>
%endif
......@@ -122,3 +122,11 @@
});
</script>
</%block>
<ol class="video-mod">
% for t in annotations:
<li id="video-${annotations.index(t)}">
${t[1]['content']}
</li>
% endfor
</ol>
......@@ -49,6 +49,7 @@ if settings.COURSEWARE_ENABLED:
url(r'^courseware/$', 'courseware.views.index', name="courseware"),
url(r'^info$', 'util.views.info'),
url(r'^wiki/', include('simplewiki.urls')),
url(r'^masquerade/', include('masquerade.urls')),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index', name="courseware_chapter"),
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index', name="courseware_course"),
......@@ -76,6 +77,10 @@ if settings.ASKBOT_ENABLED:
# url(r'^robots.txt$', include('robots.urls')),
)
if settings.DEBUG:
## Jasmine
urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),)
urlpatterns = patterns(*urlpatterns)
if settings.DEBUG:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment