Merge branch 'master' into pmitros/name-change
Conflicts: static/css/application.css static/css/marketing.css
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,3 +9,5 @@ courseware/static/js/mathjax/*
|
||||
db.newaskbot
|
||||
db.oldaskbot
|
||||
flushdb.sh
|
||||
build
|
||||
\#*\#
|
||||
29
ci/build.sh
29
ci/build.sh
@@ -1,29 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
#sass sass:static/css -r templates/sass/bourbon/lib/bourbon.rb --style :compressed
|
||||
|
||||
if [ -z "${GIT_COMMIT}" ]; then
|
||||
GIT_COMMIT=$(git rev-parse HEAD)
|
||||
fi
|
||||
|
||||
if [ -z "${GIT_BRANCH}" ]; then
|
||||
GIT_BRANCH=$(git symbolic-ref -q HEAD)
|
||||
GIT_BRANCH=${GIT_BRANCH##refs/heads/}
|
||||
GIT_BRANCH=${GIT_BRANCH:-HEAD}
|
||||
fi
|
||||
GIT_BRANCH=${GIT_BRANCH##origin/}
|
||||
GIT_BRANCH=${GIT_BRANCH//\//_}
|
||||
|
||||
if [ -z "${BUILD_NUMBER}" ]; then
|
||||
BUILD_NUMBER=dev
|
||||
fi
|
||||
|
||||
ID=mitx-${GIT_BRANCH}-${BUILD_NUMBER}-${GIT_COMMIT}
|
||||
REPO_ROOT=$(dirname $0)/..
|
||||
BUILD_DIR=${REPO_ROOT}/build
|
||||
|
||||
mkdir -p ${BUILD_DIR}
|
||||
tar --exclude=.git --exclude=build --transform="s#^#mitx/#" -czf ${BUILD_DIR}/${ID}.tgz ${REPO_ROOT}
|
||||
@@ -5,6 +5,7 @@ import operator
|
||||
import re
|
||||
|
||||
import numpy
|
||||
import numbers
|
||||
import scipy.constants
|
||||
|
||||
from pyparsing import Word, alphas, nums, oneOf, Literal
|
||||
@@ -121,7 +122,7 @@ def evaluator(variables, functions, string, cs=False):
|
||||
def number_parse_action(x): # [ '7' ] -> [ 7 ]
|
||||
return [super_float("".join(x))]
|
||||
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=reduce(lambda a,b:b**a, x)
|
||||
return x
|
||||
@@ -130,7 +131,7 @@ def evaluator(variables, functions, string, cs=False):
|
||||
return x[0]
|
||||
if 0 in x:
|
||||
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)
|
||||
def sum_parse_action(x): # [ 1 + 2 - 3 ] -> 0
|
||||
total = 0.0
|
||||
@@ -217,4 +218,7 @@ if __name__=='__main__':
|
||||
print evaluator({},{}, "-(7+5)")
|
||||
print evaluator({},{}, "-0.33")
|
||||
print evaluator({},{}, "-.33")
|
||||
print evaluator({},{}, "5+1*j")
|
||||
print evaluator({},{}, "j||1")
|
||||
print evaluator({},{}, "e^(j*pi)")
|
||||
print evaluator({},{}, "5+7 QWSEKO")
|
||||
|
||||
@@ -8,7 +8,8 @@ class textline(object):
|
||||
def render(element, value, state):
|
||||
eid=element.get('id')
|
||||
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)
|
||||
return etree.XML(html)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import math
|
||||
import numbers
|
||||
import numpy
|
||||
import random
|
||||
import scipy
|
||||
@@ -37,7 +38,7 @@ class numericalresponse(object):
|
||||
def __init__(self, xml, context):
|
||||
self.xml = xml
|
||||
self.correct_answer = contextualize_text(xml.get('answer'), context)
|
||||
self.correct_answer = float(self.correct_answer)
|
||||
self.correct_answer = complex(self.correct_answer)
|
||||
self.tolerance_xml = xml.xpath('//*[@id=$id]//responseparam[@type="tolerance"]/@default',
|
||||
id=xml.get('id'))[0]
|
||||
self.tolerance = contextualize_text(self.tolerance_xml, context)
|
||||
@@ -49,7 +50,10 @@ class numericalresponse(object):
|
||||
student_answer = student_answers[self.answer_id]
|
||||
try:
|
||||
correct = compare_with_tolerance (evaluator(dict(),dict(),student_answer), self.correct_answer, self.tolerance)
|
||||
except:
|
||||
# We should catch this explicitly.
|
||||
# I think this is just pyparsing.ParseException, calc.UndefinedVariable:
|
||||
# But we'd need to confirm
|
||||
except:
|
||||
raise StudentInputError('Invalid input -- please use a number only')
|
||||
|
||||
if correct:
|
||||
@@ -141,7 +145,7 @@ class formularesponse(object):
|
||||
except:
|
||||
#traceback.print_exc()
|
||||
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"}
|
||||
if not compare_with_tolerance(student_result, instructor_result, self.tolerance):
|
||||
return {self.answer_id:"incorrect"}
|
||||
@@ -153,9 +157,9 @@ class formularesponse(object):
|
||||
keys and all non-numeric values stripped out. All values also
|
||||
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 \
|
||||
(type(d[k]) == float or type(d[k]) == int) ])
|
||||
isinstance(d[k], numbers.Number)])
|
||||
return d
|
||||
|
||||
def get_answers(self):
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import logging
|
||||
import urllib
|
||||
from lxml import etree
|
||||
|
||||
import courseware.content_parser as content_parser
|
||||
from models import StudentModule
|
||||
from django.conf import settings
|
||||
import courseware.modules
|
||||
import logging
|
||||
import random
|
||||
import urllib
|
||||
|
||||
from collections import namedtuple
|
||||
from django.conf import settings
|
||||
from lxml import etree
|
||||
from models import StudentModule
|
||||
from student.models import UserProfile
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
Score = namedtuple("Score", "earned possible graded section")
|
||||
|
||||
def get_grade(user, problem, cache):
|
||||
## HACK: assumes max score is fixed per problem
|
||||
id = problem.get('id')
|
||||
correct = 0
|
||||
|
||||
# If the ID is not in the cache, add the item
|
||||
if id not in cache:
|
||||
if id not in cache:
|
||||
module = StudentModule(module_type = 'problem', # TODO: Move into StudentModule.__init__?
|
||||
module_id = id,
|
||||
student = user,
|
||||
@@ -44,6 +47,17 @@ def get_grade(user, problem, cache):
|
||||
return (correct, total)
|
||||
|
||||
def grade_sheet(student):
|
||||
"""
|
||||
This pulls a summary of all problems in the course. It returns a dictionary with two datastructures:
|
||||
|
||||
- courseware_summary is a summary of all sections with problems in the course. It is organized as an array of chapters,
|
||||
each containing an array of sections, each containing an array of scores. This contains information for graded and ungraded
|
||||
problems, and is good for displaying a course summary with due dates, etc.
|
||||
|
||||
- grade_summary is a summary of how the final grade breaks down. It is an array of "sections". Each section can either be
|
||||
a conglomerate of scores (like labs or homeworks) which has subscores and a totalscore, or a section can be all from one assignment
|
||||
(such as a midterm or final) and only has a totalscore. Each section has a weight that shows how it contributes to the total grade.
|
||||
"""
|
||||
dom=content_parser.course_file(student)
|
||||
course = dom.xpath('//course/@name')[0]
|
||||
xmlChapters = dom.xpath('//course[@name=$course]/chapter', course=course)
|
||||
@@ -54,11 +68,14 @@ def grade_sheet(student):
|
||||
response_by_id[response.module_id] = response
|
||||
|
||||
|
||||
total_scores = {}
|
||||
|
||||
totaled_scores = {}
|
||||
chapters=[]
|
||||
for c in xmlChapters:
|
||||
sections = []
|
||||
chname=c.get('name')
|
||||
|
||||
|
||||
for s in dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section',
|
||||
course=course, chname=chname):
|
||||
problems=dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section[@name=$section]//problem',
|
||||
@@ -84,22 +101,26 @@ def grade_sheet(student):
|
||||
else:
|
||||
correct = total
|
||||
|
||||
scores.append((int(correct),total, graded ))
|
||||
scores.append( Score(int(correct),total, graded, s.get("name")) )
|
||||
|
||||
|
||||
section_total = Score(sum([score.earned for score in scores]),
|
||||
sum([score.possible for score in scores]),
|
||||
False,
|
||||
p.get("id"))
|
||||
|
||||
section_total = (sum([score[0] for score in scores]),
|
||||
sum([score[1] for score in scores]))
|
||||
graded_total = Score(sum([score.earned for score in scores if score.graded]),
|
||||
sum([score.possible for score in scores if score.graded]),
|
||||
True,
|
||||
p.get("id"))
|
||||
|
||||
graded_total = (sum([score[0] for score in scores if score[2]]),
|
||||
sum([score[1] for score in scores if score[2]]))
|
||||
|
||||
#Add the graded total to total_scores
|
||||
#Add the graded total to totaled_scores
|
||||
format = s.get('format') if s.get('format') else ""
|
||||
subtitle = s.get('subtitle') if s.get('subtitle') else format
|
||||
if format and graded_total[1] > 0:
|
||||
format_scores = total_scores[ format ] if format in total_scores else []
|
||||
format_scores.append( graded_total + (s.get("name"),) )
|
||||
total_scores[ format ] = format_scores
|
||||
format_scores = totaled_scores.get(format, [])
|
||||
format_scores.append( graded_total )
|
||||
totaled_scores[ format ] = format_scores
|
||||
|
||||
score={'section':s.get("name"),
|
||||
'scores':scores,
|
||||
@@ -114,7 +135,20 @@ def grade_sheet(student):
|
||||
chapters.append({'course':course,
|
||||
'chapter' : c.get("name"),
|
||||
'sections' : sections,})
|
||||
|
||||
|
||||
|
||||
grade_summary = grade_summary_6002x(totaled_scores)
|
||||
|
||||
return {'courseware_summary' : chapters,
|
||||
'grade_summary' : grade_summary}
|
||||
|
||||
|
||||
def grade_summary_6002x(totaled_scores):
|
||||
"""
|
||||
This function takes the a dictionary of (graded) section scores, and applies the course grading rules to create
|
||||
the grade_summary. For 6.002x this means homeworks and labs all have equal weight, with the lowest 2 of each
|
||||
being dropped. There is one midterm and one final.
|
||||
"""
|
||||
|
||||
def totalWithDrops(scores, drop_count):
|
||||
#Note that this key will sort the list descending
|
||||
@@ -131,12 +165,12 @@ def grade_sheet(student):
|
||||
return aggregate_score, dropped_indices
|
||||
|
||||
#Figure the homework scores
|
||||
homework_scores = total_scores['Homework'] if 'Homework' in total_scores else []
|
||||
homework_scores = totaled_scores['Homework'] if 'Homework' in totaled_scores else []
|
||||
homework_percentages = []
|
||||
for i in range(12):
|
||||
if i < len(homework_scores):
|
||||
percentage = homework_scores[i][0] / float(homework_scores[i][1])
|
||||
summary = "Homework {0} - {1} - {2:.0%} ({3:g}/{4:g})".format( i + 1, homework_scores[i][2] , percentage, homework_scores[i][0], homework_scores[i][1] )
|
||||
percentage = homework_scores[1].earned / float(homework_scores[i].possible)
|
||||
summary = "Homework {0} - {1} - {2:.0%} ({3:g}/{4:g})".format( i + 1, homework_scores[i].section , percentage, homework_scores[i].earned, homework_scores[i].possible )
|
||||
else:
|
||||
percentage = 0
|
||||
summary = "Unreleased Homework {0} - 0% (?/?)".format(i + 1)
|
||||
@@ -153,13 +187,12 @@ def grade_sheet(student):
|
||||
homework_total, homework_dropped_indices = totalWithDrops(homework_percentages, 2)
|
||||
|
||||
#Figure the lab scores
|
||||
lab_scores = total_scores['Lab'] if 'Lab' in total_scores else []
|
||||
lab_scores = totaled_scores['Lab'] if 'Lab' in totaled_scores else []
|
||||
lab_percentages = []
|
||||
log.debug("lab_scores: {0}".format(lab_scores))
|
||||
for i in range(12):
|
||||
if i < len(lab_scores):
|
||||
percentage = lab_scores[i][0] / float(lab_scores[i][1])
|
||||
summary = "Lab {0} - {1} - {2:.0%} ({3:g}/{4:g})".format( i + 1, lab_scores[i][2] , percentage, lab_scores[i][0], lab_scores[i][1] )
|
||||
percentage = lab_scores[i].earned / float(lab_scores[i].possible)
|
||||
summary = "Lab {0} - {1} - {2:.0%} ({3:g}/{4:g})".format( i + 1, lab_scores[i].section , percentage, lab_scores[i].earned, lab_scores[i].possible )
|
||||
else:
|
||||
percentage = 0
|
||||
summary = "Unreleased Lab {0} - 0% (?/?)".format(i + 1)
|
||||
@@ -177,18 +210,18 @@ def grade_sheet(student):
|
||||
|
||||
|
||||
#TODO: Pull this data about the midterm and final from the databse. It should be exactly similar to above, but we aren't sure how exams will be done yet.
|
||||
midterm_score = ('?', '?')
|
||||
midterm_score = Score('?', '?', True, "?")
|
||||
midterm_percentage = 0
|
||||
|
||||
final_score = ('?', '?')
|
||||
final_score = Score('?', '?', True, "?")
|
||||
final_percentage = 0
|
||||
|
||||
if settings.GENERATE_PROFILE_SCORES:
|
||||
midterm_score = (random.randrange(50, 150), 150)
|
||||
midterm_percentage = midterm_score[0] / float(midterm_score[1])
|
||||
midterm_score = Score(random.randrange(50, 150), 150, True, "?")
|
||||
midterm_percentage = midterm_score.earned / float(midterm_score.possible)
|
||||
|
||||
final_score = (random.randrange(100, 300), 300)
|
||||
final_percentage = final_score[0] / float(final_score[1])
|
||||
final_score = Score(random.randrange(100, 300), 300, True, "?")
|
||||
final_percentage = final_score.earned / float(final_score.possible)
|
||||
|
||||
|
||||
grade_summary = [
|
||||
@@ -196,7 +229,8 @@ def grade_sheet(student):
|
||||
'category': 'Homework',
|
||||
'subscores' : homework_percentages,
|
||||
'dropped_indices' : homework_dropped_indices,
|
||||
'totalscore' : {'score' : homework_total, 'summary' : "Homework Average - {0:.0%}".format(homework_total)},
|
||||
'totalscore' : homework_total,
|
||||
'totalscore_summary' : "Homework Average - {0:.0%}".format(homework_total),
|
||||
'totallabel' : 'HW Avg',
|
||||
'weight' : 0.15,
|
||||
},
|
||||
@@ -204,25 +238,25 @@ def grade_sheet(student):
|
||||
'category': 'Labs',
|
||||
'subscores' : lab_percentages,
|
||||
'dropped_indices' : lab_dropped_indices,
|
||||
'totalscore' : {'score' : lab_total, 'summary' : "Lab Average - {0:.0%}".format(lab_total)},
|
||||
'totalscore' : lab_total,
|
||||
'totalscore_summary' : "Lab Average - {0:.0%}".format(lab_total),
|
||||
'totallabel' : 'Lab Avg',
|
||||
'weight' : 0.15,
|
||||
},
|
||||
{
|
||||
'category': 'Midterm',
|
||||
'totalscore' : {'score' : midterm_percentage, 'summary' : "Midterm - {0:.0%} ({1}/{2})".format(midterm_percentage, midterm_score[0], midterm_score[1])},
|
||||
'totalscore' : midterm_percentage,
|
||||
'totalscore_summary' : "Midterm - {0:.0%} ({1}/{2})".format(midterm_percentage, midterm_score.earned, midterm_score.possible),
|
||||
'totallabel' : 'Midterm',
|
||||
'weight' : 0.30,
|
||||
},
|
||||
{
|
||||
'category': 'Final',
|
||||
'totalscore' : {'score' : final_percentage, 'summary' : "Final - {0:.0%} ({1}/{2})".format(final_percentage, final_score[0], final_score[1])},
|
||||
'totalscore' : final_percentage,
|
||||
'totalscore_summary' : "Final - {0:.0%} ({1}/{2})".format(final_percentage, final_score.earned, final_score.possible),
|
||||
'totallabel' : 'Final',
|
||||
'weight' : 0.40,
|
||||
}
|
||||
]
|
||||
|
||||
return {'grade_summary' : grade_summary,
|
||||
'chapters':chapters}
|
||||
|
||||
|
||||
return grade_summary
|
||||
|
||||
@@ -20,7 +20,7 @@ class ModelsTest(unittest.TestCase):
|
||||
variables={'R1':2.0, 'R3':4.0}
|
||||
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(variables, functions, "13"), 13)
|
||||
self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5)
|
||||
@@ -30,6 +30,8 @@ class ModelsTest(unittest.TestCase):
|
||||
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, "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
|
||||
try:
|
||||
calc.evaluator({},{}, "5+7 QWSEKO")
|
||||
|
||||
1
pre-requirements.txt
Normal file
1
pre-requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
numpy
|
||||
78
rakefile
Normal file
78
rakefile
Normal file
@@ -0,0 +1,78 @@
|
||||
require 'rake/clean'
|
||||
require 'tempfile'
|
||||
|
||||
# Build Constants
|
||||
REPO_ROOT = File.dirname(__FILE__)
|
||||
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')
|
||||
CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util")
|
||||
|
||||
|
||||
task :package do
|
||||
FileUtils.mkdir_p(BUILD_DIR)
|
||||
|
||||
Dir.chdir(BUILD_DIR) do
|
||||
|
||||
postinstall = Tempfile.new('postinstall')
|
||||
postinstall.write <<-POSTINSTALL.gsub(/^\s*/, '')
|
||||
#! /bin/sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
service gunicorn stop
|
||||
rm #{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",
|
||||
"--after-install=#{postinstall.path}",
|
||||
"--prefix=#{INSTALL_DIR_PATH}",
|
||||
"-C", "#{REPO_ROOT}",
|
||||
"--depends=python-mysqldb",
|
||||
"--depends=python-django",
|
||||
"--depends=python-pip",
|
||||
"--depends=python-flup",
|
||||
"--depends=python-numpy",
|
||||
"--depends=python-scipy",
|
||||
"--depends=python-matplotlib",
|
||||
"--depends=python-libxml2",
|
||||
"--depends=python2.7-dev",
|
||||
"--depends=libxml2-dev",
|
||||
"--depends=libxslt-dev",
|
||||
"--depends=python-markdown",
|
||||
"--depends=python-pygments",
|
||||
"--depends=mysql-client",
|
||||
"--name=#{DEPLOY_NAME}",
|
||||
"--version=#{VERSION}",
|
||||
"-a", "all",
|
||||
"."]
|
||||
system(*args) || raise("fpm failed to build the .deb")
|
||||
end
|
||||
end
|
||||
|
||||
task :publish => :package do
|
||||
sh("scp #{BUILD_DIR}/#{DEPLOY_NAME}_#{VERSION}-1_all.deb #{PACKAGE_REPO}")
|
||||
end
|
||||
14
requirements.txt
Normal file
14
requirements.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
django
|
||||
pip
|
||||
flup
|
||||
scipy
|
||||
matplotlib
|
||||
markdown
|
||||
pygments
|
||||
django-mako
|
||||
django-ses
|
||||
lxml
|
||||
boto
|
||||
mako
|
||||
python-memcached
|
||||
django-celery
|
||||
@@ -174,7 +174,9 @@ CACHES = {
|
||||
}
|
||||
|
||||
# Make sure we execute correctly regardless of where we're called from
|
||||
execfile(os.path.join(BASE_DIR, "settings.py"))
|
||||
override_settings = os.path.join(BASE_DIR, "settings.py")
|
||||
if os.path.isfile(override_settings):
|
||||
execfile(override_settings)
|
||||
|
||||
# A sample logging configuration. The only tangible logging
|
||||
# performed by this configuration is to send an email to
|
||||
@@ -238,7 +240,7 @@ LOGGING = {
|
||||
},
|
||||
'loggers' : {
|
||||
'django' : {
|
||||
'handlers' : handlers + ['mail_admins'],
|
||||
'handlers' : handlers, # + ['mail_admins'],
|
||||
'propagate' : True,
|
||||
'level' : 'INFO'
|
||||
},
|
||||
|
||||
@@ -117,7 +117,7 @@ input, select {
|
||||
font-weight: 800;
|
||||
font-style: italic; }
|
||||
|
||||
.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.wiki-wrapper section.wiki-body header:after, html body section.main-content:after, html body section.outside-app:after, div.header-wrapper header:after, div.header-wrapper header hgroup:after, div.header-wrapper header nav ul:after, footer:after, li.calc-main div#calculator_wrapper form:after, div.leanModal_box#enroll ol:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls div#slider:after, section.course-content nav.sequence-bottom ul:after, div#graph-container:after, div#schematic-container:after, div.book-wrapper section.book nav ul:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.profile-wrapper section.course-info header:after, div.profile-wrapper section.course-info > ol > li:after, div#wiki_panel div#wiki_create_form:after, div.wiki-wrapper section.wiki-body:after, ul.badge-list li.badge:after {
|
||||
.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.wiki-wrapper section.wiki-body header:after, html body section.main-content:after, html body section.outside-app:after, div.header-wrapper header:after, div.header-wrapper header hgroup:after, div.header-wrapper header nav ul:after, footer:after, li.calc-main div#calculator_wrapper form:after, li.calc-main div#calculator_wrapper form div.input-wrapper:after, div.leanModal_box#enroll ol:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls div#slider:after, section.course-content nav.sequence-bottom ul:after, div#graph-container:after, div#schematic-container:after, div.book-wrapper section.book nav ul:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.profile-wrapper section.course-info header:after, div.profile-wrapper section.course-info > ol > li:after, div#wiki_panel div#wiki_create_form:after, div.wiki-wrapper section.wiki-body:after, ul.badge-list li.badge:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
@@ -449,8 +449,7 @@ html body section.main-content, html body section.outside-app {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin-top: 3px;
|
||||
overflow: hidden; }
|
||||
margin-top: 3px; }
|
||||
@media print {
|
||||
html body section.main-content, html body section.outside-app {
|
||||
border-bottom: 0;
|
||||
@@ -665,7 +664,7 @@ footer nav ul.social li.linkedin a {
|
||||
background: url("/static/images/linkedin.png") 0 0 no-repeat; }
|
||||
|
||||
li.calc-main {
|
||||
bottom: 0;
|
||||
bottom: -36px;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
width: 100%; }
|
||||
@@ -692,32 +691,20 @@ li.calc-main a.calc {
|
||||
*vertical-align: auto;
|
||||
padding: 8px 12px;
|
||||
width: 16px;
|
||||
height: 20px; }
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: -36px; }
|
||||
li.calc-main a.calc:hover {
|
||||
opacity: .8; }
|
||||
li.calc-main a.calc.closed {
|
||||
background-image: url("/static/images/close-calc-icon.png"); }
|
||||
li.calc-main div#calculator_wrapper {
|
||||
background: rgba(17, 17, 17, 0.9);
|
||||
position: relative;
|
||||
top: -36px;
|
||||
clear: both; }
|
||||
li.calc-main div#calculator_wrapper form {
|
||||
padding: 22.652px; }
|
||||
li.calc-main div#calculator_wrapper form input#calculator_input {
|
||||
border: none;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
width: 61.741%;
|
||||
margin: 0;
|
||||
float: left; }
|
||||
li.calc-main div#calculator_wrapper form input#calculator_input:focus {
|
||||
outline: none;
|
||||
border: none; }
|
||||
li.calc-main div#calculator_wrapper form input#calculator_button {
|
||||
background: #111;
|
||||
border: 1px solid #000;
|
||||
@@ -758,14 +745,82 @@ li.calc-main div#calculator_wrapper form input#calculator_output {
|
||||
margin: 1px 0 0;
|
||||
padding: 10px;
|
||||
width: 31.984%; }
|
||||
li.calc-main div#calculator_wrapper dl {
|
||||
display: none; }
|
||||
li.calc-main div#calculator_wrapper dl dt {
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper {
|
||||
position: relative;
|
||||
width: 61.741%;
|
||||
margin: 0;
|
||||
float: left; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper input#calculator_input {
|
||||
border: none;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
width: 100%; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper input#calculator_input:focus {
|
||||
outline: none;
|
||||
border: none; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper div.help-wrapper {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 15px; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper div.help-wrapper a {
|
||||
text-indent: -9999px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background: url("/static/images/info-icon.png") center center no-repeat; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper div.help-wrapper dl {
|
||||
background: #fff;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-ms-border-radius: 3px;
|
||||
-o-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-webkit-box-shadow: 0 0 3px #999999;
|
||||
-moz-box-shadow: 0 0 3px #999999;
|
||||
box-shadow: 0 0 3px #999999;
|
||||
color: #333;
|
||||
opacity: 0;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
right: -40px;
|
||||
top: -110px;
|
||||
width: 500px;
|
||||
-webkit-transition-property: all;
|
||||
-moz-transition-property: all;
|
||||
-ms-transition-property: all;
|
||||
-o-transition-property: all;
|
||||
transition-property: all;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-moz-transition-duration: 0.15s;
|
||||
-ms-transition-duration: 0.15s;
|
||||
-o-transition-duration: 0.15s;
|
||||
transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out;
|
||||
-moz-transition-timing-function: ease-out;
|
||||
-ms-transition-timing-function: ease-out;
|
||||
-o-transition-timing-function: ease-out;
|
||||
transition-timing-function: ease-out;
|
||||
-webkit-transition-delay: 0;
|
||||
-moz-transition-delay: 0;
|
||||
-ms-transition-delay: 0;
|
||||
-o-transition-delay: 0;
|
||||
transition-delay: 0; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper div.help-wrapper dl.shown {
|
||||
opacity: 1;
|
||||
top: -115px; }
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper div.help-wrapper dl dt {
|
||||
clear: both;
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
padding-right: 11.326px; }
|
||||
li.calc-main div#calculator_wrapper dl dd {
|
||||
li.calc-main div#calculator_wrapper form div.input-wrapper div.help-wrapper dl dd {
|
||||
float: left; }
|
||||
|
||||
#lean_overlay {
|
||||
@@ -2900,14 +2955,25 @@ section.course-content div.video-subtitles.closed ol.subtitles {
|
||||
height: 0; }
|
||||
|
||||
nav.sequence-nav {
|
||||
margin-bottom: 22.652px; }
|
||||
nav.sequence-nav ol {
|
||||
display: table-row;
|
||||
float: left;
|
||||
width: 90.611%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 22.652px;
|
||||
position: relative; }
|
||||
nav.sequence-nav ol {
|
||||
border-bottom: 1px solid #e4d080;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
display: table;
|
||||
padding-right: 8.696%;
|
||||
width: 100%; }
|
||||
nav.sequence-nav ol li {
|
||||
display: table-cell; }
|
||||
border-left: 1px solid #e4d080;
|
||||
display: table-cell;
|
||||
min-width: 20px; }
|
||||
nav.sequence-nav ol li:first-child {
|
||||
border-left: none; }
|
||||
nav.sequence-nav ol li .inactive, nav.sequence-nav ol li a.seq_video_inactive, nav.sequence-nav ol li a.seq_other_inactive, nav.sequence-nav ol li a.seq_vertical_inactive, nav.sequence-nav ol li a.seq_problem_inactive {
|
||||
background-repeat: no-repeat; }
|
||||
nav.sequence-nav ol li .inactive:hover, nav.sequence-nav ol li a.seq_video_inactive:hover, nav.sequence-nav ol li a.seq_other_inactive:hover, nav.sequence-nav ol li a.seq_vertical_inactive:hover, nav.sequence-nav ol li a.seq_problem_inactive:hover {
|
||||
@@ -2922,25 +2988,21 @@ nav.sequence-nav ol li .visited:hover, nav.sequence-nav ol li a.seq_video_visite
|
||||
background-color: #f6efd4;
|
||||
background-position: center center; }
|
||||
nav.sequence-nav ol li .active, nav.sequence-nav ol div.header-wrapper header nav.courseware li.courseware a, div.header-wrapper header nav.courseware nav.sequence-nav ol li.courseware a, nav.sequence-nav ol div.header-wrapper header nav.book li.book a, div.header-wrapper header nav.book nav.sequence-nav ol li.book a, nav.sequence-nav ol div.header-wrapper header nav.info li.info a, div.header-wrapper header nav.info nav.sequence-nav ol li.info a, nav.sequence-nav ol div.header-wrapper header nav.discussion li.discussion a, div.header-wrapper header nav.discussion nav.sequence-nav ol li.discussion a, nav.sequence-nav ol div.header-wrapper header nav.wiki li.wiki a, div.header-wrapper header nav.wiki nav.sequence-nav ol li.wiki a, nav.sequence-nav ol div.header-wrapper header nav.profile li.profile a, div.header-wrapper header nav.profile nav.sequence-nav ol li.profile a, nav.sequence-nav ol li section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion nav.sequence-nav ol li h3.ui-accordion-header.ui-state-active, nav.sequence-nav ol li section.course-index div#accordion div#wiki_panel input.ui-accordion-header.ui-state-active[type="button"], section.course-index div#accordion div#wiki_panel nav.sequence-nav ol li input.ui-accordion-header.ui-state-active[type="button"], nav.sequence-nav ol li div#wiki_panel section.course-index div#accordion input.ui-accordion-header.ui-state-active[type="button"], div#wiki_panel section.course-index div#accordion nav.sequence-nav ol li input.ui-accordion-header.ui-state-active[type="button"], nav.sequence-nav ol li a.seq_video_active, nav.sequence-nav ol li a.seq_other_active, nav.sequence-nav ol li a.seq_vertical_active, nav.sequence-nav ol li a.seq_problem_active {
|
||||
background-color: #fff;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-box-shadow: 0 1px 0 white;
|
||||
-moz-box-shadow: 0 1px 0 white;
|
||||
box-shadow: 0 1px 0 white;
|
||||
background-color: #fff;
|
||||
background-repeat: no-repeat; }
|
||||
box-shadow: 0 1px 0 white; }
|
||||
nav.sequence-nav ol li .active:hover, nav.sequence-nav ol div.header-wrapper header nav.courseware li.courseware a:hover, div.header-wrapper header nav.courseware nav.sequence-nav ol li.courseware a:hover, nav.sequence-nav ol div.header-wrapper header nav.book li.book a:hover, div.header-wrapper header nav.book nav.sequence-nav ol li.book a:hover, nav.sequence-nav ol div.header-wrapper header nav.info li.info a:hover, div.header-wrapper header nav.info nav.sequence-nav ol li.info a:hover, nav.sequence-nav ol div.header-wrapper header nav.discussion li.discussion a:hover, div.header-wrapper header nav.discussion nav.sequence-nav ol li.discussion a:hover, nav.sequence-nav ol div.header-wrapper header nav.wiki li.wiki a:hover, div.header-wrapper header nav.wiki nav.sequence-nav ol li.wiki a:hover, nav.sequence-nav ol div.header-wrapper header nav.profile li.profile a:hover, div.header-wrapper header nav.profile nav.sequence-nav ol li.profile a:hover, nav.sequence-nav ol li section.course-index div#accordion h3.ui-accordion-header.ui-state-active:hover, section.course-index div#accordion nav.sequence-nav ol li h3.ui-accordion-header.ui-state-active:hover, nav.sequence-nav ol li section.course-index div#accordion div#wiki_panel input.ui-accordion-header.ui-state-active[type="button"]:hover, section.course-index div#accordion div#wiki_panel nav.sequence-nav ol li input.ui-accordion-header.ui-state-active[type="button"]:hover, nav.sequence-nav ol li div#wiki_panel section.course-index div#accordion input.ui-accordion-header.ui-state-active[type="button"]:hover, div#wiki_panel section.course-index div#accordion nav.sequence-nav ol li input.ui-accordion-header.ui-state-active[type="button"]:hover, nav.sequence-nav ol li a.seq_video_active:hover, nav.sequence-nav ol li a.seq_other_active:hover, nav.sequence-nav ol li a.seq_vertical_active:hover, nav.sequence-nav ol li a.seq_problem_active:hover {
|
||||
background-color: #fff;
|
||||
background-position: center; }
|
||||
nav.sequence-nav ol li a {
|
||||
-webkit-box-shadow: 1px 0 0 white;
|
||||
-moz-box-shadow: 1px 0 0 white;
|
||||
box-shadow: 1px 0 0 white;
|
||||
background-position: center center;
|
||||
border: none;
|
||||
border-right: 1px solid #eddfaa;
|
||||
cursor: pointer;
|
||||
padding: 15px 4px 14px;
|
||||
width: 28px;
|
||||
display: block;
|
||||
height: 17px;
|
||||
padding: 15px 0 14px;
|
||||
-webkit-transition-property: all;
|
||||
-moz-transition-property: all;
|
||||
-ms-transition-property: all;
|
||||
@@ -2960,7 +3022,8 @@ nav.sequence-nav ol li a {
|
||||
-moz-transition-delay: 0;
|
||||
-ms-transition-delay: 0;
|
||||
-o-transition-delay: 0;
|
||||
transition-delay: 0; }
|
||||
transition-delay: 0;
|
||||
width: 100%; }
|
||||
nav.sequence-nav ol li a.seq_video_inactive {
|
||||
background-image: url("/static/images/sequence-nav/video-icon-normal.png");
|
||||
background-position: center; }
|
||||
@@ -3020,8 +3083,8 @@ nav.sequence-nav ol li p {
|
||||
white-space: pre-wrap;
|
||||
z-index: 99; }
|
||||
nav.sequence-nav ol li p.shown {
|
||||
opacity: 1;
|
||||
margin-top: 4px; }
|
||||
margin-top: 4px;
|
||||
opacity: 1; }
|
||||
nav.sequence-nav ol li p:empty {
|
||||
background: none; }
|
||||
nav.sequence-nav ol li p:empty::after {
|
||||
@@ -3031,9 +3094,9 @@ nav.sequence-nav ol li p::after {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 10px;
|
||||
left: 18px;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 18px;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
@@ -3041,30 +3104,33 @@ nav.sequence-nav ol li p::after {
|
||||
transform: rotate(45deg);
|
||||
width: 10px; }
|
||||
nav.sequence-nav ul {
|
||||
float: right;
|
||||
margin-right: 1px;
|
||||
width: 8.696%;
|
||||
display: table-row; }
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 8.696%; }
|
||||
nav.sequence-nav ul li {
|
||||
display: table-cell; }
|
||||
float: left;
|
||||
width: 50%; }
|
||||
nav.sequence-nav ul li.prev a, nav.sequence-nav ul li.next a {
|
||||
-webkit-box-shadow: inset 1px 0 0 #faf7e9;
|
||||
-moz-box-shadow: inset 1px 0 0 #faf7e9;
|
||||
box-shadow: inset 1px 0 0 #faf7e9;
|
||||
background-color: #f2e7bf;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
border-left: 1px solid #e4d080;
|
||||
-webkit-box-shadow: inset 1px 0 0 #faf7e9;
|
||||
-moz-box-shadow: inset 1px 0 0 #faf7e9;
|
||||
box-shadow: inset 1px 0 0 #faf7e9;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
padding: 0 4px;
|
||||
text-indent: -9999px;
|
||||
width: 38px;
|
||||
display: block; }
|
||||
display: block;
|
||||
text-indent: -9999px; }
|
||||
nav.sequence-nav ul li.prev a:hover, nav.sequence-nav ul li.next a:hover {
|
||||
text-decoration: none;
|
||||
background-color: none;
|
||||
color: #7e691a;
|
||||
text-decoration: none;
|
||||
background-color: none; }
|
||||
text-decoration: none; }
|
||||
nav.sequence-nav ul li.prev a.disabled, nav.sequence-nav ul li.next a.disabled {
|
||||
cursor: normal;
|
||||
opacity: .4; }
|
||||
@@ -3077,16 +3143,13 @@ nav.sequence-nav ul li.next a {
|
||||
nav.sequence-nav ul li.next a:hover {
|
||||
background-color: none; }
|
||||
|
||||
section.course-content {
|
||||
position: relative; }
|
||||
section.course-content div#seq_content {
|
||||
margin-bottom: 60px; }
|
||||
section.course-content nav.sequence-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 50%;
|
||||
margin-right: -53px; }
|
||||
bottom: -22.652px;
|
||||
position: relative; }
|
||||
section.course-content nav.sequence-bottom ul {
|
||||
background-color: #f2e7bf;
|
||||
background-color: #f2e7bf;
|
||||
border: 1px solid #e4d080;
|
||||
border-bottom: 0;
|
||||
@@ -3095,12 +3158,12 @@ section.course-content nav.sequence-bottom ul {
|
||||
-ms-border-radius: 3px 3px 0 0;
|
||||
-o-border-radius: 3px 3px 0 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
overflow: hidden;
|
||||
width: 106px;
|
||||
background-color: #f2e7bf;
|
||||
-webkit-box-shadow: inset 0 0 0 1px #faf7e9;
|
||||
-moz-box-shadow: inset 0 0 0 1px #faf7e9;
|
||||
box-shadow: inset 0 0 0 1px #faf7e9; }
|
||||
box-shadow: inset 0 0 0 1px #faf7e9;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
width: 106px; }
|
||||
section.course-content nav.sequence-bottom ul li {
|
||||
float: left; }
|
||||
section.course-content nav.sequence-bottom ul li.prev, section.course-content nav.sequence-bottom ul li.next {
|
||||
@@ -3110,10 +3173,9 @@ section.course-content nav.sequence-bottom ul li.prev a, section.course-content
|
||||
background-repeat: no-repeat;
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
display: block;
|
||||
padding: 16.989px 4px;
|
||||
text-indent: -9999px;
|
||||
width: 45px;
|
||||
display: block;
|
||||
-webkit-transition-property: all;
|
||||
-moz-transition-property: all;
|
||||
-ms-transition-property: all;
|
||||
@@ -3133,7 +3195,8 @@ section.course-content nav.sequence-bottom ul li.prev a, section.course-content
|
||||
-moz-transition-delay: 0;
|
||||
-ms-transition-delay: 0;
|
||||
-o-transition-delay: 0;
|
||||
transition-delay: 0; }
|
||||
transition-delay: 0;
|
||||
width: 45px; }
|
||||
section.course-content nav.sequence-bottom ul li.prev a:hover, section.course-content nav.sequence-bottom ul li.next a:hover {
|
||||
background-color: #eddfaa;
|
||||
color: #7e691a;
|
||||
@@ -3287,6 +3350,11 @@ div.info-wrapper section.updates > ol > li {
|
||||
padding-bottom: 11.326px;
|
||||
margin-bottom: 11.326px;
|
||||
border-bottom: 1px solid #e3e3e3; }
|
||||
div.info-wrapper section.updates > ol > li:first-child {
|
||||
padding: 11.326px;
|
||||
margin: 0 -11.326px 22.652px;
|
||||
background: #f6efd4;
|
||||
border-bottom: 1px solid #eddfaa; }
|
||||
div.info-wrapper section.updates > ol > li h2 {
|
||||
float: left;
|
||||
width: 20.109%;
|
||||
|
||||
BIN
static/images/info-icon.png
Normal file
BIN
static/images/info-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 302 B |
@@ -1,22 +1,76 @@
|
||||
<%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=''" />
|
||||
<section class="main-content">
|
||||
<div class="gradebook-wrapper">
|
||||
<section class="gradebook-content">
|
||||
<h1>Gradebook</h1>
|
||||
% for s in students:
|
||||
<h2><a href=/profile/${s['id']}>${s['username']}</a></h2>
|
||||
% for c in s['grade_info']['grade_summary']:
|
||||
<h3>${c['category']} </h3>
|
||||
<p>
|
||||
% if 'subscores' in c:
|
||||
% for ss in c['subscores']:
|
||||
<br>${ss['summary']}
|
||||
% endfor
|
||||
% endif
|
||||
</p>
|
||||
% endfor
|
||||
% endfor
|
||||
<h1>Gradebook</h1>
|
||||
|
||||
%if len(students) > 0:
|
||||
<table>
|
||||
<%
|
||||
templateSummary = students[0]['grade_info']['grade_summary']
|
||||
%>
|
||||
|
||||
|
||||
<tr> <!-- Header Row -->
|
||||
<th>Student</th>
|
||||
%for section in templateSummary:
|
||||
%if 'subscores' in section:
|
||||
%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="/discussion/users/${student['id']}/${student['username']}/">${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>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
30
templates/gradebook_profilegraphs.html
Normal file
30
templates/gradebook_profilegraphs.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<%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>
|
||||
@@ -57,21 +57,27 @@
|
||||
|
||||
<div id="calculator_wrapper">
|
||||
<form id="calculator">
|
||||
<input type="text" id="calculator_input" />
|
||||
<dl class="help">
|
||||
<dt>Suffixes:</dt>
|
||||
<dd> %kMGTcmunp</dd>
|
||||
<dt>Operations:</dt>
|
||||
<dd>^ * / + - ()</dd>
|
||||
<dt>Functions:</dt>
|
||||
<dd>sin, cos, tan, sqrt, log10, log2, ln, arccos, arcsin, arctan, abs </dd>
|
||||
<dt>Constants</dt>
|
||||
<dd>e, pi</dd>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="calculator_input" />
|
||||
|
||||
<!-- Students won't know what parallel means at this time. Complex numbers aren't well tested in the courseware, so we would prefer to not expose them. If you read the comments in the source, feel free to use them. If you run into a bug, please let us know. But we can't officially support them right now.
|
||||
<div class="help-wrapper">
|
||||
<a href="#">Hints</a>
|
||||
<dl class="help">
|
||||
<dt>Suffixes:</dt>
|
||||
<dd> %kMGTcmunp</dd>
|
||||
<dt>Operations:</dt>
|
||||
<dd>^ * / + - ()</dd>
|
||||
<dt>Functions:</dt>
|
||||
<dd>sin, cos, tan, sqrt, log10, log2, ln, arccos, arcsin, arctan, abs </dd>
|
||||
<dt>Constants</dt>
|
||||
<dd>e, pi</dd>
|
||||
|
||||
<dt>Unsupported:</dt> <dd>||, j </dd> -->
|
||||
</dl>
|
||||
<!-- Students won't know what parallel means at this time. Complex numbers aren't well tested in the courseware, so we would prefer to not expose them. If you read the comments in the source, feel free to use them. If you run into a bug, please let us know. But we can't officially support them right now.
|
||||
|
||||
<dt>Unsupported:</dt> <dd>||, j </dd> -->
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<input id="calculator_button" type="submit" value="="/>
|
||||
<input type="text" id="calculator_output" readonly />
|
||||
</form>
|
||||
@@ -128,11 +134,20 @@ $(function() {
|
||||
$("#calculator_wrapper").hide();
|
||||
|
||||
$(".calc").click(function(){
|
||||
$("#calculator_wrapper").slideToggle();
|
||||
$("#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")},
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<%inherit file="main.html" />
|
||||
<%namespace name="profile_graphs" file="profile_graphs.js"/>
|
||||
|
||||
<%block name="title"><title>Profile - MITx 6.002x</title></%block>
|
||||
|
||||
<%!
|
||||
@@ -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.symbol.js"></script>
|
||||
<script>
|
||||
<%include file="profile_graphs.js"/>
|
||||
${profile_graphs.body(grade_summary, "grade-detail-graph")}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
@@ -136,7 +138,7 @@ $(function() {
|
||||
<div id="grade-detail-graph"></div>
|
||||
|
||||
<ol class="chapters">
|
||||
%for chapter in chapters:
|
||||
%for chapter in courseware_summary:
|
||||
%if not chapter['chapter'] == "hidden":
|
||||
<li>
|
||||
<h2><a href="${reverse('courseware_chapter', args=format_url_params([chapter['course'], chapter['chapter']])) }">
|
||||
@@ -146,8 +148,8 @@ $(function() {
|
||||
%for section in chapter['sections']:
|
||||
<li>
|
||||
<%
|
||||
earned = section['section_total'][0]
|
||||
total = section['section_total'][1]
|
||||
earned = section['section_total'].earned
|
||||
total = section['section_total'].possible
|
||||
percentageString = "{0:.0%}".format( float(earned)/total) if earned > 0 else ""
|
||||
%>
|
||||
|
||||
@@ -162,7 +164,7 @@ $(function() {
|
||||
<ol class="scores">
|
||||
${ "Problem Scores: " if section['graded'] else "Practice 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
|
||||
</ol>
|
||||
%endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<%page args="grade_summary, graph_div_id, **kwargs"/>
|
||||
<%!
|
||||
import json
|
||||
%>
|
||||
@@ -57,21 +58,21 @@ $(function () {
|
||||
category_total_label = section['category'] + " Total"
|
||||
series.append({
|
||||
'label' : category_total_label,
|
||||
'data' : [ [tickIndex, section['totalscore']['score']] ],
|
||||
'data' : [ [tickIndex, section['totalscore']] ],
|
||||
'color' : colors[sectionIndex]
|
||||
})
|
||||
|
||||
ticks.append( [tickIndex, section['totallabel']] )
|
||||
detail_tooltips[category_total_label] = [section['totalscore']['summary']]
|
||||
detail_tooltips[category_total_label] = [section['totalscore_summary']]
|
||||
else:
|
||||
series.append({
|
||||
'label' : section['category'],
|
||||
'data' : [ [tickIndex, section['totalscore']['score']] ],
|
||||
'data' : [ [tickIndex, section['totalscore']] ],
|
||||
'color' : colors[sectionIndex]
|
||||
})
|
||||
|
||||
ticks.append( [tickIndex, section['totallabel']] )
|
||||
detail_tooltips[section['category']] = [section['totalscore']['summary']]
|
||||
detail_tooltips[section['category']] = [section['totalscore_summary']]
|
||||
|
||||
tickIndex += 1 + sectionSpacer
|
||||
sectionIndex += 1
|
||||
@@ -86,12 +87,12 @@ $(function () {
|
||||
overviewBarX = tickIndex
|
||||
|
||||
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'])
|
||||
|
||||
|
||||
weighted_category_label = section['category'] + " - Weighted"
|
||||
|
||||
if section['totalscore']['score'] > 0:
|
||||
if section['totalscore'] > 0:
|
||||
series.append({
|
||||
'label' : weighted_category_label,
|
||||
'data' : [ [overviewBarX, weighted_score] ],
|
||||
@@ -101,7 +102,7 @@ $(function () {
|
||||
detail_tooltips[weighted_category_label] = [ summary_text ]
|
||||
sectionIndex += 1
|
||||
totalWeight += section['weight']
|
||||
totalScore += section['totalscore']['score'] * section['weight']
|
||||
totalScore += section['totalscore'] * section['weight']
|
||||
|
||||
ticks += [ [overviewBarX, "Total"] ]
|
||||
tickIndex += 1 + sectionSpacer
|
||||
@@ -128,7 +129,7 @@ $(function () {
|
||||
legend: {show: false},
|
||||
};
|
||||
|
||||
var $grade_detail_graph = $("#grade-detail-graph");
|
||||
var $grade_detail_graph = $("#${graph_div_id}");
|
||||
if ($grade_detail_graph.length > 0) {
|
||||
var plot = $.plot($grade_detail_graph, series, options);
|
||||
|
||||
@@ -137,7 +138,7 @@ $(function () {
|
||||
}
|
||||
|
||||
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));
|
||||
$("#y").text(pos.y.toFixed(2));
|
||||
if (item) {
|
||||
|
||||
@@ -8,4 +8,4 @@ div.gradebook-wrapper {
|
||||
@extend .top-header;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,12 @@ div.info-wrapper {
|
||||
@extend .clearfix;
|
||||
border-bottom: 1px solid #e3e3e3;
|
||||
|
||||
// &:first-child {
|
||||
// padding: lh(.5);
|
||||
// margin-left: (-(lh(.5)));
|
||||
// background: $cream;
|
||||
// border-bottom: 1px solid darken($cream, 10%);
|
||||
// }
|
||||
&:first-child {
|
||||
padding: lh(.5);
|
||||
margin: 0 (-(lh(.5))) lh();
|
||||
background: $cream;
|
||||
border-bottom: 1px solid darken($cream, 10%);
|
||||
}
|
||||
|
||||
h2 {
|
||||
float: left;
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
nav.sequence-nav {
|
||||
@extend .topbar;
|
||||
@include box-sizing(border-box);
|
||||
margin-bottom: $body-line-height;
|
||||
position: relative;
|
||||
|
||||
ol {
|
||||
display: table-row;
|
||||
float: left;
|
||||
width: flex-grid(8,9) + flex-gutter();
|
||||
position: relative;
|
||||
border-bottom: 1px solid darken($cream, 20%);
|
||||
@include box-sizing(border-box);
|
||||
display: table;
|
||||
padding-right: flex-grid(1, 9);
|
||||
width: 100%;
|
||||
|
||||
a {
|
||||
@extend .block-link;
|
||||
}
|
||||
|
||||
li {
|
||||
border-left: 1px solid darken($cream, 20%);
|
||||
display: table-cell;
|
||||
min-width: 20px;
|
||||
|
||||
&:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.inactive {
|
||||
background-repeat: no-repeat;
|
||||
@@ -35,9 +44,9 @@ nav.sequence-nav {
|
||||
}
|
||||
|
||||
.active {
|
||||
@include box-shadow(0 1px 0 #fff);
|
||||
background-color: #fff;
|
||||
background-repeat: no-repeat;
|
||||
@include box-shadow(0 1px 0 #fff);
|
||||
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
@@ -46,15 +55,14 @@ nav.sequence-nav {
|
||||
}
|
||||
|
||||
a {
|
||||
@include box-shadow(1px 0 0 #fff);
|
||||
background-position: center center;
|
||||
border: none;
|
||||
border-right: 1px solid darken($cream, 10%);
|
||||
cursor: pointer;
|
||||
padding: 15px 4px 14px;
|
||||
width: 28px;
|
||||
display: block;
|
||||
height: 17px;
|
||||
padding: 15px 0 14px;
|
||||
@include transition(all, .4s, $ease-in-out-quad);
|
||||
width: 100%;
|
||||
|
||||
// @media screen and (max-width: 800px) {
|
||||
// padding: 12px 8px;
|
||||
@@ -134,8 +142,8 @@ nav.sequence-nav {
|
||||
z-index: 99;
|
||||
|
||||
&.shown {
|
||||
opacity: 1;
|
||||
margin-top: 4px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
@@ -151,9 +159,9 @@ nav.sequence-nav {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 10px;
|
||||
left: 18px;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 18px;
|
||||
@include transform(rotate(45deg));
|
||||
width: 10px;
|
||||
}
|
||||
@@ -162,33 +170,34 @@ nav.sequence-nav {
|
||||
}
|
||||
|
||||
ul {
|
||||
float: right;
|
||||
margin-right: 1px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: flex-grid(1, 9);
|
||||
display: table-row;
|
||||
|
||||
li {
|
||||
display: table-cell;
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
&.prev, &.next {
|
||||
|
||||
a {
|
||||
@include box-shadow(inset 1px 0 0 lighten(#f6efd4, 5%));
|
||||
background-color: darken($cream, 5%);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
border-left: 1px solid darken(#f6efd4, 20%);
|
||||
@include box-shadow(inset 1px 0 0 lighten(#f6efd4, 5%));
|
||||
@include box-sizing(border-box);
|
||||
cursor: pointer;
|
||||
padding: 0 4px;
|
||||
text-indent: -9999px;
|
||||
width: 38px;
|
||||
display: block;
|
||||
text-indent: -9999px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background-color: none;
|
||||
color: darken($cream, 60%);
|
||||
text-decoration: none;
|
||||
background-color: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
@@ -223,28 +232,26 @@ nav.sequence-nav {
|
||||
|
||||
|
||||
section.course-content {
|
||||
position: relative;
|
||||
|
||||
div#seq_content {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
nav.sequence-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 50%;
|
||||
margin-right: -53px;
|
||||
bottom: (-(lh()));
|
||||
position: relative;
|
||||
|
||||
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 box-shadow(inset 0 0 0 1px lighten(#f6efd4, 5%));
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
width: 106px;
|
||||
background-color: darken($cream, 5%);
|
||||
@include box-shadow(inset 0 0 0 1px lighten(#f6efd4, 5%));
|
||||
|
||||
li {
|
||||
float: left;
|
||||
@@ -257,11 +264,11 @@ section.course-content {
|
||||
background-repeat: no-repeat;
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
display: block;
|
||||
padding: lh(.75) 4px;
|
||||
text-indent: -9999px;
|
||||
width: 45px;
|
||||
display: block;
|
||||
@include transition(all, .4s, $ease-in-out-quad);
|
||||
width: 45px;
|
||||
|
||||
&:hover {
|
||||
background-color: darken($cream, 10%);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
li.calc-main {
|
||||
bottom: 0;
|
||||
bottom: -36px;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
@@ -16,6 +16,8 @@ li.calc-main {
|
||||
padding: 8px 12px;
|
||||
width: 16px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: -36px;
|
||||
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
@@ -28,27 +30,14 @@ li.calc-main {
|
||||
|
||||
div#calculator_wrapper {
|
||||
background: rgba(#111, .9);
|
||||
position: relative;
|
||||
top: -36px;
|
||||
clear: both;
|
||||
|
||||
form {
|
||||
padding: lh();
|
||||
@extend .clearfix;
|
||||
|
||||
input#calculator_input {
|
||||
border: none;
|
||||
@include box-shadow(none);
|
||||
@include box-sizing(border-box);
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
width: flex-grid(7.5);
|
||||
margin: 0;
|
||||
float: left;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
input#calculator_button {
|
||||
background: #111;
|
||||
@@ -83,20 +72,70 @@ li.calc-main {
|
||||
padding: 10px;
|
||||
width: flex-grid(4);
|
||||
}
|
||||
}
|
||||
|
||||
dl {
|
||||
display: none;
|
||||
|
||||
dt {
|
||||
clear: both;
|
||||
div.input-wrapper {
|
||||
position: relative;
|
||||
@extend .clearfix;
|
||||
width: flex-grid(7.5);
|
||||
margin: 0;
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
padding-right: lh(.5);
|
||||
|
||||
input#calculator_input {
|
||||
border: none;
|
||||
@include box-shadow(none);
|
||||
@include box-sizing(border-box);
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
float: left;
|
||||
div.help-wrapper {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 15px;
|
||||
|
||||
a {
|
||||
@include hide-text;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background: url("/static/images/info-icon.png") center center no-repeat;
|
||||
}
|
||||
|
||||
dl {
|
||||
background: #fff;
|
||||
@include border-radius(3px);
|
||||
@include box-shadow(0 0 3px #999);
|
||||
color: #333;
|
||||
opacity: 0;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
right: -40px;
|
||||
top: -110px;
|
||||
width: 500px;
|
||||
@include transition();
|
||||
|
||||
&.shown {
|
||||
opacity: 1;
|
||||
top: -115px;
|
||||
}
|
||||
|
||||
dt {
|
||||
clear: both;
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
padding-right: lh(.5);
|
||||
}
|
||||
|
||||
dd {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ html {
|
||||
@include box-shadow(0 0 4px #dfdfdf);
|
||||
@include box-sizing(border-box);
|
||||
margin-top: 3px;
|
||||
overflow: hidden;
|
||||
// overflow: hidden;
|
||||
|
||||
@media print {
|
||||
border-bottom: 0;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user