diff --git a/cms/djangoapps/contentstore/features/advanced-settings.feature b/cms/djangoapps/contentstore/features/advanced-settings.feature
index db7294c14c..558294e890 100644
--- a/cms/djangoapps/contentstore/features/advanced-settings.feature
+++ b/cms/djangoapps/contentstore/features/advanced-settings.feature
@@ -21,8 +21,7 @@ Feature: Advanced (manual) course policy
Scenario: Test editing key value
Given I am on the Advanced Course Settings page in Studio
- When I edit the value of a policy key
- And I press the "Save" notification button
+ When I edit the value of a policy key and save
Then the policy key value is changed
And I reload the page
Then the policy key value is changed
diff --git a/cms/djangoapps/contentstore/features/advanced-settings.py b/cms/djangoapps/contentstore/features/advanced-settings.py
index 16562b6b15..6fb102faea 100644
--- a/cms/djangoapps/contentstore/features/advanced-settings.py
+++ b/cms/djangoapps/contentstore/features/advanced-settings.py
@@ -51,6 +51,11 @@ def edit_the_value_of_a_policy_key(step):
e._element.send_keys(Keys.TAB, Keys.END, Keys.ARROW_LEFT, ' ', 'X')
+@step(u'I edit the value of a policy key and save$')
+def edit_the_value_of_a_policy_key(step):
+ change_display_name_value(step, '"foo"')
+
+
@step('I create a JSON object as a value$')
def create_JSON_object(step):
change_display_name_value(step, '{"key": "value", "key_2": "value_2"}')
@@ -96,7 +101,7 @@ def the_policy_key_value_is_unchanged(step):
@step(u'the policy key value is changed$')
def the_policy_key_value_is_changed(step):
- assert_equal(get_display_name_value(), '"Robot Super Course X"')
+ assert_equal(get_display_name_value(), '"foo"')
############# HELPERS ###############
diff --git a/cms/djangoapps/contentstore/features/course-settings.py b/cms/djangoapps/contentstore/features/course-settings.py
index 9eb5b0951d..d69266b7de 100644
--- a/cms/djangoapps/contentstore/features/course-settings.py
+++ b/cms/djangoapps/contentstore/features/course-settings.py
@@ -18,8 +18,8 @@ COURSE_END_TIME_CSS = "#course-end-time"
ENROLLMENT_START_TIME_CSS = "#course-enrollment-start-time"
ENROLLMENT_END_TIME_CSS = "#course-enrollment-end-time"
-DUMMY_TIME = "3:30pm"
-DEFAULT_TIME = "12:00am"
+DUMMY_TIME = "15:30"
+DEFAULT_TIME = "00:00"
############### ACTIONS ####################
diff --git a/cms/djangoapps/contentstore/features/section.py b/cms/djangoapps/contentstore/features/section.py
index fca14e21f0..59c5a37b33 100644
--- a/cms/djangoapps/contentstore/features/section.py
+++ b/cms/djangoapps/contentstore/features/section.py
@@ -38,7 +38,7 @@ def i_click_the_edit_link_for_the_release_date(step):
@step('I save a new section release date$')
def i_save_a_new_section_release_date(step):
set_date_and_time('input.start-date.date.hasDatepicker', '12/25/2013',
- 'input.start-time.time.ui-timepicker-input', '12:00am')
+ 'input.start-time.time.ui-timepicker-input', '00:00')
world.browser.click_link_by_text('Save')
@@ -105,7 +105,7 @@ def the_section_release_date_picker_not_visible(step):
def the_section_release_date_is_updated(step):
css = 'span.published-status'
status_text = world.css_text(css)
- assert_equal(status_text, 'Will Release: 12/25/2013 at 12:00am')
+ assert_equal(status_text, 'Will Release: 12/25/2013 at 00:00 UTC')
############ HELPER METHODS ###################
diff --git a/cms/djangoapps/contentstore/features/subsection.py b/cms/djangoapps/contentstore/features/subsection.py
index 1ec43e6971..f9e5b52bb2 100644
--- a/cms/djangoapps/contentstore/features/subsection.py
+++ b/cms/djangoapps/contentstore/features/subsection.py
@@ -57,18 +57,18 @@ def i_see_complete_subsection_name_with_quote_in_editor(step):
@step('I have set a release date and due date in different years$')
def test_have_set_dates_in_different_years(step):
- set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '3:00am')
+ set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '03:00')
world.css_click('.set-date')
# Use a year in the past so that current year will always be different.
- set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '4:00am')
+ set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '04:00')
@step('I see the correct dates$')
def i_see_the_correct_dates(step):
assert_equal('12/25/2011', world.css_find('input#start_date').first.value)
- assert_equal('3:00am', world.css_find('input#start_time').first.value)
+ assert_equal('03:00', world.css_find('input#start_time').first.value)
assert_equal('01/02/2012', world.css_find('input#due_date').first.value)
- assert_equal('4:00am', world.css_find('input#due_time').first.value)
+ assert_equal('04:00', world.css_find('input#due_time').first.value)
@step('I mark it as Homework$')
diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index 685867a1cb..ef6ab71b88 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -93,6 +93,69 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
return cnt
+ def test_draft_metadata(self):
+ '''
+ This verifies a bug we had where inherited metadata was getting written to the
+ module as 'own-metadata' when publishing. Also verifies the metadata inheritance is
+ properly computed
+ '''
+ store = modulestore()
+ draft_store = modulestore('draft')
+ import_from_xml(store, 'common/test/data/', ['simple'])
+
+ course = draft_store.get_item(Location(['i4x', 'edX', 'simple',
+ 'course', '2012_Fall', None]), depth=None)
+ html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
+
+ self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod)
+ self.assertNotIn('graceperiod', own_metadata(html_module))
+
+ draft_store.clone_item(html_module.location, html_module.location)
+
+ # refetch to check metadata
+ html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
+
+ self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod)
+ self.assertNotIn('graceperiod', own_metadata(html_module))
+
+ # publish module
+ draft_store.publish(html_module.location, 0)
+
+ # refetch to check metadata
+ html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
+
+ self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod)
+ self.assertNotIn('graceperiod', own_metadata(html_module))
+
+ # put back in draft and change metadata and see if it's now marked as 'own_metadata'
+ draft_store.clone_item(html_module.location, html_module.location)
+ html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
+
+ new_graceperiod = timedelta(**{'hours': 1})
+
+ self.assertNotIn('graceperiod', own_metadata(html_module))
+ html_module.lms.graceperiod = new_graceperiod
+ self.assertIn('graceperiod', own_metadata(html_module))
+ self.assertEqual(html_module.lms.graceperiod, new_graceperiod)
+
+ draft_store.update_metadata(html_module.location, own_metadata(html_module))
+
+ # read back to make sure it reads as 'own-metadata'
+ html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
+
+ self.assertIn('graceperiod', own_metadata(html_module))
+ self.assertEqual(html_module.lms.graceperiod, new_graceperiod)
+
+ # republish
+ draft_store.publish(html_module.location, 0)
+
+ # and re-read and verify 'own-metadata'
+ draft_store.clone_item(html_module.location, html_module.location)
+ html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None])
+
+ self.assertIn('graceperiod', own_metadata(html_module))
+ self.assertEqual(html_module.lms.graceperiod, new_graceperiod)
+
def test_get_depth_with_drafts(self):
import_from_xml(modulestore(), 'common/test/data/', ['simple'])
@@ -609,6 +672,113 @@ class ContentStoreTest(ModuleStoreTestCase):
self.assertIn('markdown', context, "markdown is missing from context")
self.assertNotIn('markdown', problem.editable_metadata_fields, "Markdown slipped into the editable metadata fields")
+ def test_cms_imported_course_walkthrough(self):
+ """
+ Import and walk through some common URL endpoints. This just verifies non-500 and no other
+ correct behavior, so it is not a deep test
+ """
+ import_from_xml(modulestore(), 'common/test/data/', ['simple'])
+ loc = Location(['i4x', 'edX', 'simple', 'course', '2012_Fall', None])
+ resp = self.client.get(reverse('course_index',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+
+ self.assertEqual(200, resp.status_code)
+ self.assertContains(resp, 'Chapter 2')
+
+ # go to various pages
+
+ # import page
+ resp = self.client.get(reverse('import_course',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # export page
+ resp = self.client.get(reverse('export_course',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # manage users
+ resp = self.client.get(reverse('manage_users',
+ kwargs={'location': loc.url()}))
+ self.assertEqual(200, resp.status_code)
+
+ # course info
+ resp = self.client.get(reverse('course_info',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # settings_details
+ resp = self.client.get(reverse('settings_details',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # settings_details
+ resp = self.client.get(reverse('settings_grading',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # static_pages
+ resp = self.client.get(reverse('static_pages',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'coursename': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # static_pages
+ resp = self.client.get(reverse('asset_index',
+ kwargs={'org': loc.org,
+ 'course': loc.course,
+ 'name': loc.name}))
+ self.assertEqual(200, resp.status_code)
+
+ # go look at a subsection page
+ subsection_location = loc._replace(category='sequential', name='test_sequence')
+ resp = self.client.get(reverse('edit_subsection',
+ kwargs={'location': subsection_location.url()}))
+ self.assertEqual(200, resp.status_code)
+
+ # go look at the Edit page
+ unit_location = loc._replace(category='vertical', name='test_vertical')
+ resp = self.client.get(reverse('edit_unit',
+ kwargs={'location': unit_location.url()}))
+ self.assertEqual(200, resp.status_code)
+
+ # delete a component
+ del_loc = loc._replace(category='html', name='test_html')
+ resp = self.client.post(reverse('delete_item'),
+ json.dumps({'id': del_loc.url()}), "application/json")
+ self.assertEqual(200, resp.status_code)
+
+ # delete a unit
+ del_loc = loc._replace(category='vertical', name='test_vertical')
+ resp = self.client.post(reverse('delete_item'),
+ json.dumps({'id': del_loc.url()}), "application/json")
+ self.assertEqual(200, resp.status_code)
+
+ # delete a unit
+ del_loc = loc._replace(category='sequential', name='test_sequence')
+ resp = self.client.post(reverse('delete_item'),
+ json.dumps({'id': del_loc.url()}), "application/json")
+ self.assertEqual(200, resp.status_code)
+
+ # delete a chapter
+ del_loc = loc._replace(category='chapter', name='chapter_2')
+ resp = self.client.post(reverse('delete_item'),
+ json.dumps({'id': del_loc.url()}), "application/json")
+ self.assertEqual(200, resp.status_code)
+
def test_import_metadata_with_attempts_empty_string(self):
import_from_xml(modulestore(), 'common/test/data/', ['simple'])
module_store = modulestore('direct')
diff --git a/cms/static/client_templates/checklist.html b/cms/static/client_templates/checklist.html
index ec6ff4e892..6884b0e9c9 100644
--- a/cms/static/client_templates/checklist.html
+++ b/cms/static/client_templates/checklist.html
@@ -44,7 +44,7 @@
<% if (item['action_text'] !== '' && item['action_url'] !== '') { %>
-
+
rel="external" title="This link will open in a new browser window/tab"
diff --git a/cms/static/js/base.js b/cms/static/js/base.js
index 7b930a176b..6a582a45a6 100644
--- a/cms/static/js/base.js
+++ b/cms/static/js/base.js
@@ -37,11 +37,11 @@ $(document).ready(function () {
$(this).select();
});
+ $('body').addClass('js');
+
$('.unit .item-actions .delete-button').bind('click', deleteUnit);
$('.new-unit-item').bind('click', createNewUnit);
- $('body').addClass('js');
-
// lean/simple modal
$('a[rel*=modal]').leanModal({overlay : 0.80, closeButton: '.action-modal-close' });
$('a.action-modal-close').click(function(e){
@@ -89,6 +89,9 @@ $(document).ready(function () {
// tender feedback window scrolling
$('a.show-tender').bind('click', smoothScrollTop);
+ // toggling footer additional support
+ $('.cta-show-sock').bind('click', toggleSock);
+
// toggling overview section details
$(function () {
if ($('.courseware-section').length > 0) {
@@ -470,6 +473,33 @@ function onKeyUp(e) {
}
}
+function toggleSock(e) {
+ e.preventDefault();
+
+ var $btnLabel = $(this).find('.copy');
+ var $sock = $('.wrapper-sock');
+ var $sockContent = $sock.find('.wrapper-inner');
+
+ $sock.toggleClass('is-shown');
+ $sockContent.toggle('fast');
+
+ $.smoothScroll({
+ offset: -200,
+ easing: 'swing',
+ speed: 1000,
+ scrollElement: null,
+ scrollTarget: $sock
+ });
+
+ if($sock.hasClass('is-shown')) {
+ $btnLabel.text('Hide Studio Help');
+ }
+
+ else {
+ $btnLabel.text('Looking for Help with Studio?');
+ }
+}
+
function toggleSubmodules(e) {
e.preventDefault();
$(this).toggleClass('expand').toggleClass('collapse');
@@ -796,7 +826,7 @@ function saveSetSectionScheduleDate(e) {
data: JSON.stringify({ 'id': id, 'metadata': {'start': start}})
}).success(function () {
var $thisSection = $('.courseware-section[data-id="' + id + '"]');
- $thisSection.find('.section-published-date').html('Will Release: ' + input_date + ' at ' + input_time + ' Edit ');
+ $thisSection.find('.section-published-date').html('Will Release: ' + input_date + ' at ' + input_time + ' UTCEdit ');
$thisSection.find('.section-published-date').animate({
'background-color': 'rgb(182,37,104)'
}, 300).animate({
diff --git a/cms/static/js/views/settings/main_settings_view.js b/cms/static/js/views/settings/main_settings_view.js
index 3e1690f0b6..5c7e605545 100644
--- a/cms/static/js/views/settings/main_settings_view.js
+++ b/cms/static/js/views/settings/main_settings_view.js
@@ -110,7 +110,7 @@ CMS.Views.Settings.Details = CMS.Views.ValidatingView.extend({
};
// instrument as date and time pickers
- timefield.timepicker();
+ timefield.timepicker({'timeFormat' : 'H:i'});
datefield.datepicker();
// Using the change event causes savefield to be triggered twice, but it is necessary
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index 5a9ac2f280..cda99b676c 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -22,7 +22,7 @@ body, input {
a {
text-decoration: none;
color: $blue;
- @include transition(color .15s);
+ @include transition(color 0.25s ease-in-out);
&:hover {
color: #cb9c40;
@@ -52,7 +52,6 @@ h1 {
// layout - basic page header
.wrapper-mast {
- margin: 0;
padding: 0 $baseline;
position: relative;
@@ -63,7 +62,7 @@ h1 {
max-width: $fg-max-width;
min-width: $fg-min-width;
width: flex-grid(12);
- margin: 0 auto $baseline auto;
+ margin: ($baseline*1.5) auto $baseline auto;
color: $gray-d2;
}
@@ -272,19 +271,17 @@ h1 {
}
.title-1 {
-
+ @extend .t-title-1;
}
.title-2 {
- @include font-size(24);
+ @extend .t-title-2;
margin: 0 0 ($baseline/2) 0;
- font-weight: 600;
}
.title-3 {
- @include font-size(16);
+ @extend .t-title-3;
margin: 0 0 ($baseline/2) 0;
- font-weight: 600;
}
.title-4 {
@@ -351,7 +348,7 @@ h1 {
// layout - grandfathered
.main-wrapper {
position: relative;
- margin: 40px;
+ margin: 0 ($baseline*2);
}
.inner-wrapper {
diff --git a/cms/static/sass/_cms_mixins.scss b/cms/static/sass/_cms_mixins.scss
index 015a94b762..a25a07cb73 100644
--- a/cms/static/sass/_cms_mixins.scss
+++ b/cms/static/sass/_cms_mixins.scss
@@ -1,6 +1,7 @@
// studio - utilities - mixins and extends
// ====================
+// mixins - utility
@mixin clearfix {
&:after {
content: '';
@@ -11,6 +12,7 @@
}
}
+// mixins - grandfathered
@mixin button {
display: inline-block;
padding: 4px 20px 6px;
@@ -110,6 +112,21 @@
}
}
+@mixin gray-button {
+ @include button;
+ border: 1px solid $gray-d1;
+ border-radius: 3px;
+ @include linear-gradient(top, $white-t1, rgba(255, 255, 255, 0));
+ background-color: $gray-d2;
+ @include box-shadow(0 1px 0 $white-t1 inset);
+ color: $gray-l3;
+
+ &:hover {
+ background-color: $gray-d3;
+ color: $white;
+ }
+}
+
@mixin green-button {
@include button;
border: 1px solid $darkGreen;
@@ -279,20 +296,97 @@
}
}
-@mixin sr-text {
- border: 0;
- clip: rect(0 0 0 0);
- height: 1px;
- margin: -1px;
- overflow: hidden;
- padding: 0;
- position: absolute;
- width: 1px;
-}
-
@mixin active {
@include linear-gradient(top, rgba(255, 255, 255, .4), rgba(255, 255, 255, 0));
background-color: rgba(255, 255, 255, .3);
@include box-shadow(0 -1px 0 rgba(0, 0, 0, .2) inset, 0 1px 0 #fff inset);
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-}
\ No newline at end of file
+}
+
+// ====================
+
+// extends - buttons
+.btn {
+ @include box-sizing(border-box);
+ @include transition(color 0.25s ease-in-out, border-color 0.25s ease-in-out, background 0.25s ease-in-out, box-shadow 0.25s ease-in-out);
+ display: inline-block;
+ cursor: pointer;
+
+ &:hover, &:active {
+
+ }
+
+ &.disabled, &[disabled] {
+ cursor: default;
+ pointer-events: none;
+ opacity: 0.5;
+ }
+
+ .icon-inline {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: ($baseline/4);
+ }
+}
+
+// pill button
+.btn-pill {
+ @include border-radius($baseline/5);
+}
+
+.btn-rounded {
+ @include border-radius($baseline/2);
+}
+
+// primary button
+.btn-primary {
+ @extend .btn;
+ @extend .btn-pill;
+ padding:($baseline/2) $baseline;
+ border-width: 1px;
+ border-style: solid;
+ line-height: 1.5em;
+ text-align: center;
+
+ &:hover, &:active {
+ @include box-shadow(0 2px 1px $shadow-l1);
+ }
+
+ &.current, &.active {
+ @include box-shadow(inset 1px 1px 2px $shadow-d1);
+
+ &:hover, &:active {
+ @include box-shadow(inset 1px 1px 1px $shadow-d1);
+ }
+ }
+}
+
+// secondary button
+.btn-secondary {
+ @extend .btn;
+ @extend .btn-pill;
+ border-width: 1px;
+ border-style: solid;
+ padding:($baseline/2) $baseline;
+ background: transparent;
+ line-height: 1.5em;
+ text-align: center;
+
+ &:hover, &:active {
+
+ }
+
+ &.current, &.active {
+
+ }
+}
+
+// ====================
+
+// extends - depth levels
+.depth0 { z-index: 0; }
+.depth1 { z-index: 10; }
+.depth2 { z-index: 100; }
+.depth3 { z-index: 1000; }
+.depth4 { z-index: 10000; }
+.depth5 { z-index: 100000; }
\ No newline at end of file
diff --git a/cms/static/sass/_reset.scss b/cms/static/sass/_reset.scss
index 87a6e51232..ee4e76e381 100644
--- a/cms/static/sass/_reset.scss
+++ b/cms/static/sass/_reset.scss
@@ -1,6 +1,7 @@
// studio - utilities - reset
// ====================
+// not ready for this yet, but this should be done as things get cleaner
// * {
// @include box-sizing(border-box);
// }
@@ -26,6 +27,10 @@ time, mark, audio, video {
vertical-align: baseline;
}
+html,body {
+ height: 100%;
+}
+
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
@@ -57,6 +62,12 @@ table {
border-spacing: 0;
}
+abbr[title] {
+ border-bottom: none;
+ text-decoration: none;
+ cursor: help;
+}
+
// ====================
// grandfathered styles
diff --git a/cms/static/sass/_variables.scss b/cms/static/sass/_variables.scss
index 3bac14fdf4..41c9e57d54 100644
--- a/cms/static/sass/_variables.scss
+++ b/cms/static/sass/_variables.scss
@@ -57,6 +57,10 @@ $blue-s3: saturate($blue,45%);
$blue-u1: desaturate($blue,15%);
$blue-u2: desaturate($blue,30%);
$blue-u3: desaturate($blue,45%);
+$blue-t0: rgba(85, 151, 221,0.125);
+$blue-t1: rgba(85, 151, 221,0.25);
+$blue-t2: rgba(85, 151, 221,0.50);
+$blue-t3: rgba(85, 151, 221,0.75);
$pink: rgb(183, 37, 103);
$pink-l1: tint($pink,20%);
@@ -148,7 +152,7 @@ $shadow-l1: rgba(0,0,0,0.1);
$shadow-d1: rgba(0,0,0,0.4);
// colors - inherited
-$baseFontColor: #3c3c3c;
+$baseFontColor: $gray-d2;
$offBlack: #3c3c3c;
$green: #108614;
$lightGrey: #edf1f5;
@@ -163,4 +167,4 @@ $disabledGreen: rgb(124, 206, 153);
$darkGreen: rgb(52, 133, 76);
$lightBluishGrey: rgb(197, 207, 223);
$lightBluishGrey2: rgb(213, 220, 228);
-$error-red: rgb(253, 87, 87);
+$error-red: rgb(253, 87, 87);
\ No newline at end of file
diff --git a/cms/static/sass/base-style.scss b/cms/static/sass/base-style.scss
index b9becc4829..1bf9329b36 100644
--- a/cms/static/sass/base-style.scss
+++ b/cms/static/sass/base-style.scss
@@ -21,9 +21,13 @@
@import 'base';
// elements
+@import 'elements/typography';
+@import 'elements/icons';
+@import 'elements/controls';
+@import 'elements/navigation';
@import 'elements/header';
@import 'elements/footer';
-@import 'elements/navigation';
+@import 'elements/sock';
@import 'elements/forms';
@import 'elements/modal';
@import 'elements/alerts';
diff --git a/cms/static/sass/elements/_controls.scss b/cms/static/sass/elements/_controls.scss
new file mode 100644
index 0000000000..c4e96616a8
--- /dev/null
+++ b/cms/static/sass/elements/_controls.scss
@@ -0,0 +1,143 @@
+// studio - elements - UI controls
+// ====================
+
+// gray primary button
+.btn-primary-gray {
+ @extend .btn-primary;
+ background: $gray-l1;
+ border-color: $gray-l2;
+ color: $white;
+
+ &:hover, &:active {
+ border-color: $gray-l1;
+ background: $gray;
+ }
+
+ &.current, &.active {
+ background: $gray-d1;
+ color: $gray-l1;
+
+ &:hover, &:active {
+ background: $gray-d1;
+ }
+ }
+}
+
+// blue primary button
+.btn-primary-blue {
+ @extend .btn-primary;
+ background: $blue;
+ border-color: $blue-s1;
+ color: $white;
+
+ &:hover, &:active {
+ background: $blue-s2;
+ border-color: $blue-s2;
+ }
+
+ &.current, &.active {
+ background: $blue-d1;
+ color: $blue-l4;
+ border-color: $blue-d2;
+
+ &:hover, &:active {
+ background: $blue-d1;
+ }
+ }
+}
+
+// green primary button
+.btn-primary-green {
+ @extend .btn-primary;
+ background: $green;
+ border-color: $green;
+ color: $white;
+
+ &:hover, &:active {
+ background: $green-s1;
+ border-color: $green-s1;
+ }
+
+ &.current, &.active {
+ background: $green-d1;
+ color: $green-l4;
+ border-color: $green-d2;
+
+ &:hover, &:active {
+ background: $green-d1;
+ }
+ }
+}
+
+// gray secondary button
+.btn-secondary-gray {
+ @extend .btn-secondary;
+ border-color: $gray-l3;
+ color: $gray-l1;
+
+ &:hover, &:active {
+ background: $gray-l3;
+ color: $gray-d2;
+ }
+
+ &.current, &.active {
+ background: $gray-d2;
+ color: $gray-l5;
+
+ &:hover, &:active {
+ background: $gray-d2;
+ }
+ }
+}
+
+// blue secondary button
+.btn-secondary-blue {
+ @extend .btn-secondary;
+ border-color: $blue-l3;
+ color: $blue;
+
+ &:hover, &:active {
+ background: $blue-l3;
+ color: $blue-s2;
+ }
+
+ &.current, &.active {
+ border-color: $blue-l3;
+ background: $blue-l3;
+ color: $blue-d1;
+
+ &:hover, &:active {
+
+ }
+ }
+}
+
+// green secondary button
+.btn-secondary-green {
+ @extend .btn-secondary;
+ border-color: $green-l4;
+ color: $green-l2;
+
+ &:hover, &:active {
+ background: $green-l4;
+ color: $green-s1;
+ }
+
+ &.current, &.active {
+ background: $green-s1;
+ color: $green-l4;
+
+ &:hover, &:active {
+ background: $green-s1;
+ }
+ }
+}
+
+// ====================
+
+// layout-based buttons
+
+// ====================
+
+// calls-to-action
+
diff --git a/cms/static/sass/elements/_footer.scss b/cms/static/sass/elements/_footer.scss
index b1c0f57bb2..75eb0c4070 100644
--- a/cms/static/sass/elements/_footer.scss
+++ b/cms/static/sass/elements/_footer.scss
@@ -2,10 +2,10 @@
// ====================
.wrapper-footer {
- margin: ($baseline*1.5) 0 $baseline 0;
- padding: $baseline;
position: relative;
width: 100%;
+ margin: 0 0 $baseline 0;
+ padding: $baseline;
footer.primary {
@include clearfix();
@@ -14,9 +14,7 @@
min-width: $fg-min-width;
width: flex-grid(12);
margin: 0 auto;
- padding-top: $baseline;
- border-top: 1px solid $gray-l4;
- color: $gray-l2;
+ color: $gray-l1;
.colophon {
width: flex-grid(4, 12);
@@ -24,6 +22,14 @@
margin-right: flex-gutter(2);
}
+ a {
+ color: $gray;
+
+ &:hover, &:active {
+ color: $gray-d2;
+ }
+ }
+
.nav-peripheral {
width: flex-grid(6, 12);
float: right;
@@ -36,14 +42,33 @@
&:last-child {
margin-right: 0;
}
- }
- }
- a {
- color: $gray-l1;
+ a {
+ @include border-radius(2px);
+ padding: ($baseline/2) ($baseline*0.75);
+ background: transparent;
- &:hover, &:active {
- color: $blue;
+ .ss-icon {
+ @include transition(top .25s ease-in-out .25s);
+ @include font-size(15);
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: ($baseline/4);
+ color: $gray-l1;
+ }
+
+ &:hover, &:active {
+ color: $gray-d2;
+
+ .ss-icon {
+ color: $gray-d2;
+ }
+ }
+
+ &.is-active {
+ color: $gray-d2;
+ }
+ }
}
}
}
diff --git a/cms/static/sass/elements/_header.scss b/cms/static/sass/elements/_header.scss
index b7fb381f2e..00e2963630 100644
--- a/cms/static/sass/elements/_header.scss
+++ b/cms/static/sass/elements/_header.scss
@@ -2,7 +2,7 @@
// ====================
.wrapper-header {
- margin: 0 0 ($baseline*1.5) 0;
+ margin: 0;
padding: $baseline;
border-bottom: 1px solid $gray;
@include box-shadow(0 1px 5px 0 rgba(0,0,0, 0.1));
diff --git a/cms/static/sass/elements/_icons.scss b/cms/static/sass/elements/_icons.scss
new file mode 100644
index 0000000000..2bc73d8b8d
--- /dev/null
+++ b/cms/static/sass/elements/_icons.scss
@@ -0,0 +1,16 @@
+// studio - elements - icons
+// ====================
+
+.icon {
+
+}
+
+.ss-icon {
+
+}
+
+.icon-inline {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: ($baseline/4);
+}
\ No newline at end of file
diff --git a/cms/static/sass/elements/_sock.scss b/cms/static/sass/elements/_sock.scss
new file mode 100644
index 0000000000..16148690c3
--- /dev/null
+++ b/cms/static/sass/elements/_sock.scss
@@ -0,0 +1,152 @@
+// studio - elements - support sock
+// ====================
+
+.wrapper-sock {
+ @include clearfix();
+ position: relative;
+ margin: ($baseline*2) 0 0 0;
+ border-top: 1px solid $gray-l4;
+ width: 100%;
+
+ .wrapper-inner {
+ @include linear-gradient($gray-d3 0%, $gray-d3 98%, $black 100%);
+ @extend .depth0;
+ display: none;
+ width: 100% !important;
+ border-bottom: 1px solid $white;
+ padding: 0 $baseline !important;
+ }
+
+ // sock - actions
+ .list-cta {
+ @extend .depth1;
+ position: absolute;
+ top: -($baseline*0.75);
+ width: 100%;
+ margin: 0 auto;
+ text-align: center;
+
+ .cta-show-sock {
+ @extend .btn-pill;
+ @extend .t-action3;
+ background: $gray-l5;
+ padding: ($baseline/2) $baseline;
+ color: $gray;
+
+ .icon {
+ @include font-size(16);
+ }
+
+ &:hover {
+ background: $blue;
+ color: $white;
+ }
+ }
+ }
+
+ // sock - additional help
+ .sock {
+ @include clearfix();
+ @extend .t-copy-sub2;
+ max-width: $fg-max-width;
+ min-width: $fg-min-width;
+ width: flex-grid(12);
+ margin: 0 auto;
+ padding: ($baseline*2) 0;
+ color: $gray-l3;
+
+ // support body
+ header {
+
+ .title {
+ @extend .t-title-2;
+ }
+
+ .ss-icon {
+ @extend .t-icon;
+ @extend .icon-inline;
+ }
+ }
+
+ // shared elements
+ .support, .feedback {
+ @include box-sizing(border-box);
+
+ .title {
+ @extend .t-title-3;
+ color: $white;
+ margin-bottom: ($baseline/2);
+ }
+
+ .copy {
+ margin: 0 0 $baseline 0;
+ }
+
+ .list-actions {
+ @include clearfix();
+
+ .action-item {
+ float: left;
+ margin-right: ($baseline/2);
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ .action {
+ display: block;
+
+ .icon {
+ @include font-size(18);
+ }
+
+ &:hover, &:active {
+
+ }
+ }
+
+ .tip {
+ @extend .sr;
+ }
+ }
+
+ .action-primary {
+ @extend .btn-primary-blue;
+ @extend .t-action3;
+ }
+ }
+ }
+
+ // studio support content
+ .support {
+ width: flex-grid(8,12);
+ float: left;
+ margin-right: flex-gutter();
+
+ .action-item {
+ width: flexgrid(4,8);
+ }
+ }
+
+ // studio feedback content
+ .feedback {
+ width: flex-grid(4,12);
+ float: left;
+
+ .action-item {
+ width: flexgrid(4,4);
+ }
+ }
+ }
+
+ // case: sock content is shown
+ &.is-shown {
+ border-color: $gray-d3;
+
+ .list-cta .cta-show-sock {
+ background: $gray-d3;
+ border-color: $gray-d3;
+ color: $white;
+ }
+ }
+}
\ No newline at end of file
diff --git a/cms/static/sass/elements/_typography.scss b/cms/static/sass/elements/_typography.scss
new file mode 100644
index 0000000000..32c4b3928b
--- /dev/null
+++ b/cms/static/sass/elements/_typography.scss
@@ -0,0 +1,85 @@
+// studio - elements - typography
+// ====================
+
+// headings/titles
+.t-title-1, .t-title-2, .t-title-3, .t-title-4, .t-title-5, .t-title-5 {
+ color: $gray-d3;
+}
+
+.t-title-1 {
+ @include font-size(36);
+}
+
+.t-title-2 {
+ @include font-size(24);
+ font-weight: 600;
+}
+
+.t-title-3 {
+ @include font-size(16);
+ font-weight: 600;
+}
+
+.t-title-4 {
+
+}
+
+.t-title-5 {
+
+}
+
+// ====================
+
+// copy
+.t-copy-base {
+ @include font-size(16);
+}
+
+.t-copy-lead1 {
+ @include font-size(18);
+}
+
+.t-copy-lead2 {
+ @include font-size(20);
+}
+
+.t-copy-sub1 {
+ @include font-size(14);
+}
+
+.t-copy-sub2 {
+ @include font-size(13);
+}
+
+.t-copy-sub3 {
+ @include font-size(12);
+}
+
+// ====================
+
+// actions/labels
+.t-action1 {
+ @include font-size(14);
+ font-weight: 600;
+}
+
+.t-action2 {
+ @include font-size(13);
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.t-action3 {
+ @include font-size(13);
+}
+
+.t-action4 {
+ @include font-size(12);
+}
+
+// ====================
+
+// misc
+.t-icon {
+ line-height: 0;
+}
\ No newline at end of file
diff --git a/cms/static/sass/views/_account.scss b/cms/static/sass/views/_account.scss
index 1206db5e76..2be94a81ea 100644
--- a/cms/static/sass/views/_account.scss
+++ b/cms/static/sass/views/_account.scss
@@ -71,7 +71,7 @@ body.signup, body.signin {
@include blue-button;
@include transition(all .15s);
@include font-size(15);
- display:block;
+ display: block;
width: 100%;
padding: ($baseline*0.75) ($baseline/2);
font-weight: 600;
diff --git a/cms/static/sass/views/_index.scss b/cms/static/sass/views/_index.scss
index f4087a8605..7c45530339 100644
--- a/cms/static/sass/views/_index.scss
+++ b/cms/static/sass/views/_index.scss
@@ -9,17 +9,6 @@ body.index {
margin-bottom: 0;
}
- .wrapper-footer {
- margin: 0;
- border-top: 2px solid $gray-l3;
-
- footer.primary {
- border: none;
- margin-top: 0;
- padding-top: 0;
- }
- }
-
.wrapper-content-header, .wrapper-content-features, .wrapper-content-cta {
@include box-sizing(border-box);
margin: 0;
@@ -199,7 +188,7 @@ body.index {
img {
display: block;
width: 100%;
- height: 100%;
+ height: auto;
}
}
@@ -306,8 +295,8 @@ body.index {
// call to action content
.wrapper-content-cta {
- padding-bottom: ($baseline*2);
- padding-top: ($baseline*2);
+ position: relative;
+ padding: ($baseline*2) 0;
background: $white;
}
diff --git a/cms/static/sass/views/_outline.scss b/cms/static/sass/views/_outline.scss
index 6a141fa789..6b179f0731 100644
--- a/cms/static/sass/views/_outline.scss
+++ b/cms/static/sass/views/_outline.scss
@@ -604,13 +604,39 @@ body.course.outline {
}
.picker {
+ @include clearfix();
margin: 30px 0 65px;
+
+ .field {
+ float: left;
+ margin-right: ($baseline/2);
+
+ &:first-child {
+ margin-left: ($baseline*5);
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ label, input {
+ display: block;
+ text-align: left;
+ }
+
+ label {
+ @include font-size(14);
+ margin-bottom: ($baseline/4);
+ }
+ }
}
.description {
+ float: left;
margin-top: 30px;
font-size: 14px;
line-height: 20px;
+ width: 100%;
}
strong {
diff --git a/cms/static/sass/views/_subsection.scss b/cms/static/sass/views/_subsection.scss
index cd29759db8..68e3548ea1 100644
--- a/cms/static/sass/views/_subsection.scss
+++ b/cms/static/sass/views/_subsection.scss
@@ -3,11 +3,41 @@
body.course.subsection {
+ .main-wrapper {
+ margin-top: ($baseline*2);
+ }
+
.unit-settings {
.window-contents {
padding: 10px 20px;
}
+ .datepair {
+
+ .field {
+ display: inline-block;
+ margin-right: ($baseline/4);
+ width: 45%;
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ label, input {
+ display: block;
+ text-align: left;
+ }
+
+ input {
+ width: 100%;
+ }
+
+ label {
+ margin-bottom: ($baseline/4);
+ }
+ }
+ }
+
.unit-actions {
border-bottom: none;
padding-bottom: 0;
@@ -74,7 +104,7 @@ body.course.subsection {
}
.window-contents {
- display: none;
+ display: none;
}
}
@@ -232,6 +262,7 @@ body.course.subsection {
.remove-date {
display: block;
+ margin-top: ($baseline/4);
}
}
@@ -259,7 +290,7 @@ body.course.subsection {
background-position: 0 -50px;
.hidden {
- background-position: 0 -5px;
+ background-position: 0 -5px;
}
}
}
@@ -369,4 +400,4 @@ body.course.subsection {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/cms/static/sass/views/_unit.scss b/cms/static/sass/views/_unit.scss
index e74690d9ec..06849f851c 100644
--- a/cms/static/sass/views/_unit.scss
+++ b/cms/static/sass/views/_unit.scss
@@ -3,9 +3,8 @@
body.course.unit {
- .unit .main-wrapper {
- @include clearfix();
- margin: 40px;
+ .main-wrapper {
+ margin-top: ($baseline*2);
}
//Problem Selector tab menu requirements
@@ -31,7 +30,7 @@ body.course.unit {
}
.unit-body {
-
+
.unit-name-input {
padding: 20px 40px;
@@ -44,7 +43,7 @@ body.course.unit {
font-size: 20px;
}
}
-
+
.breadcrumbs {
border-radius: 3px 3px 0 0;
border-bottom: 1px solid #cbd1db;
@@ -189,10 +188,10 @@ body.course.unit {
@include clearfix;
a {
- position: relative;
+ position: relative;
border: 1px solid $darkGreen;
background: tint($green,20%);
- color: #fff;
+ color: #fff;
&:hover {
background: $brightGreen;
@@ -254,8 +253,8 @@ body.course.unit {
@include transition (none);
&:hover {
- background: tint($green,30%);
- color: #fff;
+ background: tint($green,30%);
+ color: #fff;
@include transition(background-color .15s);
}
}
@@ -263,7 +262,7 @@ body.course.unit {
li {
border:none;
border-bottom: 1px dashed $lightGrey;
- color: #fff;
+ color: #fff;
}
li:first-child {
@@ -326,7 +325,7 @@ body.course.unit {
}
}
- // specific editor types
+ // specific editor types
.empty {
a {
@@ -337,20 +336,20 @@ body.course.unit {
&:hover {
- background: tint($green,30%);
+ background: tint($green,30%);
color: #fff;
}
}
}
}
- .new-component {
+ .new-component {
text-align: center;
h5 {
color: $darkGreen;
}
-
+
}
}
}
@@ -374,7 +373,7 @@ body.course.unit {
&.editing {
border: 1px solid $lightBluishGrey2;
z-index: auto;
-
+
.drag-handle,
.component-actions {
display: none;
@@ -434,7 +433,7 @@ body.course.unit {
label {
display: inline-block;
- margin-right: 10px;
+ margin-right: 10px;
}
}
@@ -528,7 +527,7 @@ body.course.unit {
}
.window-contents {
- display: none;
+ display: none;
}
}
@@ -678,4 +677,4 @@ body.unit {
padding-top: 0;
}
}
-}
\ No newline at end of file
+}
diff --git a/cms/templates/base.html b/cms/templates/base.html
index e4f5befd63..0809795f70 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -29,9 +29,7 @@
- <%include file="widgets/header.html" />
<%include file="courseware_vendor_js.html"/>
-
@@ -55,7 +53,14 @@
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
+ <%include file="widgets/header.html" />
+
<%block name="content">%block>
+
+ % if user.is_authenticated():
+ <%include file="widgets/sock.html" />
+ % endif
+
<%include file="widgets/footer.html" />
<%include file="widgets/tender.html" />
<%block name="jsextra">%block>
@@ -63,5 +68,3 @@
<%include file="widgets/qualaroo.html" />
-
-
diff --git a/cms/templates/course_info.html b/cms/templates/course_info.html
index f9166bf166..cbf436ecc5 100644
--- a/cms/templates/course_info.html
+++ b/cms/templates/course_info.html
@@ -80,5 +80,4 @@
-
%block>
\ No newline at end of file
diff --git a/cms/templates/edit_subsection.html b/cms/templates/edit_subsection.html
index 80385de829..901e0a8008 100644
--- a/cms/templates/edit_subsection.html
+++ b/cms/templates/edit_subsection.html
@@ -33,17 +33,22 @@
diff --git a/cms/templates/howitworks.html b/cms/templates/howitworks.html
index 7a819fceba..6c0029c425 100644
--- a/cms/templates/howitworks.html
+++ b/cms/templates/howitworks.html
@@ -134,10 +134,10 @@
diff --git a/cms/templates/index.html b/cms/templates/index.html
index 8b14ea179a..916720f4e7 100644
--- a/cms/templates/index.html
+++ b/cms/templates/index.html
@@ -69,7 +69,7 @@
% if user.is_active:
- %for course, url, lms_link in sorted(courses, key=lambda s: s[0].lower()):
+ %for course, url, lms_link in sorted(courses, key=lambda s: s[0].lower() if s[0] is not None else ''):
${course}
diff --git a/cms/templates/overview.html b/cms/templates/overview.html
index 04aae12f4a..e8c722cda2 100644
--- a/cms/templates/overview.html
+++ b/cms/templates/overview.html
@@ -104,20 +104,6 @@
%block>
<%block name="content">
-
-
-
Section Release Date
-
-
-
-
-
On the date set above, this section – – will be released to students. Any units marked private will only be visible to admins.
-
-
-
Save Cancel
-
-
-
@@ -162,13 +148,13 @@
<%
start_date_str = get_time_struct_display(section.lms.start, '%m/%d/%Y')
- start_time_str = get_time_struct_display(section.lms.start, '%I:%M %p')
+ start_time_str = get_time_struct_display(section.lms.start, '%H:%M')
%>
%if section.lms.start is None:
This section has not been released.
Schedule
%else:
-
Will Release: ${start_date_str} at ${start_time_str}
+
Will Release: ${get_time_struct_display(section.lms.start, '%m/%d/%Y at %H:%M UTC')}
Edit
%endif
@@ -216,4 +202,25 @@
+
+
+
+
Section Release Date
+
+
+ Release Day
+
+
+
+
+
+
On the date set above, this section – – will be released to students. Any units marked private will only be visible to admins.
+
+
+
Save Cancel
+
+
%block>
diff --git a/cms/templates/settings_advanced.html b/cms/templates/settings_advanced.html
index 838af5ada9..acbbb7cd35 100644
--- a/cms/templates/settings_advanced.html
+++ b/cms/templates/settings_advanced.html
@@ -19,6 +19,12 @@ from contentstore import utils