Perform merge from master, including renumbering of migrations in common/djangoapps/student/migrations
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"js_files": [
|
||||
"/static/js/vendor/RequireJS.js",
|
||||
"/static/js/vendor/jquery.min.js",
|
||||
"/static/js/vendor/jquery-ui.min.js",
|
||||
"/static/js/vendor/jquery.leanModal.min.js",
|
||||
|
||||
89
lms/static/coffee/spec/requirejs_spec.coffee
Normal file
@@ -0,0 +1,89 @@
|
||||
describe "RequireJS namespacing", ->
|
||||
beforeEach ->
|
||||
|
||||
# Jasmine does not provide a way to use the typeof operator. We need
|
||||
# to create our own custom matchers so that a TypeError is not thrown.
|
||||
@addMatchers
|
||||
requirejsTobeUndefined: ->
|
||||
typeof requirejs is "undefined"
|
||||
|
||||
requireTobeUndefined: ->
|
||||
typeof require is "undefined"
|
||||
|
||||
defineTobeUndefined: ->
|
||||
typeof define is "undefined"
|
||||
|
||||
|
||||
it "check that the RequireJS object is present in the global namespace", ->
|
||||
expect(RequireJS).toEqual jasmine.any(Object)
|
||||
expect(window.RequireJS).toEqual jasmine.any(Object)
|
||||
|
||||
it "check that requirejs(), require(), and define() are not in the global namespace", ->
|
||||
|
||||
# The custom matchers that we defined in the beforeEach() function do
|
||||
# not operate on an object. We pass a dummy empty object {} not to
|
||||
# confuse Jasmine.
|
||||
expect({}).requirejsTobeUndefined()
|
||||
expect({}).requireTobeUndefined()
|
||||
expect({}).defineTobeUndefined()
|
||||
expect(window.requirejs).not.toBeDefined()
|
||||
expect(window.require).not.toBeDefined()
|
||||
expect(window.define).not.toBeDefined()
|
||||
|
||||
|
||||
describe "RequireJS module creation", ->
|
||||
inDefineCallback = undefined
|
||||
inRequireCallback = undefined
|
||||
it "check that we can use RequireJS to define() and require() a module", ->
|
||||
|
||||
# Because Require JS works asynchronously when defining and requiring
|
||||
# modules, we need to use the special Jasmine functions runs(), and
|
||||
# waitsFor() to set up this test.
|
||||
runs ->
|
||||
|
||||
# Initialize the variable that we will test for. They will be set
|
||||
# to true in the appropriate callback functions called by Require
|
||||
# JS. If their values do not change, this will mean that something
|
||||
# is not working as is intended.
|
||||
inDefineCallback = false
|
||||
inRequireCallback = false
|
||||
|
||||
# Define our test module.
|
||||
RequireJS.define "test_module", [], ->
|
||||
inDefineCallback = true
|
||||
|
||||
# This module returns an object. It can be accessed via the
|
||||
# Require JS require() function.
|
||||
module_status: "OK"
|
||||
|
||||
|
||||
# Require our defined test module.
|
||||
RequireJS.require ["test_module"], (test_module) ->
|
||||
inRequireCallback = true
|
||||
|
||||
# If our test module was defined properly, then we should
|
||||
# be able to get the object it returned, and query some
|
||||
# property.
|
||||
expect(test_module.module_status).toBe "OK"
|
||||
|
||||
|
||||
|
||||
# We will wait for a specified amount of time (1 second), before
|
||||
# checking if our module was defined and that we were able to
|
||||
# require() the module.
|
||||
waitsFor (->
|
||||
|
||||
# If at least one of the callback functions was not reached, we
|
||||
# fail this test.
|
||||
return false if (inDefineCallback isnt true) or (inRequireCallback isnt true)
|
||||
|
||||
# Both of the callbacks were reached.
|
||||
true
|
||||
), "We should eventually end up in the defined callback", 1000
|
||||
|
||||
# The final test behavior, after waitsFor() finishes waiting.
|
||||
runs ->
|
||||
expect(inDefineCallback).toBeTruthy()
|
||||
expect(inRequireCallback).toBeTruthy()
|
||||
|
||||
|
||||
@@ -32,8 +32,18 @@ $ ->
|
||||
|
||||
$('#login').click ->
|
||||
$('#login_form input[name="email"]').focus()
|
||||
_gaq.push(['_trackPageview', '/login'])
|
||||
false
|
||||
|
||||
$('#signup').click ->
|
||||
$('#signup-modal input[name="email"]').focus()
|
||||
_gaq.push(['_trackPageview', '/signup'])
|
||||
false
|
||||
|
||||
# fix for ie
|
||||
if !Array::indexOf
|
||||
Array::indexOf = (obj, start = 0) ->
|
||||
for ele, i in this[start..]
|
||||
if ele is obj
|
||||
return i + start
|
||||
return -1
|
||||
|
||||
13
lms/static/coffee/src/peer_grading/peer_grading.coffee
Normal file
@@ -0,0 +1,13 @@
|
||||
# This is a simple class that just hides the error container
|
||||
# and message container when they are empty
|
||||
# Can (and should be) expanded upon when our problem list
|
||||
# becomes more sophisticated
|
||||
class PeerGrading
|
||||
constructor: () ->
|
||||
@error_container = $('.error-container')
|
||||
@error_container.toggle(not @error_container.is(':empty'))
|
||||
|
||||
@message_container = $('.message-container')
|
||||
@message_container.toggle(not @message_container.is(':empty'))
|
||||
|
||||
$(document).ready(() -> new PeerGrading())
|
||||
390
lms/static/coffee/src/peer_grading/peer_grading_problem.coffee
Normal file
@@ -0,0 +1,390 @@
|
||||
##################################
|
||||
#
|
||||
# This is the JS that renders the peer grading problem page.
|
||||
# Fetches the correct problem and/or calibration essay
|
||||
# and sends back the grades
|
||||
#
|
||||
# Should not be run when we don't have a location to send back
|
||||
# to the server
|
||||
#
|
||||
# PeerGradingProblemBackend -
|
||||
# makes all the ajax requests and provides a mock interface
|
||||
# for testing purposes
|
||||
#
|
||||
# PeerGradingProblem -
|
||||
# handles the rendering and user interactions with the interface
|
||||
#
|
||||
##################################
|
||||
class PeerGradingProblemBackend
|
||||
constructor: (ajax_url, mock_backend) ->
|
||||
@mock_backend = mock_backend
|
||||
@ajax_url = ajax_url
|
||||
@mock_cnt = 0
|
||||
|
||||
post: (cmd, data, callback) ->
|
||||
if @mock_backend
|
||||
callback(@mock(cmd, data))
|
||||
else
|
||||
# if this post request fails, the error callback will catch it
|
||||
$.post(@ajax_url + cmd, data, callback)
|
||||
.error => callback({success: false, error: "Error occured while performing this operation"})
|
||||
|
||||
mock: (cmd, data) ->
|
||||
if cmd == 'is_student_calibrated'
|
||||
# change to test each version
|
||||
response =
|
||||
success: true
|
||||
calibrated: @mock_cnt >= 2
|
||||
else if cmd == 'show_calibration_essay'
|
||||
#response =
|
||||
# success: false
|
||||
# error: "There was an error"
|
||||
@mock_cnt++
|
||||
response =
|
||||
success: true
|
||||
submission_id: 1
|
||||
submission_key: 'abcd'
|
||||
student_response: '''
|
||||
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.
|
||||
|
||||
The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.
|
||||
'''
|
||||
prompt: '''
|
||||
<h2>S11E3: Metal Bands</h2>
|
||||
<p>Shown below are schematic band diagrams for two different metals. Both diagrams appear different, yet both of the elements are undisputably metallic in nature.</p>
|
||||
<p>* Why is it that both sodium and magnesium behave as metals, even though the s-band of magnesium is filled? </p>
|
||||
<p>This is a self-assessed open response question. Please use as much space as you need in the box below to answer the question.</p>
|
||||
'''
|
||||
rubric: '''
|
||||
<ul>
|
||||
<li>Metals tend to be good electronic conductors, meaning that they have a large number of electrons which are able to access empty (mobile) energy states within the material.</li>
|
||||
<li>Sodium has a half-filled s-band, so there are a number of empty states immediately above the highest occupied energy levels within the band.</li>
|
||||
<li>Magnesium has a full s-band, but the the s-band and p-band overlap in magnesium. Thus are still a large number of available energy states immediately above the s-band highest occupied energy level.</li>
|
||||
</ul>
|
||||
|
||||
<p>Please score your response according to how many of the above components you identified:</p>
|
||||
'''
|
||||
max_score: 4
|
||||
else if cmd == 'get_next_submission'
|
||||
response =
|
||||
success: true
|
||||
submission_id: 1
|
||||
submission_key: 'abcd'
|
||||
student_response: '''Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec tristique ante. Proin at mauris sapien, quis varius leo. Morbi laoreet leo nisi. Morbi aliquam lacus ante. Cras iaculis velit sed diam mattis a fermentum urna luctus. Duis consectetur nunc vitae felis facilisis eget vulputate risus viverra. Cras consectetur ullamcorper lobortis. Nam eu gravida lorem. Nulla facilisi. Nullam quis felis enim. Mauris orci lectus, dictum id cursus in, vulputate in massa.
|
||||
|
||||
Phasellus non varius sem. Nullam commodo lacinia odio sit amet egestas. Donec ullamcorper sapien sagittis arcu volutpat placerat. Phasellus ut pretium ante. Nam dictum pulvinar nibh dapibus tristique. Sed at tellus mi, fringilla convallis justo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tristique rutrum nulla sed eleifend. Praesent at nunc arcu. Mauris condimentum faucibus nibh, eget commodo quam viverra sed. Morbi in tincidunt dolor. Morbi sed augue et augue interdum fermentum.
|
||||
|
||||
Curabitur tristique purus ac arcu consequat cursus. Cras diam felis, dignissim quis placerat at, aliquet ac metus. Mauris vulputate est eu nibh imperdiet varius. Cras aliquet rhoncus elit a laoreet. Mauris consectetur erat et erat scelerisque eu faucibus dolor consequat. Nam adipiscing sagittis nisl, eu mollis massa tempor ac. Nulla scelerisque tempus blandit. Phasellus ac ipsum eros, id posuere arcu. Nullam non sapien arcu. Vivamus sit amet lorem justo, ac tempus turpis. Suspendisse pharetra gravida imperdiet. Pellentesque lacinia mi eu elit luctus pellentesque. Sed accumsan libero a magna elementum varius. Nunc eget pellentesque metus. '''
|
||||
prompt: '''
|
||||
<h2>S11E3: Metal Bands</h2>
|
||||
<p>Shown below are schematic band diagrams for two different metals. Both diagrams appear different, yet both of the elements are undisputably metallic in nature.</p>
|
||||
<p>* Why is it that both sodium and magnesium behave as metals, even though the s-band of magnesium is filled? </p>
|
||||
<p>This is a self-assessed open response question. Please use as much space as you need in the box below to answer the question.</p>
|
||||
'''
|
||||
rubric: '''
|
||||
<ul>
|
||||
<li>Metals tend to be good electronic conductors, meaning that they have a large number of electrons which are able to access empty (mobile) energy states within the material.</li>
|
||||
<li>Sodium has a half-filled s-band, so there are a number of empty states immediately above the highest occupied energy levels within the band.</li>
|
||||
<li>Magnesium has a full s-band, but the the s-band and p-band overlap in magnesium. Thus are still a large number of available energy states immediately above the s-band highest occupied energy level.</li>
|
||||
</ul>
|
||||
|
||||
<p>Please score your response according to how many of the above components you identified:</p>
|
||||
'''
|
||||
max_score: 4
|
||||
else if cmd == 'save_calibration_essay'
|
||||
response =
|
||||
success: true
|
||||
actual_score: 2
|
||||
else if cmd == 'save_grade'
|
||||
response =
|
||||
success: true
|
||||
|
||||
return response
|
||||
|
||||
|
||||
class PeerGradingProblem
|
||||
constructor: (backend) ->
|
||||
@prompt_wrapper = $('.prompt-wrapper')
|
||||
@backend = backend
|
||||
|
||||
|
||||
# get the location of the problem
|
||||
@location = $('.peer-grading').data('location')
|
||||
# prevent this code from trying to run
|
||||
# when we don't have a location
|
||||
if(!@location)
|
||||
return
|
||||
|
||||
# get the other elements we want to fill in
|
||||
@submission_container = $('.submission-container')
|
||||
@prompt_container = $('.prompt-container')
|
||||
@rubric_container = $('.rubric-container')
|
||||
@calibration_panel = $('.calibration-panel')
|
||||
@grading_panel = $('.grading-panel')
|
||||
@content_panel = $('.content-panel')
|
||||
@grading_message = $('.grading-message')
|
||||
@grading_message.hide()
|
||||
|
||||
@grading_wrapper =$('.grading-wrapper')
|
||||
@calibration_feedback_panel = $('.calibration-feedback')
|
||||
@interstitial_page = $('.interstitial-page')
|
||||
@interstitial_page.hide()
|
||||
|
||||
@error_container = $('.error-container')
|
||||
|
||||
@submission_key_input = $("input[name='submission-key']")
|
||||
@essay_id_input = $("input[name='essay-id']")
|
||||
@feedback_area = $('.feedback-area')
|
||||
|
||||
@score_selection_container = $('.score-selection-container')
|
||||
@score = null
|
||||
@calibration = null
|
||||
|
||||
@submit_button = $('.submit-button')
|
||||
@action_button = $('.action-button')
|
||||
@calibration_feedback_button = $('.calibration-feedback-button')
|
||||
@interstitial_page_button = $('.interstitial-page-button')
|
||||
|
||||
Collapsible.setCollapsibles(@content_panel)
|
||||
|
||||
# Set up the click event handlers
|
||||
@action_button.click -> history.back()
|
||||
@calibration_feedback_button.click =>
|
||||
@calibration_feedback_panel.hide()
|
||||
@grading_wrapper.show()
|
||||
@is_calibrated_check()
|
||||
|
||||
@interstitial_page_button.click =>
|
||||
@interstitial_page.hide()
|
||||
@is_calibrated_check()
|
||||
|
||||
@is_calibrated_check()
|
||||
|
||||
|
||||
##########
|
||||
#
|
||||
# Ajax calls to the backend
|
||||
#
|
||||
##########
|
||||
is_calibrated_check: () =>
|
||||
@backend.post('is_student_calibrated', {location: @location}, @calibration_check_callback)
|
||||
|
||||
fetch_calibration_essay: () =>
|
||||
@backend.post('show_calibration_essay', {location: @location}, @render_calibration)
|
||||
|
||||
fetch_submission_essay: () =>
|
||||
@backend.post('get_next_submission', {location: @location}, @render_submission)
|
||||
|
||||
construct_data: () ->
|
||||
data =
|
||||
score: @score
|
||||
location: @location
|
||||
submission_id: @essay_id_input.val()
|
||||
submission_key: @submission_key_input.val()
|
||||
feedback: @feedback_area.val()
|
||||
return data
|
||||
|
||||
|
||||
submit_calibration_essay: ()=>
|
||||
data = @construct_data()
|
||||
@backend.post('save_calibration_essay', data, @calibration_callback)
|
||||
|
||||
submit_grade: () =>
|
||||
data = @construct_data()
|
||||
@backend.post('save_grade', data, @submission_callback)
|
||||
|
||||
|
||||
##########
|
||||
#
|
||||
# Callbacks for various events
|
||||
#
|
||||
##########
|
||||
|
||||
# called after we perform an is_student_calibrated check
|
||||
calibration_check_callback: (response) =>
|
||||
if response.success
|
||||
# if we haven't been calibrating before
|
||||
if response.calibrated and (@calibration == null or @calibration == false)
|
||||
@calibration = false
|
||||
@fetch_submission_essay()
|
||||
# If we were calibrating before and no longer need to,
|
||||
# show the interstitial page
|
||||
else if response.calibrated and @calibration == true
|
||||
@calibration = false
|
||||
@render_interstitial_page()
|
||||
else
|
||||
@calibration = true
|
||||
@fetch_calibration_essay()
|
||||
else if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@render_error("Error contacting the grading service")
|
||||
|
||||
|
||||
# called after we submit a calibration score
|
||||
calibration_callback: (response) =>
|
||||
if response.success
|
||||
@render_calibration_feedback(response)
|
||||
else if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@render_error("Error saving calibration score")
|
||||
|
||||
# called after we submit a submission score
|
||||
submission_callback: (response) =>
|
||||
if response.success
|
||||
@is_calibrated_check()
|
||||
@grading_message.fadeIn()
|
||||
@grading_message.html("<p>Grade sent successfully.</p>")
|
||||
else
|
||||
if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@render_error("Error occurred while submitting grade")
|
||||
|
||||
# called after a grade is selected on the interface
|
||||
graded_callback: (event) =>
|
||||
@grading_message.hide()
|
||||
@score = event.target.value
|
||||
@show_submit_button()
|
||||
|
||||
|
||||
|
||||
##########
|
||||
#
|
||||
# Rendering methods and helpers
|
||||
#
|
||||
##########
|
||||
# renders a calibration essay
|
||||
render_calibration: (response) =>
|
||||
if response.success
|
||||
|
||||
# load in all the data
|
||||
@submission_container.html("<h3>Training Essay</h3>")
|
||||
@render_submission_data(response)
|
||||
# TODO: indicate that we're in calibration mode
|
||||
@calibration_panel.addClass('current-state')
|
||||
@grading_panel.removeClass('current-state')
|
||||
|
||||
# Display the right text
|
||||
# both versions of the text are written into the template itself
|
||||
# we only need to show/hide the correct ones at the correct time
|
||||
@calibration_panel.find('.calibration-text').show()
|
||||
@grading_panel.find('.calibration-text').show()
|
||||
@calibration_panel.find('.grading-text').hide()
|
||||
@grading_panel.find('.grading-text').hide()
|
||||
|
||||
|
||||
@submit_button.unbind('click')
|
||||
@submit_button.click @submit_calibration_essay
|
||||
|
||||
else if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@render_error("An error occurred while retrieving the next calibration essay")
|
||||
|
||||
# Renders a student submission to be graded
|
||||
render_submission: (response) =>
|
||||
if response.success
|
||||
@submit_button.hide()
|
||||
@submission_container.html("<h3>Submitted Essay</h3>")
|
||||
@render_submission_data(response)
|
||||
|
||||
@calibration_panel.removeClass('current-state')
|
||||
@grading_panel.addClass('current-state')
|
||||
|
||||
# Display the correct text
|
||||
# both versions of the text are written into the template itself
|
||||
# we only need to show/hide the correct ones at the correct time
|
||||
@calibration_panel.find('.calibration-text').hide()
|
||||
@grading_panel.find('.calibration-text').hide()
|
||||
@calibration_panel.find('.grading-text').show()
|
||||
@grading_panel.find('.grading-text').show()
|
||||
|
||||
@submit_button.unbind('click')
|
||||
@submit_button.click @submit_grade
|
||||
else if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@render_error("An error occured when retrieving the next submission.")
|
||||
|
||||
|
||||
make_paragraphs: (text) ->
|
||||
paragraph_split = text.split(/\n\s*\n/)
|
||||
new_text = ''
|
||||
for paragraph in paragraph_split
|
||||
new_text += "<p>#{paragraph}</p>"
|
||||
return new_text
|
||||
|
||||
# render common information between calibration and grading
|
||||
render_submission_data: (response) =>
|
||||
@content_panel.show()
|
||||
|
||||
@submission_container.append(@make_paragraphs(response.student_response))
|
||||
@prompt_container.html(response.prompt)
|
||||
@rubric_container.html(response.rubric)
|
||||
@submission_key_input.val(response.submission_key)
|
||||
@essay_id_input.val(response.submission_id)
|
||||
@setup_score_selection(response.max_score)
|
||||
|
||||
@submit_button.hide()
|
||||
@action_button.hide()
|
||||
@calibration_feedback_panel.hide()
|
||||
|
||||
|
||||
render_calibration_feedback: (response) =>
|
||||
# display correct grade
|
||||
@calibration_feedback_panel.slideDown()
|
||||
calibration_wrapper = $('.calibration-feedback-wrapper')
|
||||
calibration_wrapper.html("<p>The score you gave was: #{@score}. The actual score is: #{response.actual_score}</p>")
|
||||
|
||||
|
||||
score = parseInt(@score)
|
||||
actual_score = parseInt(response.actual_score)
|
||||
|
||||
if score == actual_score
|
||||
calibration_wrapper.append("<p>Congratulations! Your score matches the actual score!</p>")
|
||||
else
|
||||
calibration_wrapper.append("<p>Please try to understand the grading critera better to be more accurate next time.</p>")
|
||||
|
||||
# disable score selection and submission from the grading interface
|
||||
$("input[name='score-selection']").attr('disabled', true)
|
||||
@submit_button.hide()
|
||||
|
||||
render_interstitial_page: () =>
|
||||
@content_panel.hide()
|
||||
@interstitial_page.show()
|
||||
|
||||
render_error: (error_message) =>
|
||||
@error_container.show()
|
||||
@calibration_feedback_panel.hide()
|
||||
@error_container.html(error_message)
|
||||
@content_panel.hide()
|
||||
@action_button.show()
|
||||
|
||||
show_submit_button: () =>
|
||||
@submit_button.show()
|
||||
|
||||
setup_score_selection: (max_score) =>
|
||||
# first, get rid of all the old inputs, if any.
|
||||
@score_selection_container.html('Choose score: ')
|
||||
|
||||
# Now create new labels and inputs for each possible score.
|
||||
for score in [0..max_score]
|
||||
id = 'score-' + score
|
||||
label = """<label for="#{id}">#{score}</label>"""
|
||||
|
||||
input = """
|
||||
<input type="radio" name="score-selection" id="#{id}" value="#{score}"/>
|
||||
""" # " fix broken parsing in emacs
|
||||
@score_selection_container.append(input + label)
|
||||
|
||||
# And now hook up an event handler again
|
||||
$("input[name='score-selection']").change @graded_callback
|
||||
|
||||
|
||||
|
||||
mock_backend = false
|
||||
ajax_url = $('.peer-grading').data('ajax_url')
|
||||
backend = new PeerGradingProblemBackend(ajax_url, mock_backend)
|
||||
$(document).ready(() -> new PeerGradingProblem(backend))
|
||||
BIN
lms/static/files/edx-identity.zip
Normal file
BIN
lms/static/images/logo-edx-support.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
lms/static/images/press-kit/3.091x_high-res.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
lms/static/images/press-kit/3.091x_x200.jpg
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
lms/static/images/press-kit/6.002x_high-res.png
Executable file
|
After Width: | Height: | Size: 156 KiB |
BIN
lms/static/images/press-kit/6.002x_x200.jpg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
@@ -0,0 +1 @@
|
||||
b154ce99fb5c8d413ba769e8cc0df94ed674c3f4
|
||||
BIN
lms/static/images/press-kit/anant-agarwal_x200.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1 @@
|
||||
2b8c58b098bdb17f9ddcbb2098f94c50fdcedf60
|
||||
BIN
lms/static/images/press-kit/anant-tablet_x200.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1 @@
|
||||
7d8b9879f7e5b859910edba7249661eedd3fcf37
|
||||
BIN
lms/static/images/press-kit/edx-video-editing_x200.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1 @@
|
||||
caf8b43337faa75cef5da5cd090010215a67b1bd
|
||||
BIN
lms/static/images/press-kit/piotr-mitros_x200.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -23,6 +23,7 @@
|
||||
@import 'multicourse/courses';
|
||||
@import 'multicourse/course_about';
|
||||
@import 'multicourse/jobs';
|
||||
@import 'multicourse/media-kit';
|
||||
@import 'multicourse/about_pages';
|
||||
@import 'multicourse/press_release';
|
||||
@import 'multicourse/password_reset';
|
||||
|
||||
@@ -2,6 +2,5 @@
|
||||
// content-box | border-box | inherit
|
||||
-webkit-box-sizing: $box;
|
||||
-moz-box-sizing: $box;
|
||||
box-sizing: $box;
|
||||
box-sizing: $box; *behavior: url(/static/scripts/boxsizing.htc);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
div.staff-grading {
|
||||
div.staff-grading,
|
||||
div.peer-grading{
|
||||
textarea.feedback-area {
|
||||
height: 75px;
|
||||
margin: 20px;
|
||||
@@ -36,8 +37,8 @@ div.staff-grading {
|
||||
}
|
||||
|
||||
.prompt-information-container,
|
||||
.submission-wrapper,
|
||||
.rubric-wrapper,
|
||||
.calibration-feedback-wrapper,
|
||||
.grading-container
|
||||
{
|
||||
border: 1px solid gray;
|
||||
@@ -49,6 +50,18 @@ div.staff-grading {
|
||||
padding: 15px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
.submission-wrapper
|
||||
{
|
||||
h3
|
||||
{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p
|
||||
{
|
||||
margin-left:10px;
|
||||
}
|
||||
padding: 15px;
|
||||
}
|
||||
.meta-info-wrapper
|
||||
{
|
||||
background-color: #eee;
|
||||
@@ -67,7 +80,8 @@ div.staff-grading {
|
||||
}
|
||||
}
|
||||
}
|
||||
.message-container
|
||||
.message-container,
|
||||
.grading-message
|
||||
{
|
||||
background-color: $yellow;
|
||||
padding: 10px;
|
||||
@@ -81,6 +95,69 @@ div.staff-grading {
|
||||
margin-bottom:5px;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.instructions-panel
|
||||
{
|
||||
|
||||
margin-right:20px;
|
||||
> div
|
||||
{
|
||||
padding: 10px;
|
||||
margin: 0px;
|
||||
background: #eee;
|
||||
height: 10em;
|
||||
h3
|
||||
{
|
||||
text-align:center;
|
||||
text-transform:uppercase;
|
||||
color: #777;
|
||||
}
|
||||
p
|
||||
{
|
||||
color: #777;
|
||||
}
|
||||
}
|
||||
.calibration-panel
|
||||
{
|
||||
float:left;
|
||||
width:48%;
|
||||
}
|
||||
.grading-panel
|
||||
{
|
||||
float:right;
|
||||
width: 48%;
|
||||
}
|
||||
.current-state
|
||||
{
|
||||
background: #1D9DD9;
|
||||
h3, p
|
||||
{
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
|
||||
.collapsible
|
||||
{
|
||||
margin-left: 0px;
|
||||
header
|
||||
{
|
||||
margin-top:20px;
|
||||
margin-bottom:20px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.interstitial-page
|
||||
{
|
||||
text-align: center;
|
||||
input[type=button]
|
||||
{
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
|
||||
@@ -336,6 +336,7 @@
|
||||
border-bottom: 1px solid rgb(200,200,200);
|
||||
@include clearfix;
|
||||
padding: 10px 20px 8px;
|
||||
position: relative;
|
||||
|
||||
h2 {
|
||||
float: left;
|
||||
@@ -343,16 +344,27 @@
|
||||
text-shadow: 0 1px rgba(255,255,255, 0.6);
|
||||
}
|
||||
|
||||
a {
|
||||
color: $lighter-base-font-color;
|
||||
.action.action-mediakit {
|
||||
float: right;
|
||||
font-style: italic;
|
||||
font-family: $serif;
|
||||
padding-top: 3px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
font-family: $sans-serif;
|
||||
font-size: 14px;
|
||||
text-shadow: 0 1px rgba(255,255,255, 0.6);
|
||||
|
||||
&:hover {
|
||||
color: $base-font-color;
|
||||
&:after {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
display: inline-block;
|
||||
margin: 0 0 0 5px;
|
||||
content: "➤";
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.org-name {
|
||||
color: $blue;
|
||||
font-family: $sans-serif;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
260
lms/static/sass/multicourse/_media-kit.scss
Normal file
@@ -0,0 +1,260 @@
|
||||
// vars
|
||||
$baseline: 20px;
|
||||
$white: rgb(255,255,255);
|
||||
|
||||
.mediakit {
|
||||
@include box-sizing(border-box);
|
||||
margin: 0 auto;
|
||||
padding: ($baseline*3) 0;
|
||||
width: 980px;
|
||||
|
||||
.wrapper-mediakit {
|
||||
@include border-radius(4px);
|
||||
@include box-sizing(border-box);
|
||||
@include box-shadow(0 1px 10px 0 rgba(0,0,0, 0.1));
|
||||
margin: ($baseline*3) 0 0 0;
|
||||
border: 1px solid $border-color;
|
||||
padding: ($baseline*2) ($baseline*3);
|
||||
|
||||
> section {
|
||||
margin: 0 0 ($baseline*2) 0;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
header {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 $baseline 0;
|
||||
position: relative;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
hr {
|
||||
@extend .faded-hr-divider-light;
|
||||
border: none;
|
||||
margin: 0px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
&::after {
|
||||
@extend .faded-hr-divider;
|
||||
bottom: 0px;
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
// general
|
||||
a.action-download {
|
||||
position: relative;
|
||||
color: $blue;
|
||||
font-family: $sans-serif;
|
||||
text-decoration: none;
|
||||
@include transition(all, 0.1s, linear);
|
||||
|
||||
.note {
|
||||
position: relative;
|
||||
color: $blue;
|
||||
font-family: $sans-serif;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
@include transition(all, 0.1s, linear);
|
||||
|
||||
&:before {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
margin: 0 5px 0 0;
|
||||
content: "➤";
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
.note {
|
||||
color: shade($blue, 25%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// introduction section
|
||||
.introduction {
|
||||
@include clearfix();
|
||||
|
||||
header {
|
||||
margin: 0 0 ($baseline*1.5) 0;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
color: rgb(178, 181, 185);
|
||||
font-size: 32px;
|
||||
|
||||
.org-name {
|
||||
color: rgb(178, 181, 185);
|
||||
font-family: $serif;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
article {
|
||||
@include box-sizing(border-box);
|
||||
width: 500px;
|
||||
margin-right: $baseline;
|
||||
float: left;
|
||||
}
|
||||
|
||||
aside {
|
||||
@include border-radius(2px);
|
||||
@include box-sizing(border-box);
|
||||
@include box-shadow(0 1px 4px 0 rgba(0,0,0, 0.2));
|
||||
width: 330px;
|
||||
float: left;
|
||||
border: 3px solid tint(rgb(96, 155, 216), 35%);
|
||||
background: tint(rgb(96, 155, 216), 35%);
|
||||
|
||||
h3 {
|
||||
padding: ($baseline/2) ($baseline*0.75);
|
||||
font-family: $sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
letter-spacing: 0;
|
||||
color: $white;
|
||||
text-transform: uppercase;
|
||||
|
||||
.org-name {
|
||||
color: $white !important;
|
||||
font-weight: bold;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
a.action-download {
|
||||
|
||||
.note {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
figure {
|
||||
@include box-sizing(border-box);
|
||||
background: $white;
|
||||
width: 100%;
|
||||
|
||||
figcaption {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: ($baseline/2);
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// library section
|
||||
.library {
|
||||
@include border-radius(2px);
|
||||
@include box-sizing(border-box);
|
||||
@include box-shadow(0 1px 4px 0 rgba(0,0,0, 0.2));
|
||||
border: 3px solid tint($light-gray,50%);
|
||||
padding: 0;
|
||||
background: tint($light-gray,50%);
|
||||
|
||||
header {
|
||||
padding: ($baseline*0.75) $baseline;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: $dark-gray;
|
||||
font-size: 16px;
|
||||
font-family: $sans-serif;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0;
|
||||
|
||||
.org-name {
|
||||
color: $dark-gray !important;
|
||||
font-weight: bold;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.listing {
|
||||
@include clearfix();
|
||||
background: $white;
|
||||
margin: 0;
|
||||
padding: ($baseline*2);
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
@include box-sizing(border-box);
|
||||
overflow-y: auto;
|
||||
float: left;
|
||||
width: 350px;
|
||||
margin: 0 0 $baseline 0;
|
||||
|
||||
&:nth-child(odd) {
|
||||
margin-right: ($baseline*3.5);
|
||||
}
|
||||
}
|
||||
|
||||
figure {
|
||||
|
||||
a {
|
||||
@include border-radius(2px);
|
||||
@include box-sizing(border-box);
|
||||
@include box-shadow(0 1px 2px 0 rgba(0,0,0, 0.1));
|
||||
display: block;
|
||||
min-height: 380px;
|
||||
border: 2px solid tint($light-gray,75%);
|
||||
padding: $baseline;
|
||||
|
||||
&:hover {
|
||||
border-color: $blue;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
border: 2px solid tint($light-gray,80%);
|
||||
margin: 0 auto ($baseline*0.75) auto;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.note {
|
||||
display: inline-block;
|
||||
margin-top: ($baseline/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// share
|
||||
.share {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,10 @@
|
||||
color: $base-font-color;
|
||||
font: normal 1em/1.6em $serif;
|
||||
margin: 0px;
|
||||
|
||||
a {
|
||||
font: 1em $serif;
|
||||
}
|
||||
}
|
||||
|
||||
li + li {
|
||||
|
||||
@@ -13,6 +13,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
.courses-listing {
|
||||
@include clearfix();
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
.courses-listing-item {
|
||||
width: flex-grid(4);
|
||||
margin-right: flex-gutter();
|
||||
float: left;
|
||||
|
||||
&:nth-child(3n+3) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.course {
|
||||
background: rgb(250,250,250);
|
||||
border: 1px solid rgb(180,180,180);
|
||||
@@ -24,6 +41,31 @@
|
||||
width: 100%;
|
||||
@include transition(all, 0.15s, linear);
|
||||
|
||||
.status {
|
||||
background: $blue;
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
left: 10px;
|
||||
padding: 2px 10px;
|
||||
@include border-radius(2px);
|
||||
position: absolute;
|
||||
text-transform: uppercase;
|
||||
top: -6px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.status:after {
|
||||
border-bottom: 6px solid shade($blue, 50%);
|
||||
border-right: 6px solid transparent;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,10 @@ function update(){
|
||||
}
|
||||
resizetimeout = window.setTimeout(function(){
|
||||
restore();
|
||||
init();
|
||||
try {
|
||||
init();
|
||||
}
|
||||
catch (err) {}
|
||||
resizetimeout = null;
|
||||
},100);
|
||||
}
|
||||
|
||||