Commit 202659cb by Bridger Maxwell

Merged in master branch

parents 5aa68c9b 0704bb37
File deleted
...@@ -9,3 +9,5 @@ courseware/static/js/mathjax/* ...@@ -9,3 +9,5 @@ courseware/static/js/mathjax/*
db.newaskbot db.newaskbot
db.oldaskbot db.oldaskbot
flushdb.sh flushdb.sh
build
\#*\#
\ No newline at end of file
...@@ -5,6 +5,7 @@ import operator ...@@ -5,6 +5,7 @@ import operator
import re import re
import numpy import numpy
import numbers
import scipy.constants import scipy.constants
from pyparsing import Word, alphas, nums, oneOf, Literal from pyparsing import Word, alphas, nums, oneOf, Literal
...@@ -121,7 +122,7 @@ def evaluator(variables, functions, string, cs=False): ...@@ -121,7 +122,7 @@ def evaluator(variables, functions, string, cs=False):
def number_parse_action(x): # [ '7' ] -> [ 7 ] def number_parse_action(x): # [ '7' ] -> [ 7 ]
return [super_float("".join(x))] return [super_float("".join(x))]
def exp_parse_action(x): # [ 2 ^ 3 ^ 2 ] -> 512 def exp_parse_action(x): # [ 2 ^ 3 ^ 2 ] -> 512
x = [e for e in x if type(e) in [float, numpy.float64, numpy.complex]] # Ignore ^ x = [e for e in x if isinstance(e, numbers.Number)] # Ignore ^
x.reverse() x.reverse()
x=reduce(lambda a,b:b**a, x) x=reduce(lambda a,b:b**a, x)
return x return x
...@@ -130,7 +131,7 @@ def evaluator(variables, functions, string, cs=False): ...@@ -130,7 +131,7 @@ def evaluator(variables, functions, string, cs=False):
return x[0] return x[0]
if 0 in x: if 0 in x:
return float('nan') return float('nan')
x = [1./e for e in x if type(e) == float] # Ignore ^ x = [1./e for e in x if isinstance(e, numbers.Number)] # Ignore ||
return 1./sum(x) return 1./sum(x)
def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0 def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0
total = 0.0 total = 0.0
...@@ -217,4 +218,7 @@ if __name__=='__main__': ...@@ -217,4 +218,7 @@ if __name__=='__main__':
print evaluator({},{}, "-(7+5)") print evaluator({},{}, "-(7+5)")
print evaluator({},{}, "-0.33") print evaluator({},{}, "-0.33")
print evaluator({},{}, "-.33") print evaluator({},{}, "-.33")
print evaluator({},{}, "5+1*j")
print evaluator({},{}, "j||1")
print evaluator({},{}, "e^(j*pi)")
print evaluator({},{}, "5+7 QWSEKO") print evaluator({},{}, "5+7 QWSEKO")
...@@ -8,7 +8,8 @@ class textline(object): ...@@ -8,7 +8,8 @@ class textline(object):
def render(element, value, state): def render(element, value, state):
eid=element.get('id') eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK count = int(eid.split('_')[-2])-1 # HACK
context = {'id':eid, 'value':value, 'state':state, 'count':count} size = element.get('size')
context = {'id':eid, 'value':value, 'state':state, 'count':count, 'size': size}
html=render_to_string("textinput.html", context) html=render_to_string("textinput.html", context)
return etree.XML(html) return etree.XML(html)
......
import json import json
import math import math
import numbers
import numpy import numpy
import random import random
import scipy import scipy
...@@ -37,7 +38,6 @@ class numericalresponse(object): ...@@ -37,7 +38,6 @@ class numericalresponse(object):
def __init__(self, xml, context): def __init__(self, xml, context):
self.xml = xml self.xml = xml
self.correct_answer = contextualize_text(xml.get('answer'), context) self.correct_answer = contextualize_text(xml.get('answer'), context)
self.correct_answer = float(self.correct_answer)
self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default', self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
id=xml.get('id'))[0] id=xml.get('id'))[0]
self.tolerance = contextualize_text(self.tolerance_xml, context) self.tolerance = contextualize_text(self.tolerance_xml, context)
...@@ -48,7 +48,10 @@ class numericalresponse(object): ...@@ -48,7 +48,10 @@ class numericalresponse(object):
''' Display HTML for a numeric response ''' ''' Display HTML for a numeric response '''
student_answer = student_answers[self.answer_id] student_answer = student_answers[self.answer_id]
try: try:
correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), self.correct_answer, self.tolerance) correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), complex(self.correct_answer), self.tolerance)
# We should catch this explicitly.
# I think this is just pyparsing.ParseException, calc.UndefinedVariable:
# But we'd need to confirm
except: except:
raise StudentInputError('Invalid input -- please use a number only') raise StudentInputError('Invalid input -- please use a number only')
...@@ -141,7 +144,7 @@ class formularesponse(object): ...@@ -141,7 +144,7 @@ class formularesponse(object):
except: except:
#traceback.print_exc() #traceback.print_exc()
raise StudentInputError("Error in formula") raise StudentInputError("Error in formula")
if math.isnan(student_result) or math.isinf(student_result): if numpy.isnan(student_result) or numpy.isinf(student_result):
return {self.answer_id:"incorrect"} return {self.answer_id:"incorrect"}
if not compare_with_tolerance(student_result, instructor_result, self.tolerance): if not compare_with_tolerance(student_result, instructor_result, self.tolerance):
return {self.answer_id:"incorrect"} return {self.answer_id:"incorrect"}
...@@ -153,9 +156,9 @@ class formularesponse(object): ...@@ -153,9 +156,9 @@ class formularesponse(object):
keys and all non-numeric values stripped out. All values also keys and all non-numeric values stripped out. All values also
converted to float. Used so we can safely use Python contexts. converted to float. Used so we can safely use Python contexts.
''' '''
d=dict([(k, float(d[k])) for k in d if type(k)==str and \ d=dict([(k, numpy.complex(d[k])) for k in d if type(k)==str and \
k.isalnum() and \ k.isalnum() and \
(type(d[k]) == float or type(d[k]) == int) ]) isinstance(d[k], numbers.Number)])
return d return d
def get_answers(self): def get_answers(self):
......
...@@ -26,6 +26,12 @@ import courseware.content_parser as content_parser ...@@ -26,6 +26,12 @@ import courseware.content_parser as content_parser
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, complex):
return "{real:.7g}{imag:+.7g}*j".format(real = obj.real,imag = obj.imag)
return json.JSONEncoder.default(self, obj)
class Module(XModule): class Module(XModule):
''' Interface between capa_problem and x_module. Originally a hack ''' Interface between capa_problem and x_module. Originally a hack
meant to be refactored out, but it seems to be serving a useful meant to be refactored out, but it seems to be serving a useful
...@@ -240,7 +246,8 @@ class Module(XModule): ...@@ -240,7 +246,8 @@ class Module(XModule):
if not self.answer_available(): if not self.answer_available():
raise Http404 raise Http404
else: else:
return json.dumps(self.lcp.get_question_answers()) return json.dumps(self.lcp.get_question_answers(),
cls=ComplexEncoder)
# Figure out if we should move these to capa_problem? # Figure out if we should move these to capa_problem?
......
...@@ -20,7 +20,7 @@ class ModelsTest(unittest.TestCase): ...@@ -20,7 +20,7 @@ class ModelsTest(unittest.TestCase):
variables={'R1':2.0, 'R3':4.0} variables={'R1':2.0, 'R3':4.0}
functions={'sin':numpy.sin, 'cos':numpy.cos} functions={'sin':numpy.sin, 'cos':numpy.cos}
self.assertEqual(calc.evaluator(variables, functions, "10000||sin(7+5)-6k"), 4000.0) self.assertTrue(abs(calc.evaluator(variables, functions, "10000||sin(7+5)+0.5356"))<0.01)
self.assertEqual(calc.evaluator({'R1': 2.0, 'R3':4.0}, {}, "13"), 13) self.assertEqual(calc.evaluator({'R1': 2.0, 'R3':4.0}, {}, "13"), 13)
self.assertEqual(calc.evaluator(variables, functions, "13"), 13) self.assertEqual(calc.evaluator(variables, functions, "13"), 13)
self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5) self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5)
...@@ -30,6 +30,8 @@ class ModelsTest(unittest.TestCase): ...@@ -30,6 +30,8 @@ class ModelsTest(unittest.TestCase):
self.assertEqual(calc.evaluator(variables, functions, "R1*R3"), 8.0) self.assertEqual(calc.evaluator(variables, functions, "R1*R3"), 8.0)
self.assertTrue(abs(calc.evaluator(variables, functions, "sin(e)-0.41"))<0.01) self.assertTrue(abs(calc.evaluator(variables, functions, "sin(e)-0.41"))<0.01)
self.assertTrue(abs(calc.evaluator(variables, functions, "k*T/q-0.025"))<0.001) self.assertTrue(abs(calc.evaluator(variables, functions, "k*T/q-0.025"))<0.001)
self.assertTrue(abs(calc.evaluator(variables, functions, "e^(j*pi)")+1)<0.00001)
self.assertTrue(abs(calc.evaluator(variables, functions, "j||1")-0.5-0.5j)<0.00001)
exception_happened = False exception_happened = False
try: try:
calc.evaluator({},{}, "5+7 QWSEKO") calc.evaluator({},{}, "5+7 QWSEKO")
......
...@@ -12,6 +12,7 @@ import uuid ...@@ -12,6 +12,7 @@ import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
import json
#from cache_toolbox import cache_model, cache_relation #from cache_toolbox import cache_model, cache_relation
...@@ -29,6 +30,18 @@ class UserProfile(models.Model): ...@@ -29,6 +30,18 @@ class UserProfile(models.Model):
meta = models.CharField(blank=True, max_length=255) # JSON dictionary for future expansion meta = models.CharField(blank=True, max_length=255) # JSON dictionary for future expansion
courseware = models.CharField(blank=True, max_length=255, default='course.xml') courseware = models.CharField(blank=True, max_length=255, default='course.xml')
def get_meta(self):
js_str = self.meta
if not js_str:
js_str = dict()
else:
js_str = json.loads(self.meta)
return js_str
def set_meta(self,js):
self.meta = json.dumps(js)
## TODO: Should be renamed to generic UserGroup, and possibly ## TODO: Should be renamed to generic UserGroup, and possibly
# Given an optional field for type of group # Given an optional field for type of group
class UserTestGroup(models.Model): class UserTestGroup(models.Model):
...@@ -58,6 +71,16 @@ class Registration(models.Model): ...@@ -58,6 +71,16 @@ class Registration(models.Model):
self.user.save() self.user.save()
#self.delete() #self.delete()
class PendingNameChange(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True)
new_name = models.CharField(blank=True, max_length=255)
rationale = models.CharField(blank=True, max_length=1024)
class PendingEmailChange(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True)
new_email = models.CharField(blank=True, max_length=255, db_index=True)
activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True)
#cache_relation(User.profile) #cache_relation(User.profile)
#### Helper methods for use from python manage.py shell. #### Helper methods for use from python manage.py shell.
...@@ -88,6 +111,8 @@ def change_name(email, new_name): ...@@ -88,6 +111,8 @@ def change_name(email, new_name):
up.save() up.save()
def user_count(): def user_count():
print "All users", User.objects.all().count()
print "Active users", User.objects.filter(is_active = True).count()
return User.objects.all().count() return User.objects.all().count()
def active_user_count(): def active_user_count():
...@@ -99,12 +124,29 @@ def create_group(name, description): ...@@ -99,12 +124,29 @@ def create_group(name, description):
utg.description = description utg.description = description
utg.save() utg.save()
def add_user_to_group(group, user): def add_user_to_group(user, group):
utg = UserTestGroup.objects.get(name = group) utg = UserTestGroup.objects.get(name = group)
utg.users.add(User.objects.get(username = user)) utg.users.add(User.objects.get(username = user))
utg.save() utg.save()
def remove_user_from_group(group, user): def remove_user_from_group(user, group):
utg = UserTestGroup.objects.get(name = group) utg = UserTestGroup.objects.get(name = group)
utg.users.remove(User.objects.get(username = user)) utg.users.remove(User.objects.get(username = user))
utg.save() utg.save()
default_groups = {'email_future_courses' : 'Receive e-mails about future MITx courses',
'email_helpers' : 'Receive e-mails about how to help with MITx',
'mitx_unenroll' : 'Fully unenrolled -- no further communications',
'6002x_unenroll' : 'Took and dropped 6002x'}
def add_user_to_default_group(user, group):
try:
utg = UserTestGroup.objects.get(name = group)
except UserTestGroup.DoesNotExist:
utg = UserTestGroup()
utg.name = group
utg.description = default_groups[group]
utg.save()
utg.users.add(User.objects.get(username = user))
utg.save()
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distribuetd under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
from mako.lookup import TemplateLookup from mako.lookup import TemplateLookup
import tempfile import tempfile
from django.template import RequestContext from django.template import RequestContext
from django.conf import settings
requestcontext = None requestcontext = None
lookup = {} lookup = {}
...@@ -44,4 +45,5 @@ class MakoMiddleware(object): ...@@ -44,4 +45,5 @@ class MakoMiddleware(object):
def process_request (self, request): def process_request (self, request):
global requestcontext global requestcontext
requestcontext = RequestContext(request) requestcontext = RequestContext(request)
requestcontext['is_secure'] = request.is_secure()
requestcontext['site'] = settings.SITE_NAME
...@@ -18,18 +18,21 @@ from django.http import HttpResponse ...@@ -18,18 +18,21 @@ from django.http import HttpResponse
import mitxmako.middleware as middleware import mitxmako.middleware as middleware
from django.conf import settings from django.conf import settings
from mitxmako.middleware import requestcontext import mitxmako.middleware
def render_to_string(template_name, dictionary, context_instance=None, namespace='main'): def render_to_string(template_name, dictionary, context=None, namespace='main'):
context_instance = context_instance or Context(dictionary) context_instance = Context(dictionary)
# add dictionary to context_instance # add dictionary to context_instance
context_instance.update(dictionary or {}) context_instance.update(dictionary or {})
# collapse context_instance to a single dictionary for mako # collapse context_instance to a single dictionary for mako
context_dictionary = {} context_dictionary = {}
context_instance['settings'] = settings context_instance['settings'] = settings
context_instance['request_context'] = requestcontext for d in mitxmako.middleware.requestcontext:
context_dictionary.update(d)
for d in context_instance: for d in context_instance:
context_dictionary.update(d) context_dictionary.update(d)
if context:
context_dictionary.update(context)
# fetch and render template # fetch and render template
template = middleware.lookup[namespace].get_template(template_name) template = middleware.lookup[namespace].get_template(template_name)
return template.render(**context_dictionary) return template.render(**context_dictionary)
......
require 'rake/clean' require 'rake/clean'
require 'tempfile' require 'tempfile'
# Build Constants
REPO_ROOT = File.dirname(__FILE__) REPO_ROOT = File.dirname(__FILE__)
BUILD_DIR = File.join(REPO_ROOT, "build") BUILD_DIR = File.join(REPO_ROOT, "build")
# Packaging constants
DEPLOY_DIR = "/opt/wwc"
PACKAGE_NAME = "mitx"
LINK_PATH = File.join(DEPLOY_DIR, PACKAGE_NAME)
VERSION = "0.1"
COMMIT = (ENV["GIT_COMMIT"] || `git rev-parse HEAD`).chomp()[0, 10]
BRANCH = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp().gsub('refs/heads/', '').gsub('origin/', '').gsub('/', '_')
BUILD_NUMBER = (ENV["BUILD_NUMBER"] || "dev").chomp()
if BRANCH == "master"
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BUILD_NUMBER}-#{COMMIT}"
else
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BRANCH}-#{BUILD_NUMBER}-#{COMMIT}"
end
INSTALL_DIR_PATH = File.join(DEPLOY_DIR, DEPLOY_NAME)
PACKAGE_REPO = "packages@gp.mitx.mit.edu:/opt/pkgrepo.incoming"
# Set up the clean and clobber tasks
CLOBBER.include('build') CLOBBER.include('build')
CLEAN.include("#{BUILD_DIR}/*.deb") CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util")
task :package do
commit = (ENV["GIT_COMMIT"] || `git rev-parse HEAD`).chomp()
branch = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp()
branch = branch.gsub('refs/heads/', '').gsub('origin/', '').gsub('/', '_')
build_number = (ENV["BUILD_NUMBER"] || "dev").chomp()
if branch == "master"
package_name = "mitx"
else
package_name = "mitx-#{branch}"
end
task :package do
FileUtils.mkdir_p(BUILD_DIR) FileUtils.mkdir_p(BUILD_DIR)
Dir.chdir(BUILD_DIR) do Dir.chdir(BUILD_DIR) do
postinstall = Tempfile.new('postinstall')
postinstall.write <<-POSTINSTALL.gsub(/^\s*/, '')
#! /bin/sh
set -e
set -x
service gunicorn stop
rm -f #{LINK_PATH}
ln -s #{INSTALL_DIR_PATH} #{LINK_PATH}
service gunicorn start
POSTINSTALL
postinstall.close()
FileUtils.chmod(0755, postinstall.path)
args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb", args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb",
"--exclude=build", "--after-install=#{postinstall.path}",
"--exclude=rakefile", "--prefix=#{INSTALL_DIR_PATH}",
"--exclude=.git", "-C", "#{REPO_ROOT}",
"--prefix=/opt/wwc/mitx-#{commit}",
"--depends=python-mysqldb", "--depends=python-mysqldb",
"--depends=python-django", "--depends=python-django",
"--depends=python-pip", "--depends=python-pip",
...@@ -40,11 +65,15 @@ task :package do ...@@ -40,11 +65,15 @@ task :package do
"--depends=python-markdown", "--depends=python-markdown",
"--depends=python-pygments", "--depends=python-pygments",
"--depends=mysql-client", "--depends=mysql-client",
"--name=#{package_name}-#{commit}", "--provides=#{PACKAGE_NAME}",
"--version=0.1", "--name=#{DEPLOY_NAME}",
"--iteration=#{build_number}", "--version=#{VERSION}",
"-a", "all", "-a", "all",
"#{REPO_ROOT}"] "."]
system(*args) || raise("fpm failed to build the .deb") system(*args) || raise("fpm failed to build the .deb")
end end
end end
task :publish => :package do
sh("scp #{BUILD_DIR}/#{DEPLOY_NAME}_#{VERSION}-1_all.deb #{PACKAGE_REPO}")
end
...@@ -166,6 +166,15 @@ MAKO_TEMPLATES = {} ...@@ -166,6 +166,15 @@ MAKO_TEMPLATES = {}
LOGGING_ENV = "dev" # override this in different environments LOGGING_ENV = "dev" # override this in different environments
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '../mitx.db',
}
}
SECRET_KEY = 'unsecure'
# Default dev cache (i.e. no caching) # Default dev cache (i.e. no caching)
CACHES = { CACHES = {
'default': { 'default': {
...@@ -240,7 +249,7 @@ LOGGING = { ...@@ -240,7 +249,7 @@ LOGGING = {
}, },
'loggers' : { 'loggers' : {
'django' : { 'django' : {
'handlers' : handlers + ['mail_admins'], 'handlers' : handlers, # + ['mail_admins'],
'propagate' : True, 'propagate' : True,
'level' : 'INFO' 'level' : 'INFO'
}, },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -352,6 +352,8 @@ function updateytplayerInfo() { ...@@ -352,6 +352,8 @@ function updateytplayerInfo() {
} }
if (player_state == 1){ if (player_state == 1){
update_captions(getCurrentTime()); update_captions(getCurrentTime());
handle = $('.ui-slider-handle', $('#slider'));
handle.qtip('option', 'content.text', '' + format_time(getCurrentTime()));
} }
// updateHTML("videoduration", getDuration()); // updateHTML("videoduration", getDuration());
// updateHTML("videotime", getCurrentTime()); // updateHTML("videotime", getCurrentTime());
......
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
<section class="activation"> <section class="activation">
<h1>Account already active!</h1> <h1>Account already active!</h1>
<!-- <p>Now go <a href="/">log in</a> and try the course!</a></p> --> <!-- <p>Now go <a href="/">log in</a> and try the course!</a></p> -->
<p> This account has already been activated. We will notify you as <p> This account has already been activated. You can log in at
soon as the course starts.</p> the <a href="/">6.002x course page</a>.</p>
<p>For now you can go to the <a href="http://mitx.mit.edu/">MITx homepage</a> or the <a href="/">6.002x course page</a>.</p>
</div> </div>
</section> </section>
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
<div> <div>
<h1>Activation Complete!</h1> <h1>Activation Complete!</h1>
<!-- <p>Now go <a href="/">log in</a> and try the course!</a></p> --> <!-- <p>Now go <a href="/">log in</a> and try the course!</a></p> -->
<p>Thanks for activating your email. We will notify you as soon as the course starts.</p> <p>Thanks for activating your account. You can log in at the <a href="/">6.002x course page</a>.</p>
<p>For now you can go to the <a href="http://mitx.mit.edu/">MITx homepage</a> or the <a href="/">6.002x course page</a>.</p>
</div> </div>
</section> </section>
<h1>E-mail change successful!</h1>
<p> You should see your new name in your profile.
<h1> Could not change e-mail </h1>
An account with the new e-mail address already exists. Sorry.
...@@ -3,7 +3,11 @@ offering of 6.002 using this email address. If it was you, and you'd ...@@ -3,7 +3,11 @@ offering of 6.002 using this email address. If it was you, and you'd
like to activate and use your account, copy and paste this address like to activate and use your account, copy and paste this address
into your web browser's address bar: into your web browser's address bar:
http://${ site }/activate/${ key } % if is_secure:
https://${ site }/activate/${ key }
% else:
http://${ site }/activate/${ key }
% endif
If you didn't request this, you don't need to do anything; you won't If you didn't request this, you don't need to do anything; you won't
receive any more email from us. Please do not reply to this e-mail; if receive any more email from us. Please do not reply to this e-mail; if
......
This is to confirm that you changed the e-mail associated with MITx
from ${old_email} to ${new_email}. If you did not make this request,
please contact the course staff immediately. Contact information is
listed at:
% if is_secure:
https://${ site }/t/mitx_help.html
% else:
http://${ site }/t/mitx_help.html
% endif
We keep a log of old e-mails, so if this request was unintentional, we
can investigate.
We received a request to change the e-mail associated with your MITx
account from ${old_email} to ${new_email}. If this is correct, please
confirm your new e-mail address by visiting:
% if is_secure:
https://${ site }/email_confirm/${ key }
% else:
http://${ site }/email_confirm/${ key }
% endif
If you didn't request this, you don't need to do anything; you won't
receive any more email from us. Please do not reply to this e-mail; if
you require assistance, check the help section of the MITx web site.
Request to change MITx account e-mail
(Not currently used)
We are sorry. Our course staff did not approve your request to change
your name from ${old_name} to ${new_name}. If you need further
assistance, please e-mail the course staff at ta@mitx.mit.edu.
MITx's prototype offering, 6.002x, is now open. To log in, visit MITx's prototype offering, 6.002x, is now open. To log in, visit
% if is_secure:
https://6002x.mitx.mit.edu https://6002x.mitx.mit.edu
% else:
http://6002x.mitx.mit.edu
% endif
where you will find a login button at the top right-hand corner of the where you will find a login button at the top right-hand corner of the
window. window.
......
<h1>E-mail change successful!</h1>
<p> You should see your new name in your profile.
<%inherit file="main.html" /> <%inherit file="main.html" />
<%block name="headextra">
<script type="text/javascript" src="/static/js/flot/jquery.flot.js"></script>
<script type="text/javascript" src="/static/js/flot/jquery.flot.stack.js"></script>
<script type="text/javascript" src="/static/js/flot/jquery.flot.symbol.js"></script>
<style type="text/css">
.grade_a {color:green;}
.grade_b {color:Chocolate;}
.grade_c {color:DimGray;}
.grade_none {color:LightGray;}
</style>
</%block>
<%include file="navigation.html" args="active_page=''" /> <%include file="navigation.html" args="active_page=''" />
<section class="main-content"> <section class="main-content">
<div class="gradebook-wrapper"> <div class="gradebook-wrapper">
<section class="gradebook-content"> <section class="gradebook-content">
<h1>Gradebook</h1> <h1>Gradebook</h1>
% for s in students:
<h2><a href=/profile/${s['id']}>${s['username']}</a></h2> %if len(students) > 0:
% for c in s['grade_info']['grade_summary']: <table>
<h3>${c['category']} </h3> <%
<p> templateSummary = students[0]['grade_info']['grade_summary']
% if 'subscores' in c: %>
% for ss in c['subscores']:
<br>${ss['summary']}
% endfor <tr> <!-- Header Row -->
% endif <th>Student</th>
</p> %for section in templateSummary:
% endfor %if 'subscores' in section:
% endfor %for subsection in section['subscores']:
<th>${subsection['label']}</th>
%endfor
<th>${section['totallabel']}</th>
%else:
<th>${section['category']}</th>
%endif
%endfor
</tr>
<%def name="percent_data(percentage)">
<%
data_class = "grade_none"
if percentage > .87:
data_class = "grade_a"
elif percentage > .70:
data_class = "grade_b"
elif percentage > .6:
data_class = "grade_c"
%>
<td class="${data_class}">${ "{0:.0%}".format( percentage ) }</td>
</%def>
%for student in students:
<tr>
<td><a href="/profile/${student['id']}/">${student['username']}</a></td>
%for section in student['grade_info']['grade_summary']:
%if 'subscores' in section:
%for subsection in section['subscores']:
${percent_data( subsection['percentage'] )}
%endfor
${percent_data( section['totalscore'] )}
%else:
${percent_data( section['totalscore'] )}
%endif
%endfor
</tr>
%endfor
</table>
%endif
</section> </section>
</div> </div>
</section> </section>
<%inherit file="main.html" />
<%namespace name="profile_graphs" file="profile_graphs.js"/>
<%block name="headextra">
<script type="text/javascript" src="/static/js/flot/jquery.flot.js"></script>
<script type="text/javascript" src="/static/js/flot/jquery.flot.stack.js"></script>
<script type="text/javascript" src="/static/js/flot/jquery.flot.symbol.js"></script>
% for s in students:
<script>
${profile_graphs.body(s['grade_info']['grade_summary'], "grade-detail-graph-" + str(s['id']))}
</script>
%endfor
</%block>
<%include file="navigation.html" args="active_page=''" />
<section class="main-content">
<div class="gradebook-wrapper">
<section class="gradebook-content">
<h1>Gradebook</h1>
<ol>
% for s in students:
<li>
<h2><a href=/profile/${s['id']}>${s['username']}</a></h2>
<div id="grade-detail-graph-${s['id']}" style="width:1000px;height:300px;"></div>
</li>
% endfor
</ol>
</section>
</div>
</section>
<%inherit file="main.html" /> <%inherit file="main.html" />
<%block name="js_extra">
<script>
$(document).ready(function(){
//if(!page) {
// cookie_page = $.cookie("book_page");
// if(cookie_page) {
// goto_page(cookie_page);
// }
//}
$(".handouts ol").treeview({collapsed:true, unique:true/*, cookieId: "treeview-book-nav", persist: "cookie"*/});
});
</script>
</%block>
<%block name="title"><title>Course Info - MITx 6.002x</title></%block> <%block name="title"><title>Course Info - MITx 6.002x</title></%block>
<%include file="navigation.html" args="active_page='info'" /> <%include file="navigation.html" args="active_page='info'" />
......
<h1>Invalid key</h1>
<p> This e-mail key is not valid. Please check:
<ul>
<li> Was this key already used? Check whether the e-mail change has already happened.
<li> Did your e-mail client break the URL into two lines?
<li> The keys are valid for a limited amount of time. Has the key expired?
</ul>
...@@ -107,6 +107,7 @@ ...@@ -107,6 +107,7 @@
<script type="text/javascript" src="${ settings.LIB_URL }jquery.treeview.js"></script> <script type="text/javascript" src="${ settings.LIB_URL }jquery.treeview.js"></script>
<script type="text/javascript" src="/static/js/jquery.leanModal.min.js"></script> <script type="text/javascript" src="/static/js/jquery.leanModal.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.qtip.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.cookie.js"></script> <script type="text/javascript" src="/static/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/static/js/video_player.js"></script> <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/schematic.js"></script>
......
<%inherit file="main.html" />
<%include file="navigation.html" args="active_page=''" />
<section class="main-content">
<script>
function name_confirm(id) {
postJSON('/accept_name_change',{"id":id},
function(data){
if(data.success){
$("#div"+id).html("Accepted");
} else {
alert('Error');
}
});
}
function name_deny(id) {
postJSON('/reject_name_change',{"id":id},
function(data){
if(data.success){
$("#div"+id).html("Rejected");
} else {
alert('Error');
}
});
}
</script>
<div class="gradebook-wrapper">
<section class="gradebook-content">
<h1>Pending name changes</h1>
<table>
% for s in students:
<tr>
<td><a href=/profile/${s['uid']}/>${s['old_name']}</td>
<td>${s['new_name']|h}</td>
<td>${s['email']|h}</td>
<td>${s['rationale']|h}</td>
<td><span id="div${s['cid']}"><span onclick="name_confirm(${s['cid']});">[Confirm]</span>
<span onclick="name_deny(${s['cid']});">[Reject]</span></span></td></tr>
% endfor
</table>
</section>
</div>
</section>
<%inherit file="main.html" /> <%inherit file="main.html" />
<%namespace name="profile_graphs" file="profile_graphs.js"/>
<%block name="title"><title>Profile - MITx 6.002x</title></%block> <%block name="title"><title>Profile - MITx 6.002x</title></%block>
<%! <%!
...@@ -10,7 +12,7 @@ ...@@ -10,7 +12,7 @@
<script type="text/javascript" src="/static/js/flot/jquery.flot.stack.js"></script> <script type="text/javascript" src="/static/js/flot/jquery.flot.stack.js"></script>
<script type="text/javascript" src="/static/js/flot/jquery.flot.symbol.js"></script> <script type="text/javascript" src="/static/js/flot/jquery.flot.symbol.js"></script>
<script> <script>
<%include file="profile_graphs.js"/> ${profile_graphs.body(grade_summary, "grade-detail-graph")}
</script> </script>
<script> <script>
...@@ -78,6 +80,46 @@ $(function() { ...@@ -78,6 +80,46 @@ $(function() {
log_event("profile", {"type":"password_send"}); log_event("profile", {"type":"password_send"});
}); });
}); });
$("#change_email_form").submit(function(){
var new_email = $('#new_email_field').val();
var new_password = $('#new_email_password').val();
postJSON('/change_email',{"new_email":new_email,
"password":new_password},
function(data){
if(data.success){
$("#change_email").html("<h1>Please verify your new email</h1><p>You'll receive a confirmation in your in-box. Please click the link in the email to confirm the email change.</p>");
} else {
$("#change_email_error").html(data.error);
}
});
log_event("profile", {"type":"email_change_request",
"old_email":"${email}",
"new_email":new_email});
return false;
});
$("#change_name_form").submit(function(){
var new_name = $('#new_name_field').val();
var rationale = $('#name_rationale_field').val();
postJSON('/change_name',{"new_name":new_name,
"rationale":rationale},
function(data){
if(data.success){
$("#apply_name_change").html("<h1>Your request has been submitted.</h1><p>We'll send you an e-mail when approve the change or need further information. Please allow for up to a week for us to process your request.</p>");
} else {
$("#change_name_error").html(data.error);
}
});
log_event("profile", {"type":"name_change_request",
"new_name":new_name,
"rationale":rationale});
return false;
});
}); });
</script> </script>
</%block> </%block>
...@@ -89,12 +131,14 @@ $(function() { ...@@ -89,12 +131,14 @@ $(function() {
<div class="profile-wrapper"> <div class="profile-wrapper">
<section class="course-info"> <section class="course-info">
<header>
<h1>Course Progress</h1> <h1>Course Progress</h1>
</header>
<div id="grade-detail-graph"></div> <div id="grade-detail-graph"></div>
<ol class="chapters"> <ol class="chapters">
%for chapter in chapters: %for chapter in courseware_summary:
%if not chapter['chapter'] == "hidden": %if not chapter['chapter'] == "hidden":
<li> <li>
<h2><a href="${reverse('courseware_chapter', args=format_url_params([chapter['course'], chapter['chapter']])) }"> <h2><a href="${reverse('courseware_chapter', args=format_url_params([chapter['course'], chapter['chapter']])) }">
...@@ -104,8 +148,8 @@ $(function() { ...@@ -104,8 +148,8 @@ $(function() {
%for section in chapter['sections']: %for section in chapter['sections']:
<li> <li>
<% <%
earned = section['section_total'][0] earned = section['section_total'].earned
total = section['section_total'][1] total = section['section_total'].possible
percentageString = "{0:.0%}".format( float(earned)/total) if earned > 0 else "" percentageString = "{0:.0%}".format( float(earned)/total) if earned > 0 else ""
%> %>
...@@ -120,7 +164,7 @@ $(function() { ...@@ -120,7 +164,7 @@ $(function() {
<ol class="scores"> <ol class="scores">
${ "Problem Scores: " if section['graded'] else "Practice Scores: "} ${ "Problem Scores: " if section['graded'] else "Practice Scores: "}
%for score in section['scores']: %for score in section['scores']:
<li class="score">${"{0:g}/{1:g}".format(score[0],score[1])}</li> <li class="score">${"{0:g}/{1:g}".format(score.earned,score.possible)}</li>
%endfor %endfor
</ol> </ol>
%endif %endif
...@@ -132,37 +176,135 @@ $(function() { ...@@ -132,37 +176,135 @@ $(function() {
%endif %endif
%endfor %endfor
</ol> <!--End chapters--> </ol> <!--End chapters-->
</section> </section>
<section class="user-info"> <section class="user-info">
<h1>${name}</h1> <header>
<h1>Student Profile</h1>
</header>
<ul> <ul>
<li>Forum name: <strong>${username}</strong></li> <li>
<li>E-mail: <strong>${email}</strong></li> Name: <strong>${name}</strong>
%if True:
<a href="#apply_name_change" rel="leanModal" class="name-edit">Edit</a>
%else:
(Name change pending)
%endif
</li>
<li>
Forum name: <strong>${username}</strong>
</li>
<li>
E-mail: <strong>${email}</strong> <a href="#change_email" rel="leanModal" class="edit-email">Edit</a>
</li>
<li> <li>
Location: <div id="location_sub">${location}</div><div id="description"></div> <a href="#" id="change_location">Edit</a> Location: <div id="location_sub">${location}</div><div id="description"></div> <a href="#" id="change_location">Edit</a>
</li> </li>
<li> <li>
Language: <div id="language_sub">${language}</div> <a href="#" id="change_language">Edit</a> Language: <div id="language_sub">${language}</div> <a href="#" id="change_language">Edit</a>
</li> </li>
</ul> <li>
Password reset
<div id="change_password_pop">
<h2>Password change</h2>
<p>We'll e-mail a password reset link to ${email}.</p>
<input id="id_email" type="hidden" name="email" maxlength="75" value="${email}" /> <input id="id_email" type="hidden" name="email" maxlength="75" value="${email}" />
<input type="submit" id="pwd_reset_button" value="Reset Password" /> <input type="submit" id="pwd_reset_button" value="Reset" />
</div> <p>We'll e-mail a password reset link to ${email}.</p>
</li>
</ul>
</section> </section>
</div> </div>
</section> </section>
<div id="password_reset_complete" class="leanModal_box"> <div id="password_reset_complete" class="leanModal_box">
<a href="#password_reset_complete" rel="leanModal" id="password_reset_complete_link"></a> <a href="#password_reset_complete" rel="leanModal" id="password_reset_complete_link"></a>
<h1>Password Reset Email Sent</h1> <h1>Password Reset Email Sent</h1>
<p>
An email has been sent to ${email}. Follow the link in the email to change your password. An email has been sent to ${email}. Follow the link in the email to change your password.
</div> </p>
</div>
<div id="apply_name_change" class="leanModal_box">
<h1>Apply to change your name</h1>
<form id="change_name_form">
<div id="change_name_error"> </div>
<fieldset>
<p>To uphold the credibility of MITx certificates, name changes must go through an approval process. A member of the course staff will review your request, and if approved, update your information. Please allow up to a week for your request to be processed. Thank you.</p>
<ul>
<li>
<label>Enter your desired full name, as it will appear on the MITx Certificate: </label>
<input id="new_name_field" value="" type="text" />
</li>
<li>
<label>Reason for name change:</label>
<textarea id="name_rationale_field" value=""></textarea>
</li>
<li>
<input type="submit" id="submit">
</li>
</ul>
</fieldset>
</form>
</div>
<div id="change_email" class="leanModal_box">
<h1>Change e-mail</h1>
<div id="apply_name_change_error"></div>
<form id="change_email_form">
<div id="change_email_error"> </div>
<fieldset>
<ul>
<li>
<label> Please enter your new email address: </label>
<input id="new_email_field" type="email" value="" />
</li>
<li>
<label> Please confirm your password: </label>
<input id="new_email_password" value="" type="password" />
</li>
<li>
<p>We will send a confirmation to both ${email} and your new e-mail as part of the process.</p>
<input type="submit" id="submit_email_change" />
</li>
</ul>
</fieldset>
</form>
</div>
<div id="deactivate-account" class="leanModal_box">
<h1>Deactivate MITx Account</h1>
<p>Once you deactivate you&rsquo;re MIT<em>x</em> account you will no longer recieve updates and new class announcements from MIT<em>x</em>.</p>
<p>If you&rsquo;d like to still get updates and new class announcements you can just <a href="#unenroll" rel="leanModal">unenroll</a> and keep your account active.</p>
<form id="unenroll_form">
<div id="unenroll_error"> </div>
<fieldset>
<ul>
<li>
<input type="submit" id="" value="Yes, I don't want an MITx account or hear about any new classes or updates to MITx" />
</li>
</ul>
</fieldset>
</form>
</div>
<div id="unenroll" class="leanModal_box">
<h1>Unenroll from 6.002x</h1>
<p>Please note: you will still receive updates and new class announcements from MIT<em>x</em>. If you don&rsquo;t wish to receive any more updates or announcements <a href="#deactivate-account" rel="leanModal">deactivate your account</a>.</p>
<form id="unenroll_form">
<div id="unenroll_error"> </div>
<fieldset>
<ul>
<li>
<input type="submit" id="" value="Yes, I want to unenroll from 6.002x but still hear about any new classes or updates to MITx" />
</li>
</ul>
</fieldset>
</form>
</div>
<%page args="grade_summary, graph_div_id, **kwargs"/>
<%! <%!
import json import json
%> %>
...@@ -57,21 +58,21 @@ $(function () { ...@@ -57,21 +58,21 @@ $(function () {
category_total_label = section['category'] + " Total" category_total_label = section['category'] + " Total"
series.append({ series.append({
'label' : category_total_label, 'label' : category_total_label,
'data' : [ [tickIndex, section['totalscore']['score']] ], 'data' : [ [tickIndex, section['totalscore']] ],
'color' : colors[sectionIndex] 'color' : colors[sectionIndex]
}) })
ticks.append( [tickIndex, section['totallabel']] ) ticks.append( [tickIndex, section['totallabel']] )
detail_tooltips[category_total_label] = [section['totalscore']['summary']] detail_tooltips[category_total_label] = [section['totalscore_summary']]
else: else:
series.append({ series.append({
'label' : section['category'], 'label' : section['category'],
'data' : [ [tickIndex, section['totalscore']['score']] ], 'data' : [ [tickIndex, section['totalscore']] ],
'color' : colors[sectionIndex] 'color' : colors[sectionIndex]
}) })
ticks.append( [tickIndex, section['totallabel']] ) ticks.append( [tickIndex, section['totallabel']] )
detail_tooltips[section['category']] = [section['totalscore']['summary']] detail_tooltips[section['category']] = [section['totalscore_summary']]
tickIndex += 1 + sectionSpacer tickIndex += 1 + sectionSpacer
sectionIndex += 1 sectionIndex += 1
...@@ -86,12 +87,12 @@ $(function () { ...@@ -86,12 +87,12 @@ $(function () {
overviewBarX = tickIndex overviewBarX = tickIndex
for section in grade_summary: for section in grade_summary:
weighted_score = section['totalscore']['score'] * section['weight'] weighted_score = section['totalscore'] * section['weight']
summary_text = "{0} - {1:.1%} of a possible {2:.0%}".format(section['category'], weighted_score, section['weight']) summary_text = "{0} - {1:.1%} of a possible {2:.0%}".format(section['category'], weighted_score, section['weight'])
weighted_category_label = section['category'] + " - Weighted" weighted_category_label = section['category'] + " - Weighted"
if section['totalscore']['score'] > 0: if section['totalscore'] > 0:
series.append({ series.append({
'label' : weighted_category_label, 'label' : weighted_category_label,
'data' : [ [overviewBarX, weighted_score] ], 'data' : [ [overviewBarX, weighted_score] ],
...@@ -101,7 +102,7 @@ $(function () { ...@@ -101,7 +102,7 @@ $(function () {
detail_tooltips[weighted_category_label] = [ summary_text ] detail_tooltips[weighted_category_label] = [ summary_text ]
sectionIndex += 1 sectionIndex += 1
totalWeight += section['weight'] totalWeight += section['weight']
totalScore += section['totalscore']['score'] * section['weight'] totalScore += section['totalscore'] * section['weight']
ticks += [ [overviewBarX, "Total"] ] ticks += [ [overviewBarX, "Total"] ]
tickIndex += 1 + sectionSpacer tickIndex += 1 + sectionSpacer
...@@ -128,7 +129,7 @@ $(function () { ...@@ -128,7 +129,7 @@ $(function () {
legend: {show: false}, legend: {show: false},
}; };
var $grade_detail_graph = $("#grade-detail-graph"); var $grade_detail_graph = $("#${graph_div_id}");
if ($grade_detail_graph.length > 0) { if ($grade_detail_graph.length > 0) {
var plot = $.plot($grade_detail_graph, series, options); var plot = $.plot($grade_detail_graph, series, options);
...@@ -137,7 +138,7 @@ $(function () { ...@@ -137,7 +138,7 @@ $(function () {
} }
var previousPoint = null; var previousPoint = null;
$("#grade-detail-graph").bind("plothover", function (event, pos, item) { $grade_detail_graph.bind("plothover", function (event, pos, item) {
$("#x").text(pos.x.toFixed(2)); $("#x").text(pos.x.toFixed(2));
$("#y").text(pos.y.toFixed(2)); $("#y").text(pos.y.toFixed(2));
if (item) { if (item) {
......
...@@ -21,12 +21,12 @@ div.info-wrapper { ...@@ -21,12 +21,12 @@ div.info-wrapper {
@extend .clearfix; @extend .clearfix;
border-bottom: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3;
// &:first-child { &:first-child {
// padding: lh(.5); padding: lh(.5);
// margin-left: (-(lh(.5))); margin: 0 (-(lh(.5))) lh();
// background: $cream; background: $cream;
// border-bottom: 1px solid darken($cream, 10%); border-bottom: 1px solid darken($cream, 10%);
// } }
h2 { h2 {
float: left; float: left;
...@@ -59,39 +59,115 @@ div.info-wrapper { ...@@ -59,39 +59,115 @@ div.info-wrapper {
border-right: 0; border-right: 0;
border-left: 1px solid #d3d3d3; border-left: 1px solid #d3d3d3;
header {
@extend .bottom-border;
padding: lh(.5) lh(.75);
h1 { h1 {
padding: lh(.5) lh();
font-size: 18px; font-size: 18px;
margin: 0 ; margin: 0 ;
@extend .bottom-border; }
p {
margin-bottom: 0;
margin-top: 4px;
font-size: 12px;
color: #666;
}
} }
ol { ol {
list-style: none; list-style: none;
background: none;
li { li {
@include box-shadow(0 1px 0 #eee); @include box-shadow(0 1px 0 #eee);
border-bottom: 1px solid #d3d3d3; border-bottom: 1px solid #d3d3d3;
@include box-sizing(border-box);
@extend .clearfix; @extend .clearfix;
padding: 7px lh(.75);
background: none;
position: relative;
&.expandable,
&.collapsable {
h4 {
padding-left: 18px;
font-style: $body-font-size;
font-weight: normal;
}
}
ul {
background: none;
margin: 7px (-(lh(.75))) 0;
li {
padding-left: 18px + lh(.75);
@include box-shadow(inset 0 1px 0 #eee);
border-top: 1px solid #d3d3d3;
border-bottom: 0;
}
}
&:hover {
background-color: #e9e9e9;
}
div.hitarea {
background-image: url('/static/images/treeview-default.gif');
width: 100%;
height: 100%;
max-height: 20px;
display: block;
position: absolute;
left: lh(.75);
margin-left: 0;
&:hover {
opacity: 0.6;
filter: alpha(opacity=60);
}
&.expandable-hitarea {
background-position: -80px 1px;
}
&.collapsable-hitarea {
background-position: -64px -21px;
}
}
h3 {
border-bottom: 0;
text-transform: uppercase;
font-weight: bold;
color: #999;
@include box-shadow(none);
font-size: 12px;
}
p { p {
padding: 7px lh();
margin: 0; margin: 0;
text-transform: none; text-transform: none;
letter-spacing: 0; letter-spacing: 0;
font-size: $body-font-size; font-size: $body-font-size;
&:hover {
background: #efefef;
}
a { a {
display: inline; padding-right: 8px;
padding: 0;
&:hover { &:before {
text-decoration: underline; content: "•";
background: none; @include inline-block();
padding-right: 8px;
color: #ccc;
}
&:first-child {
&:before {
content: "";
padding-right: 0;
}
} }
} }
} }
...@@ -99,12 +175,11 @@ div.info-wrapper { ...@@ -99,12 +175,11 @@ div.info-wrapper {
a { a {
@include transition(); @include transition();
color: lighten($text-color, 10%); color: lighten($text-color, 10%);
display: block;
padding: 7px lh();
text-decoration: none; text-decoration: none;
@include inline-block();
&:hover { &:hover {
background: #efefef; color: $mit-red;
} }
} }
} }
......
...@@ -8,11 +8,29 @@ div.profile-wrapper { ...@@ -8,11 +8,29 @@ div.profile-wrapper {
border-left: 1px solid #d3d3d3; border-left: 1px solid #d3d3d3;
border-right: 0; border-right: 0;
h1 { header {
padding: lh(.5) lh(); padding: lh(.5) lh();
font-size: 18px;
margin: 0 ; margin: 0 ;
@extend .bottom-border; @extend .bottom-border;
h1 {
font-size: 18px;
margin: 0;
padding-right: 30px;
}
a {
position: absolute;
top: 13px;
right: lh(.5);
text-transform: uppercase;
font-size: 12px;
color: #999;
&:hover {
color: #555;
}
}
} }
ul { ul {
...@@ -57,7 +75,11 @@ div.profile-wrapper { ...@@ -57,7 +75,11 @@ div.profile-wrapper {
font-size: 12px; font-size: 12px;
} }
a#change_language, a#change_location { a#change_language,
a#change_location,
a.edit-email,
a.name-edit,
a.email-edit {
position: absolute; position: absolute;
top: 9px; top: 9px;
right: lh(.5); right: lh(.5);
...@@ -69,20 +91,66 @@ div.profile-wrapper { ...@@ -69,20 +91,66 @@ div.profile-wrapper {
color: #555; color: #555;
} }
} }
p {
font-size: 12px;
margin-bottom: 0;
margin-top: 4px;
color: #999;
}
a.deactivate {
color: #aaa;
font-style: italic;
}
input#pwd_reset_button {
background: none;
border: none;
@include box-shadow(none);
color: #999;
font-size: 12px;
font-weight: normal;
margin: 0;
padding: 0;
position: absolute;
right: lh(.5);
text-transform: uppercase;
top: 9px;
&:hover {
color: #555;
}
}
} }
} }
div#change_password_pop { div#change_password_pop {
padding: 7px lh(); border-bottom: 1px solid #d3d3d3;
@include box-shadow(0 1px 0 #eee);
color: #4D4D4D; color: #4D4D4D;
padding: 7px lh();
h2 {
margin-top: 0;
font-weight: bold;
text-transform: uppercase;
font-size: $body-font-size;
}
} }
} }
section.course-info { section.course-info {
@extend .content; @extend .content;
> h1 { header {
@extend .top-header; @extend h1.top-header;
@extend .clearfix;
h1 {
margin: 0;
float: left;
}
} }
div#grade-detail-graph { div#grade-detail-graph {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
@import "base/reset", "base/font-face"; @import "base/reset", "base/font-face";
@import "base/variables", "base/functions", "base/extends", "base/base"; @import "base/variables", "base/functions", "base/extends", "base/base";
@import "layout/layout", "layout/header", "layout/footer", "layout/calculator", "layout/leanmodal"; @import "layout/layout", "layout/header", "layout/footer", "layout/calculator", "layout/leanmodal";
@import "plugins/jquery-ui-1.8.16.custom"; @import "plugins/jquery-ui-1.8.16.custom", "plugins/jquery.qtip.min";
// pages // pages
@import "courseware/courseware", "courseware/sidebar", "courseware/video", "courseware/sequence-nav", "courseware/amplifier"; @import "courseware/courseware", "courseware/sidebar", "courseware/video", "courseware/sequence-nav", "courseware/amplifier";
......
...@@ -46,6 +46,36 @@ h1.top-header { ...@@ -46,6 +46,36 @@ h1.top-header {
} }
} }
.light-button, a.light-button {
@include box-shadow(inset 0 1px 0 #fff);
@include linear-gradient(#fff, lighten(#888, 40%));
@include border-radius(3px);
border: 1px solid #ccc;
padding: 4px 8px;
color: #666;
font: normal $body-font-size $body-font-family;
text-decoration: none;
cursor: pointer;
-webkit-font-smoothing: antialiased;
&:hover, &:focus {
@include linear-gradient(#fff, lighten(#888, 37%));
border: 1px solid #ccc;
text-decoration: none;
}
}
.action-link {
a {
color: $mit-red;
&:hover {
text-decoration: none;
color: darken($mit-red, 20%);
}
}
}
.content { .content {
@include box-shadow(inset 0 0 2px 3px #f3f3f3); @include box-shadow(inset 0 0 2px 3px #f3f3f3);
@include box-sizing(border-box); @include box-sizing(border-box);
......
@mixin border-image($images) { @mixin border-image ($image) {
-webkit-border-image: border-add-prefix($images, webkit); -webkit-border-image: $image;
-moz-border-image: border-add-prefix($images, moz); -moz-border-image: $image;
-o-border-image: border-add-prefix($images, o); -ms-border-image: $image;
border-image: border-add-prefix($images); -o-border-image: $image;
border-image: $image;
} }
@function border-add-prefix($images, $vendor: false) {
$border-image: ();
$images-type: type-of(nth($images, 1));
$first-var: nth(nth($images, 1), 1); // Get type of Gradient (Linear || radial)
// If input is a gradient
@if $images-type == string {
@if ($first-var == "linear") or ($first-var == "radial") {
@for $i from 2 through length($images) {
$gradient-type: nth($images, 1); // Get type of gradient (linear || radial)
$gradient-args: nth($images, $i); // Get actual gradient (red, blue)
$border-image: render-gradients($gradient-args, $gradient-type, $vendor);
}
}
// If input is a URL
@else {
$border-image: $images;
}
}
// If input is gradient or url + additional args
@else if $images-type == list {
@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)
$border-image: render-gradients($gradient-args, $gradient-type, $vendor);
}
// If variable is a string - Image or number
@else if ($type == string) or ($type == number) {
$border-image: append($border-image, nth($images, $i));
}
}
}
@return $border-image;
}
//Examples:
// @include border-image(url("image.png"));
// @include border-image(url("image.png") 20 stretch);
// @include border-image(linear-gradient(45deg, orange, yellow));
// @include border-image(linear-gradient(45deg, orange, yellow) stretch);
// @include border-image(linear-gradient(45deg, orange, yellow) 20 30 40 50 stretch round);
// @include border-image(radial-gradient(top, cover, orange, yellow, orange));
...@@ -175,6 +175,7 @@ div.course-wrapper { ...@@ -175,6 +175,7 @@ div.course-wrapper {
} }
div.staff_info { div.staff_info {
@include clearfix();
white-space: pre-wrap; white-space: pre-wrap;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
padding-top: lh(); padding-top: lh();
......
nav.sequence-nav { nav.sequence-nav {
@extend .topbar; @extend .topbar;
@include box-sizing(border-box);
margin-bottom: $body-line-height; margin-bottom: $body-line-height;
position: relative;
ol { ol {
display: table-row; border-bottom: 1px solid darken($cream, 20%);
float: left; @include box-sizing(border-box);
width: flex-grid(8,9) + flex-gutter(); display: table;
position: relative; padding-right: flex-grid(1, 9);
width: 100%;
a { a {
@extend .block-link; @extend .block-link;
} }
li { li {
border-left: 1px solid darken($cream, 20%);
display: table-cell; display: table-cell;
min-width: 20px;
&:first-child {
border-left: none;
}
.inactive { .inactive {
background-repeat: no-repeat; background-repeat: no-repeat;
...@@ -35,9 +44,9 @@ nav.sequence-nav { ...@@ -35,9 +44,9 @@ nav.sequence-nav {
} }
.active { .active {
@include box-shadow(0 1px 0 #fff);
background-color: #fff; background-color: #fff;
background-repeat: no-repeat; background-repeat: no-repeat;
@include box-shadow(0 1px 0 #fff);
&:hover { &:hover {
background-color: #fff; background-color: #fff;
...@@ -46,15 +55,14 @@ nav.sequence-nav { ...@@ -46,15 +55,14 @@ nav.sequence-nav {
} }
a { a {
@include box-shadow(1px 0 0 #fff);
background-position: center center; background-position: center center;
border: none; border: none;
border-right: 1px solid darken($cream, 10%);
cursor: pointer; cursor: pointer;
padding: 15px 4px 14px; display: block;
width: 28px;
height: 17px; height: 17px;
padding: 15px 0 14px;
@include transition(all, .4s, $ease-in-out-quad); @include transition(all, .4s, $ease-in-out-quad);
width: 100%;
// @media screen and (max-width: 800px) { // @media screen and (max-width: 800px) {
// padding: 12px 8px; // padding: 12px 8px;
...@@ -134,8 +142,8 @@ nav.sequence-nav { ...@@ -134,8 +142,8 @@ nav.sequence-nav {
z-index: 99; z-index: 99;
&.shown { &.shown {
opacity: 1;
margin-top: 4px; margin-top: 4px;
opacity: 1;
} }
&:empty { &:empty {
...@@ -151,9 +159,9 @@ nav.sequence-nav { ...@@ -151,9 +159,9 @@ nav.sequence-nav {
content: " "; content: " ";
display: block; display: block;
height: 10px; height: 10px;
left: 18px;
position: absolute; position: absolute;
top: -5px; top: -5px;
left: 18px;
@include transform(rotate(45deg)); @include transform(rotate(45deg));
width: 10px; width: 10px;
} }
...@@ -162,33 +170,34 @@ nav.sequence-nav { ...@@ -162,33 +170,34 @@ nav.sequence-nav {
} }
ul { ul {
float: right;
margin-right: 1px; margin-right: 1px;
position: absolute;
right: 0;
top: 0;
width: flex-grid(1, 9); width: flex-grid(1, 9);
display: table-row;
li { li {
display: table-cell; float: left;
width: 50%;
&.prev, &.next { &.prev, &.next {
a { a {
@include box-shadow(inset 1px 0 0 lighten(#f6efd4, 5%));
background-color: darken($cream, 5%); background-color: darken($cream, 5%);
background-position: center center; background-position: center center;
background-repeat: no-repeat; background-repeat: no-repeat;
border-left: 1px solid darken(#f6efd4, 20%); border-left: 1px solid darken(#f6efd4, 20%);
@include box-shadow(inset 1px 0 0 lighten(#f6efd4, 5%));
@include box-sizing(border-box);
cursor: pointer; cursor: pointer;
padding: 0 4px;
text-indent: -9999px;
width: 38px;
display: block; display: block;
text-indent: -9999px;
&:hover { &:hover {
text-decoration: none; background-color: none;
color: darken($cream, 60%); color: darken($cream, 60%);
text-decoration: none; text-decoration: none;
background-color: none; text-decoration: none;
} }
&.disabled { &.disabled {
...@@ -223,28 +232,26 @@ nav.sequence-nav { ...@@ -223,28 +232,26 @@ nav.sequence-nav {
section.course-content { section.course-content {
position: relative;
div#seq_content { div#seq_content {
margin-bottom: 60px; margin-bottom: 60px;
} }
nav.sequence-bottom { nav.sequence-bottom {
position: absolute; bottom: (-(lh()));
bottom: 0; position: relative;
right: 50%;
margin-right: -53px;
ul { ul {
@extend .clearfix; @extend .clearfix;
background-color: darken(#F6EFD4, 5%); background-color: darken(#F6EFD4, 5%);
background-color: darken($cream, 5%);
border: 1px solid darken(#f6efd4, 20%); border: 1px solid darken(#f6efd4, 20%);
border-bottom: 0; border-bottom: 0;
@include border-radius(3px 3px 0 0); @include border-radius(3px 3px 0 0);
@include box-shadow(inset 0 0 0 1px lighten(#f6efd4, 5%));
margin: 0 auto;
overflow: hidden; overflow: hidden;
width: 106px; width: 106px;
background-color: darken($cream, 5%);
@include box-shadow(inset 0 0 0 1px lighten(#f6efd4, 5%));
li { li {
float: left; float: left;
...@@ -257,11 +264,11 @@ section.course-content { ...@@ -257,11 +264,11 @@ section.course-content {
background-repeat: no-repeat; background-repeat: no-repeat;
border-bottom: none; border-bottom: none;
display: block; display: block;
display: block;
padding: lh(.75) 4px; padding: lh(.75) 4px;
text-indent: -9999px; text-indent: -9999px;
width: 45px;
display: block;
@include transition(all, .4s, $ease-in-out-quad); @include transition(all, .4s, $ease-in-out-quad);
width: 45px;
&:hover { &:hover {
background-color: darken($cream, 10%); background-color: darken($cream, 10%);
......
section.course-content { section.course-content {
div.video-subtitles { div.video-subtitles {
padding: 6px lh();
margin: 0 (-(lh()));
border-top: 1px solid #e1e1e1;
border-bottom: 1px solid #e1e1e1;
background: #f3f3f3;
position: relative; position: relative;
@include clearfix();
div.video-wrapper { div.video-wrapper {
float: left; float: left;
...@@ -56,6 +62,7 @@ section.course-content { ...@@ -56,6 +62,7 @@ section.course-content {
background: #333; background: #333;
position: relative; position: relative;
border: 1px solid #000; border: 1px solid #000;
border-top: 0;
color: #ccc; color: #ccc;
div#slider { div#slider {
...@@ -64,25 +71,77 @@ section.course-content { ...@@ -64,25 +71,77 @@ section.course-content {
@include box-shadow(inset 0 1px 0 #eee, 0 1px 0 #555); @include box-shadow(inset 0 1px 0 #eee, 0 1px 0 #555);
background: #c2c2c2; background: #c2c2c2;
border: none; border: none;
border-top: 1px solid #000;
border-bottom: 1px solid #000; border-bottom: 1px solid #000;
height: 14px; height: 7px;
@include transition(height 2.0s ease-in-out);
div.ui-widget-header {
background: #777;
@include box-shadow(inset 0 1px 0 #999);
}
.ui-tooltip.qtip .ui-tooltip-content {
background: $mit-red;
border: 1px solid darken($mit-red, 20%);
@include border-radius(2px);
@include box-shadow(inset 0 1px 0 lighten($mit-red, 10%));
color: #fff;
font: bold 12px $body-font-family;
margin-bottom: 6px;
padding: 4px;
text-align: center;
-webkit-font-smoothing: antialiased;
text-shadow: 0 -1px 0 darken($mit-red, 10%);
overflow: visible;
&::after {
content: " ";
width: 7px;
height: 7px;
display: block;
position: absolute;
bottom: -5px;
left: 50%;
margin-left: -3px;
@include transform(rotate(45deg));
background: $mit-red;
border-right: 1px solid darken($mit-red, 20%);
border-bottom: 1px solid darken($mit-red, 20%);
}
}
a.ui-slider-handle { a.ui-slider-handle {
@include border-radius(20px); @include border-radius(15px);
@include box-shadow(inset 0 1px 0 lighten($mit-red, 10%)); @include box-shadow(inset 0 1px 0 lighten($mit-red, 10%));
background: $mit-red url(/static/images/slider-handle.png) center center no-repeat; background: $mit-red url(/static/images/slider-handle.png) center center no-repeat;
border: 1px solid darken($mit-red, 20%); border: 1px solid darken($mit-red, 20%);
cursor: pointer; cursor: pointer;
height: 20px; height: 15px;
margin-left: -10px; margin-left: -7px;
top: -4px; top: -4px;
width: 20px; width: 15px;
@include transition(height 2.0s ease-in-out, width 2.0s ease-in-out);
@include background-size(50%);
&:focus, &:hover { &:focus, &:hover {
background-color: lighten($mit-red, 10%); background-color: lighten($mit-red, 10%);
outline: none; outline: none;
} }
} }
&:hover {
height: 14px;
margin-top: -7px;
a.ui-slider-handle {
@include border-radius(20px);
height: 20px;
margin-left: -10px;
top: -4px;
width: 20px;
}
}
} }
ul.vcr { ul.vcr {
...@@ -100,9 +159,10 @@ section.course-content { ...@@ -100,9 +159,10 @@ section.course-content {
display: block; display: block;
cursor: pointer; cursor: pointer;
height: 14px; height: 14px;
padding: lh(.75) lh(); padding: lh(.75);
text-indent: -9999px; text-indent: -9999px;
width: 14px; width: 14px;
@include transition();
&.play { &.play {
background: url('/static/images/play-icon.png') center center no-repeat; background: url('/static/images/play-icon.png') center center no-repeat;
...@@ -123,7 +183,7 @@ section.course-content { ...@@ -123,7 +183,7 @@ section.course-content {
} }
div#vidtime { div#vidtime {
padding-left: lh(); padding-left: lh(.75);
font-weight: bold; font-weight: bold;
line-height: 46px; //height of play pause buttons line-height: 46px; //height of play pause buttons
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
...@@ -135,38 +195,68 @@ section.course-content { ...@@ -135,38 +195,68 @@ section.course-content {
float: right; float: right;
div.speeds { div.speeds {
border-right: 1px solid #000;
border-left: 1px solid #000; border-left: 1px solid #000;
border-right: 1px solid #000;
@include box-shadow(1px 0 0 #555, inset 1px 0 0 #555); @include box-shadow(1px 0 0 #555, inset 1px 0 0 #555);
float: left; float: left;
line-height: 46px; //height of play pause buttons line-height: 46px; //height of play pause buttons
margin-right: 0; margin-right: 0;
-webkit-font-smoothing: antialiased; position: relative;
opacity: .7;
@include transition(); @include transition();
width: 110px;
cursor: pointer;
-webkit-font-smoothing: antialiased;
h3 { h3 {
@include inline-block(); @include inline-block();
padding: 0 lh(.5); padding: 0 lh(.25) 0 lh(.5);
font-weight: normal; font-weight: normal;
text-transform: uppercase;
font-size: 12px;
letter-spacing: 1px;
color: #999;
}
p.active {
@include inline-block();
padding: 0 lh(.5) 0 0;
margin-bottom: 0;
font-weight: bold;
} }
// fix for now // fix for now
ol#video_speeds { ol#video_speeds {
background-color: #444;
border: 1px solid #000;
border-top: 0;
@include box-shadow(inset 1px 0 0 #555);
@include inline-block(); @include inline-block();
padding-right: lh(.5); left: -1px;
position: absolute;
top: 48px;
width: 100%;
z-index: 10;
li { li {
cursor: pointer; border-bottom: 1px solid #000;
@include box-shadow( 0 1px 0 #555);
color: #fff; color: #fff;
@include inline-block(); cursor: pointer;
padding: 0 lh(.5);
&.active { &.active {
font-weight: bold; font-weight: bold;
} }
&:last-child {
border-bottom: 0;
margin-top: 0;
@include box-shadow(none);
}
&:hover { &:hover {
color: #aaa; color: #aaa;
background-color: #666;
} }
} }
} }
...@@ -180,20 +270,52 @@ section.course-content { ...@@ -180,20 +270,52 @@ section.course-content {
a.hide-subtitles { a.hide-subtitles {
float: left; float: left;
display: block; display: block;
padding-right: lh(.5); padding: 0 lh(.5);
margin-left: 0; margin-left: 0;
color: #797979; color: #797979;
padding-left: 50px;
line-height: 46px; //height of play pause buttons line-height: 46px; //height of play pause buttons
width: 30px;
text-indent: -9999px;
font-weight: 800; font-weight: 800;
background: url('/static/images/cc.png') 16px center no-repeat; background: url('/static/images/cc.png') center no-repeat;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@include transition(); @include transition();
opacity: 1;
position: relative;
&:after {
text-indent: 0;
position: absolute;
top: 0;
right: -40px;
content: "turn off";
display: block;
width: 70px;
opacity: 0;
visibility: hidden;
@include transition();
}
&:hover { &:hover {
color: #fff; color: #fff;
text-decoration: none; text-decoration: none;
background-color: #444; background-color: #444;
padding-right: 80px;
background-position: 11px center;
&:after {
right: 0;
opacity: 1;
visibility: visible;
}
}
&.off {
opacity: .7;
&:after {
content: "turn on";
}
} }
} }
} }
...@@ -203,19 +325,21 @@ section.course-content { ...@@ -203,19 +325,21 @@ section.course-content {
ol.subtitles { ol.subtitles {
float: left; float: left;
width: flex-grid(3, 9); width: flex-grid(3, 9);
height: 530px; padding-top: 10px;
max-height: 460px;
overflow: hidden; overflow: hidden;
li { li {
margin-bottom: 0px;
cursor: pointer;
border: 0; border: 0;
padding: 0;
color: #666; color: #666;
cursor: pointer;
margin-bottom: 0px;
padding: 0;
@include transition(all, .5s, ease-in);
&.current { &.current {
background-color: #f3f3f3;
color: #333; color: #333;
font-weight: 700;
} }
&:hover { &:hover {
...@@ -246,3 +370,9 @@ section.course-content { ...@@ -246,3 +370,9 @@ section.course-content {
} }
} }
} }
div.course-wrapper.closed section.course-content div.video-subtitles {
ol.subtitles {
max-height: 577px;
}
}
// Base extends (Merge with main stylesheet later)
.light-button, a.light-button {
@include box-shadow(inset 0 1px 0 #fff);
@include linear-gradient(#fff, lighten(#888, 40%));
@include border-radius(3px);
border: 1px solid #ccc;
padding: 4px 8px;
color: #666;
font: normal $body-font-size $body-font-family;
text-decoration: none;
cursor: pointer;
-webkit-font-smoothing: antialiased;
&:hover, &:focus {
@include linear-gradient(#fff, lighten(#888, 37%));
border: 1px solid #ccc;
text-decoration: none;
}
}
.action-link {
a {
color: $mit-red;
&:hover {
text-decoration: none;
color: darken($mit-red, 20%);
}
}
}
// Layout // Layout
body.askbot { body.askbot {
......
...@@ -105,8 +105,8 @@ ul.question-list, div#question-list { ...@@ -105,8 +105,8 @@ ul.question-list, div#question-list {
li.single-question { li.single-question {
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
list-style: none; list-style: none;
padding: 10px 3%; padding: 10px lh();
margin-left: -3%; margin-left: (-(lh()));
width: 100%; width: 100%;
&:hover { &:hover {
......
...@@ -288,6 +288,7 @@ div.discussion-wrapper aside { ...@@ -288,6 +288,7 @@ div.discussion-wrapper aside {
border-top: 0; border-top: 0;
@include box-shadow(none); @include box-shadow(none);
} }
a { a {
width: 100%; width: 100%;
@include box-sizing(border-box); @include box-sizing(border-box);
...@@ -295,6 +296,7 @@ div.discussion-wrapper aside { ...@@ -295,6 +296,7 @@ div.discussion-wrapper aside {
padding: 10px; padding: 10px;
display: block; display: block;
margin-top: 10px; margin-top: 10px;
@extend .light-button;
&:first-child { &:first-child {
margin-top: 0; margin-top: 0;
......
li.calc-main { li.calc-main {
bottom: 0; bottom: -36px;
left: 0; left: 0;
position: fixed; position: fixed;
width: 100%; width: 100%;
...@@ -16,6 +16,8 @@ li.calc-main { ...@@ -16,6 +16,8 @@ li.calc-main {
padding: 8px 12px; padding: 8px 12px;
width: 16px; width: 16px;
height: 20px; height: 20px;
position: relative;
top: -36px;
&:hover { &:hover {
opacity: .8; opacity: .8;
...@@ -28,6 +30,8 @@ li.calc-main { ...@@ -28,6 +30,8 @@ li.calc-main {
div#calculator_wrapper { div#calculator_wrapper {
background: rgba(#111, .9); background: rgba(#111, .9);
position: relative;
top: -36px;
clear: both; clear: both;
form { form {
......
...@@ -17,7 +17,7 @@ html { ...@@ -17,7 +17,7 @@ html {
@include box-shadow(0 0 4px #dfdfdf); @include box-shadow(0 0 4px #dfdfdf);
@include box-sizing(border-box); @include box-sizing(border-box);
margin-top: 3px; margin-top: 3px;
overflow: hidden; // overflow: hidden;
@media print { @media print {
border-bottom: 0; border-bottom: 0;
......
...@@ -17,6 +17,7 @@ div.leanModal_box { ...@@ -17,6 +17,7 @@ div.leanModal_box {
@include box-sizing(border-box); @include box-sizing(border-box);
display: none; display: none;
padding: lh(2); padding: lh(2);
text-align: left;
a.modal_close { a.modal_close {
color: #aaa; color: #aaa;
...@@ -204,6 +205,35 @@ div#pwd_reset { ...@@ -204,6 +205,35 @@ div#pwd_reset {
} }
} }
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} {
display: block;
width: 100%;
@include box-sizing(border-box);
}
textarea {
height: 60px;
}
input[type="submit"] {
white-space: normal;
}
}
}
}
div#feedback_div{ div#feedback_div{
form{ form{
ol { ol {
......
.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;}.ui-tooltip-fluid{display:block;visibility:hidden;position:static!important;float:left!important;}.ui-tooltip-content{position:relative;padding:5px 9px;overflow:hidden;border:1px solid #000001;text-align:left;word-wrap:break-word;overflow:hidden;}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border:1px solid #000001;border-width:1px 1px 0;font-weight:bold;}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0!important;}/*!Default close button class */ .ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;}* html .ui-tooltip-titlebar .ui-state-default{top:16px;}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em;}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em;}/*!Default tooltip style */ .ui-tooltip-default .ui-tooltip-titlebar,.ui-tooltip-default .ui-tooltip-content{border-color:#F1D031;background-color:#FFFFA3;color:#555;}.ui-tooltip-default .ui-tooltip-titlebar{background-color:#FFEF93;}.ui-tooltip-default .ui-tooltip-icon{border-color:#CCC;background:#F1F1F1;color:#777;}.ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111;}
\ No newline at end of file
<section class="text-input"> <section class="text-input">
<input type="text" name="input_${id}" id="input_${id}" value="${value}" /> <input type="text" name="input_${id}" id="input_${id}" value="${value}"
% if size:
size="${size}"
% endif
/>
<span id="answer_${id}"></span> <span id="answer_${id}"></span>
......
...@@ -29,10 +29,11 @@ ...@@ -29,10 +29,11 @@
<div class="secondary-controls"> <div class="secondary-controls">
<div class="speeds"> <div class="speeds">
<h3>Speed</h3> <h3>Speed</h3>
<p class="active"></p>
<ol id="video_speeds"></ol> <ol id="video_speeds"></ol>
</div> </div>
<a href="#" class="hide-subtitles">turn off</a> <a href="#" class="hide-subtitles">Captions</a>
</div> </div>
</section> </section>
</section> </section>
...@@ -54,7 +55,7 @@ ...@@ -54,7 +55,7 @@
<li id="stt_p5"><div id="std_p5" onclick="title_seek( 5);"></div></li> <li id="stt_p5"><div id="std_p5" onclick="title_seek( 5);"></div></li>
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 6);"></div></li> <li id="stt_p6"><div id="std_p7" onclick="title_seek( 6);"></div></li>
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 7);"></div></li> <li id="stt_p6"><div id="std_p7" onclick="title_seek( 7);"></div></li>
<!-- <li id="stt_p6"><div id="std_p7" onclick="title_seek( 8);"></div></li> --> <li id="stt_p6"><div id="std_p7" onclick="title_seek( 8);"></div></li>
</ol> </ol>
</div> </div>
...@@ -65,10 +66,15 @@ ...@@ -65,10 +66,15 @@
$('.hide-subtitles').click(function() { $('.hide-subtitles').click(function() {
$('div.video-subtitles').toggleClass('closed'); $('div.video-subtitles').toggleClass('closed');
var link_text = $('.hide-subtitles').text(); $(this).toggleClass("off");
$(this).text((link_text == 'turn off') ? 'turn on' : 'turn off');
return false; return false;
}); });
$("ol#video_speeds").hide();
$("div.speeds").click(function() {
$("ol#video_speeds").slideToggle(150);
});
}); });
</script> </script>
</%block> </%block>
...@@ -20,9 +20,47 @@ if (swfobject.hasFlashPlayerVersion("10.1")){ ...@@ -20,9 +20,47 @@ if (swfobject.hasFlashPlayerVersion("10.1")){
// Make sure the callback is called once API ready, YT seems to be buggy // Make sure the callback is called once API ready, YT seems to be buggy
loadHTML5Video(); loadHTML5Video();
} }
var captions=0; var captions=0;
$("#slider").slider({slide:function(event,ui){seek_slide('slide',event.originalEvent,ui.value);},
stop:function(event,ui){seek_slide('stop',event.originalEvent,ui.value);}}); /* Cache a reference to our slider element */
var slider = $('#slider')
.slider({
range: "min",
slide: function(event,ui) {
var slider_time = format_time(ui.value)
seek_slide('slide',event.originalEvent,ui.value);
handle.qtip('option', 'content.text', '' + slider_time);
},
stop:function(event,ui){seek_slide('stop',event.originalEvent,ui.value);}
}),
/* Grab and cache the newly created slider handle */
handle = $('.ui-slider-handle', slider);
/*
* Selector needs changing here to match your elements.
*
* Notice the second argument to the $() constructor, which tells
* jQuery to use that as the top-level element to seareh down from.
*/
handle.qtip({
content: '' + slider.slider('option', 'value'), // Use the current value of the slider
position: {
my: 'bottom center',
at: 'top center',
container: handle // Stick it inside the handle element so it keeps the position synched up
},
hide: {
delay: 700 // Give it a longer delay so it doesn't hide frequently as we move the handle
},
style: {
classes: 'ui-tooltip-slider',
widget: true // Make it Themeroller compatible
}
});
function good() { function good() {
window['console'].log(ytplayer.getCurrentTime()); window['console'].log(ytplayer.getCurrentTime());
...@@ -37,7 +75,8 @@ function add_speed(key, stream) { ...@@ -37,7 +75,8 @@ function add_speed(key, stream) {
var id = 'speed_' + stream; var id = 'speed_' + stream;
if (key == video_speed) { if (key == video_speed) {
$("#video_speeds").append(' <li class=active id="'+id+'">'+key+'x</li>'); $("#video_speeds").append(' <li class="active" id="'+id+'">'+key+'x</li>');
$("p.active").text(key + 'x');
} else { } else {
$("#video_speeds").append(' <li id="'+id+'">'+key+'x</li>'); $("#video_speeds").append(' <li id="'+id+'">'+key+'x</li>');
} }
...@@ -46,6 +85,8 @@ function add_speed(key, stream) { ...@@ -46,6 +85,8 @@ function add_speed(key, stream) {
change_video_speed(key, stream); change_video_speed(key, stream);
$(this).siblings().removeClass("active"); $(this).siblings().removeClass("active");
$(this).addClass("active"); $(this).addClass("active");
var active = $(this).text();
$("p.active").text(active);
}); });
} }
...@@ -89,8 +130,6 @@ $(document).ready(function() { ...@@ -89,8 +130,6 @@ $(document).ready(function() {
}); });
function toggleVideo(){ function toggleVideo(){
if ($("#video_control").hasClass("play")){ if ($("#video_control").hasClass("play")){
play(); play();
......
...@@ -8,19 +8,25 @@ import django.contrib.auth.views ...@@ -8,19 +8,25 @@ import django.contrib.auth.views
# admin.autodiscover() # admin.autodiscover()
urlpatterns = ('', urlpatterns = ('',
url(r'^$', 'student.views.index'), # Main marketing page, or redirect to courseware
url(r'^change_email$', 'student.views.change_email_request'),
url(r'^email_confirm/(?P<key>[^/]*)$', 'student.views.confirm_email_change'),
url(r'^change_name$', 'student.views.change_name_request'),
url(r'^accept_name_change$', 'student.views.accept_name_change'),
url(r'^reject_name_change$', 'student.views.reject_name_change'),
url(r'^pending_name_changes$', 'student.views.pending_name_changes'),
url(r'^gradebook$', 'courseware.views.gradebook'), url(r'^gradebook$', 'courseware.views.gradebook'),
url(r'^event$', 'track.views.user_track'), url(r'^event$', 'track.views.user_track'),
url(r'^t/(?P<template>[^/]*)$', 'static_template_view.views.index'), url(r'^t/(?P<template>[^/]*)$', 'static_template_view.views.index'),
url(r'^logout$', 'student.views.logout_user'),
url(r'^info$', 'util.views.info'),
url(r'^login$', 'student.views.login_user'), url(r'^login$', 'student.views.login_user'),
url(r'^login/(?P<error>[^/]*)$', 'student.views.login_user'), url(r'^login/(?P<error>[^/]*)$', 'student.views.login_user'),
url(r'^logout$', 'student.views.logout_user'),
url(r'^create_account$', 'student.views.create_account'), url(r'^create_account$', 'student.views.create_account'),
url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account'), url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account'),
url(r'^$', 'student.views.index'), # url(r'^reactivate/(?P<key>[^/]*)$', 'student.views.reactivation_email'),
# url(r'^password_reset/$', 'django.contrib.auth.views.password_reset',
# dict(from_email='registration@mitx.mit.edu'),name='auth_password_reset'),
url(r'^password_reset/$', 'student.views.password_reset'), url(r'^password_reset/$', 'student.views.password_reset'),
## Obsolete Django views for password resets
## TODO: Replace with Mako-ized views
url(r'^password_change/$',django.contrib.auth.views.password_change,name='auth_password_change'), url(r'^password_change/$',django.contrib.auth.views.password_change,name='auth_password_change'),
url(r'^password_change_done/$',django.contrib.auth.views.password_change_done,name='auth_password_change_done'), url(r'^password_change_done/$',django.contrib.auth.views.password_change_done,name='auth_password_change_done'),
url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',django.contrib.auth.views.password_reset_confirm, url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',django.contrib.auth.views.password_reset_confirm,
...@@ -29,6 +35,7 @@ urlpatterns = ('', ...@@ -29,6 +35,7 @@ urlpatterns = ('',
name='auth_password_reset_complete'), name='auth_password_reset_complete'),
url(r'^password_reset_done/$',django.contrib.auth.views.password_reset_done, url(r'^password_reset_done/$',django.contrib.auth.views.password_reset_done,
name='auth_password_reset_done'), name='auth_password_reset_done'),
## Feedback
url(r'^send_feedback$', 'util.views.send_feedback'), url(r'^send_feedback$', 'util.views.send_feedback'),
) )
...@@ -37,6 +44,7 @@ if settings.PERFSTATS: ...@@ -37,6 +44,7 @@ if settings.PERFSTATS:
if settings.COURSEWARE_ENABLED: if settings.COURSEWARE_ENABLED:
urlpatterns=urlpatterns + (url(r'^courseware/$', 'courseware.views.index', name="courseware"), urlpatterns=urlpatterns + (url(r'^courseware/$', 'courseware.views.index', name="courseware"),
url(r'^info$', 'util.views.info'),
url(r'^wiki/', include('simplewiki.urls')), url(r'^wiki/', include('simplewiki.urls')),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"), 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>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index', name="courseware_chapter"),
......
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