Commit d9fa723e by Chris Dodge

Merge branch 'master' of github.com:MITx/mitx into fix/cdodge/export-draft-modules

Conflicts:
	common/lib/xmodule/xmodule/modulestore/xml_importer.py
parents 4cbb9253 276b86a7
......@@ -35,6 +35,7 @@ load-plugins=
# it should appear only once).
disable=
# C0301: Line too long
# C0302: Too many lines in module
# W0141: Used builtin function 'map'
# W0142: Used * or ** magic
# R0201: Method could be a function
......@@ -42,8 +43,11 @@ disable=
# R0902: Too many instance attributes
# R0903: Too few public methods (1/2)
# R0904: Too many public methods
# R0911: Too many return statements
# R0912: Too many branches
# R0913: Too many arguments
C0301,W0141,W0142,R0201,R0901,R0902,R0903,R0904,R0913
# R0914: Too many local variables
C0301,C0302,W0141,W0142,R0201,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914
[REPORTS]
......@@ -92,7 +96,7 @@ zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
generated-members=REQUEST,acl_users,aq_parent,objects,DoesNotExist,can_read,can_write,get_url,size
generated-members=REQUEST,acl_users,aq_parent,objects,DoesNotExist,can_read,can_write,get_url,size,content
[BASIC]
......
......@@ -120,6 +120,12 @@ def howitworks(request):
else:
return render_to_response('howitworks.html', {})
# static/proof-of-concept views
def ux_alerts(request):
return render_to_response('ux-alerts.html', {})
# ==== Views for any logged-in user ==================================
......
if (!window.CmsUtils) window.CmsUtils = {};
var $body;
var $modal;
var $modalCover;
......@@ -48,6 +50,10 @@ $(document).ready(function () {
(e).preventDefault();
});
// alerts/notifications - manual close
$('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert);
$('.action-notification-close').bind('click', hideNotification);
// nav - dropdown related
$body.click(function (e) {
$('.nav-dropdown .nav-item .wrapper-nav-sub').removeClass('is-shown');
......@@ -87,7 +93,7 @@ $(document).ready(function () {
$('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink);
// tender feedback window scrolling
$('a.show-tender').bind('click', smoothScrollTop);
$('a.show-tender').bind('click', window.CmsUtils.smoothScrollTop);
// toggling footer additional support
$('.cta-show-sock').bind('click', toggleSock);
......@@ -159,21 +165,24 @@ $(document).ready(function () {
function smoothScrollLink(e) {
(e).preventDefault();
$.smoothScroll({
offset: -200,
easing: 'swing',
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $(this).attr('href')
});
}
function smoothScrollTop(e) {
// On AWS instances, this base.js gets wrapped in a separate scope as part of Django static
// pipelining (note, this doesn't happen on local runtimes). So if we set it on window,
// when we can access it from other scopes (namely Course Advanced Settings).
window.CmsUtils.smoothScrollTop = function (e) {
(e).preventDefault();
$.smoothScroll({
offset: -200,
easing: 'swing',
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $('#view-top')
......@@ -483,9 +492,9 @@ function toggleSock(e) {
$sock.toggleClass('is-shown');
$sockContent.toggle('fast');
$.smoothScroll({
offset: -200,
easing: 'swing',
$.smoothScroll({
offset: -200,
easing: 'swing',
speed: 1000,
scrollElement: null,
scrollTarget: $sock
......@@ -538,6 +547,17 @@ function removeDateSetter(e) {
$block.find('.time').val('');
}
function hideNotification(e) {
(e).preventDefault();
$(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden','true');
}
function hideAlert(e) {
(e).preventDefault();
$(this).closest('.wrapper-alert').removeClass('is-shown');
}
function showToastMessage(message, $button, lifespan) {
var $toast = $('<div class="toast-notification"></div>');
var $closeBtn = $('<a href="#" class="close-button">×</a>');
......@@ -839,4 +859,4 @@ function saveSetSectionScheduleDate(e) {
hideModal();
});
}
\ No newline at end of file
}
......@@ -32,7 +32,7 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
var listEle$ = this.$el.find('.course-advanced-policy-list');
listEle$.empty();
// b/c we've deleted all old fields, clear the map and repopulate
this.fieldToSelectorMap = {};
this.selectorToField = {};
......@@ -101,13 +101,13 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
});
},
showMessage: function (type) {
this.$el.find(".message-status").removeClass("is-shown");
$(".wrapper-alert").removeClass("is-shown");
if (type) {
if (type === this.error_saving) {
this.$el.find(".message-status.error").addClass("is-shown");
$(".wrapper-alert-error").addClass("is-shown").attr('aria-hidden','false');
}
else if (type === this.successful_changes) {
this.$el.find(".message-status.confirm").addClass("is-shown");
$(".wrapper-alert-confirmation").addClass("is-shown").attr('aria-hidden','false');
this.hideSaveCancelButtons();
}
}
......@@ -117,17 +117,20 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
}
},
showSaveCancelButtons: function(event) {
if (!this.buttonsVisible) {
if (!this.notificationBarShowing) {
this.$el.find(".message-status").removeClass("is-shown");
$('.wrapper-notification').addClass('is-shown');
this.buttonsVisible = true;
$('.wrapper-notification').removeClass('is-hiding').addClass('is-shown').attr('aria-hidden','false');
this.notificationBarShowing = true;
}
},
hideSaveCancelButtons: function() {
$('.wrapper-notification').removeClass('is-shown');
this.buttonsVisible = false;
if (this.notificationBarShowing) {
$('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden','true');
this.notificationBarShowing = false;
}
},
saveView : function(event) {
window.CmsUtils.smoothScrollTop(event);
// TODO one last verification scan:
// call validateKey on each to ensure proper format
// check for dupes
......@@ -146,6 +149,7 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
});
},
revertView : function(event) {
event.preventDefault();
var self = event.data;
self.model.deleteKeys = [];
self.model.clear({silent : true});
......@@ -158,7 +162,7 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
var newKeyId = _.uniqueId('policy_key_'),
newEle = this.template({ key : key, value : JSON.stringify(value, null, 4),
keyUniqueId: newKeyId, valueUniqueId: _.uniqueId('policy_value_')});
this.fieldToSelectorMap[key] = newKeyId;
this.selectorToField[newKeyId] = key;
return newEle;
......@@ -169,4 +173,4 @@ CMS.Views.Settings.Advanced = CMS.Views.ValidatingView.extend({
blurInput : function(event) {
$(event.target).prev().removeClass("is-focused");
}
});
\ No newline at end of file
});
......@@ -25,7 +25,7 @@ a {
@include transition(color 0.25s ease-in-out);
&:hover {
color: #cb9c40;
color: $orange-d1;
}
}
......@@ -50,11 +50,72 @@ h1 {
// ====================
// typography - basic
.title-1, .title-2, .title-3, .title-4, .title-5, .title-6 {
font-weight: 600;
color: $gray-d3;
margin: 0;
padding: 0;
}
.title-1 {
@include font-size(32);
margin-bottom: ($baseline*1.5);
}
.title-2 {
@include font-size(24);
margin-bottom: $baseline;
}
.title-3 {
@include font-size(18);
margin-bottom: ($baseline/2);
}
.title-4 {
@include font-size(14);
margin-bottom: $baseline;
font-weight: 500
}
.title-5 {
@include font-size(14);
color: $gray-l1;
margin-bottom: $baseline;
font-weight: 500
}
.title-6 {
@include font-size(14);
color: $gray-l2;
margin-bottom: $baseline;
font-weight: 500
}
p, ul, ol, dl {
margin-bottom: ($baseline/2);
&:last-child {
margin-bottom: 0;
}
}
// ====================
// layout - basic
.wrapper-view {
}
// ====================
// layout - basic page header
.wrapper-mast {
margin: ($baseline*1.5) 0 0 0;
padding: 0 $baseline;
position: relative;
.mast, .metadata {
@include clearfix();
@include font-size(16);
......@@ -62,7 +123,7 @@ h1 {
max-width: $fg-max-width;
min-width: $fg-min-width;
width: flex-grid(12);
margin: ($baseline*1.5) auto $baseline auto;
margin: 0 auto $baseline auto;
color: $gray-d2;
}
......@@ -284,18 +345,33 @@ h1 {
margin: 0 0 ($baseline/2) 0;
}
.title-4 {
}
header {
@include clearfix();
.title-5 {
.title-2 {
width: flex-grid(5, 12);
margin: 0 flex-gutter() 0 0;
float: left;
}
.tip {
@include font-size(13);
width: flex-grid(7, 12);
float: right;
margin-top: ($baseline/2);
text-align: right;
color: $gray-l2;
}
}
}
// layout - supplemental content
.content-supplementary {
> section {
margin: 0 0 $baseline 0;
}
.bit {
@include font-size(13);
margin: 0 0 $baseline 0;
......@@ -761,10 +837,10 @@ body.js {
// ====================
// works in progress
// works in progress & testing
body.hide-wip {
.wip-box {
display: none;
}
}
\ No newline at end of file
}
......@@ -15,17 +15,17 @@
// mixins - grandfathered
@mixin button {
display: inline-block;
padding: 4px 20px 6px;
font-size: 14px;
padding: ($baseline/5) $baseline ($baseline/4);
@include font-size(14);
font-weight: 700;
@include box-shadow(0 1px 0 rgba(255, 255, 255, .3) inset, 0 0 0 rgba(0, 0, 0, 0));
@include transition(background-color .15s, box-shadow .15s);
&.disabled {
border: 1px solid $lightGrey !important;
border: 1px solid $gray-l1 !important;
border-radius: 3px !important;
background: $lightGrey !important;
color: $darkGrey !important;
background: $gray-l1 !important;
color: $gray-d1 !important;
pointer-events: none;
cursor: none;
&:hover {
......@@ -38,32 +38,111 @@
}
}
@mixin green-button {
@include button;
border: 1px solid $green-d1;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: $green;
@include box-shadow(0 1px 0 rgba(255, 255, 255, .3) inset);
color: $white;
&:hover {
background-color: $green-s1;
color: $white;
}
&.disabled {
border: 1px solid $green-l3 !important;
background: $green-l3 !important;
color: $white !important;
@include box-shadow(none);
}
}
@mixin blue-button {
@include button;
border: 1px solid #437fbf;
border: 1px solid $blue-d1;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: $blue;
color: #fff;
color: $white;
&:hover, &.active {
background-color: #62aaf5;
color: #fff;
background-color: $blue-s2;
color: $white;
}
&.disabled {
border: 1px solid $blue-l3 !important;
background: $blue-l3 !important;
color: $white !important;
@include box-shadow(none);
}
}
@mixin green-button {
@include button;
border: 1px solid #0d7011;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: $green;
color: #fff;
@mixin red-button {
@include button;
border: 1px solid $red-d1;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: $red;
color: $white;
&:hover {
background-color: #129416;
color: #fff;
}
&:hover, &.active {
background-color: $red-s1;
color: $white;
}
&.disabled {
border: 1px solid $red-l3 !important;
background: $red-l3 !important;
color: $white !important;
@include box-shadow(none);
}
}
@mixin pink-button {
@include button;
border: 1px solid $pink-d1;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: $pink;
color: $white;
&:hover, &.active {
background-color: $pink-s1;
color: $white;
}
&.disabled {
border: 1px solid $pink-l3 !important;
background: $pink-l3 !important;
color: $white !important;
@include box-shadow(none);
}
}
@mixin orange-button {
@include button;
border: 1px solid $orange-d1;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0) 60%);
background-color: $orange;
@include box-shadow(0 1px 0 rgba(255, 255, 255, .3) inset);
color: $gray-d2;
&:hover {
background-color: $orange-s2;
color: $gray-d2;
}
&.disabled {
border: 1px solid $orange-l3 !important;
background: $orange-l2 !important;
color: $gray-l1 !important;
@include box-shadow(none);
}
}
@mixin white-button {
......@@ -82,24 +161,9 @@
}
}
@mixin orange-button {
@include button;
border: 1px solid #bda046;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0) 60%);
background-color: #edbd3c;
@include box-shadow(0 1px 0 rgba(255, 255, 255, .3) inset);
color: #3c3c3c;
&:hover {
background-color: #ffcd46;
color: #3c3c3c;
}
}
@mixin grey-button {
@include button;
border: 1px solid $darkGrey;
border: 1px solid $gray-d2;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: #d1dae3;
......@@ -127,39 +191,17 @@
}
}
@mixin green-button {
@include button;
border: 1px solid $darkGreen;
border-radius: 3px;
@include linear-gradient(top, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0));
background-color: $green;
@include box-shadow(0 1px 0 rgba(255, 255, 255, .3) inset);
color: #fff;
&:hover {
background-color: $brightGreen;
color: #fff;
}
&.disabled {
border: 1px solid $disabledGreen !important;
background: $disabledGreen !important;
color: #fff !important;
@include box-shadow(none);
}
}
@mixin dark-grey-button {
@include button;
border: 1px solid #1c1e20;
border: 1px solid $gray-d2;
border-radius: 3px;
background: -webkit-linear-gradient(top, rgba(255, 255, 255, .2), rgba(255, 255, 255, 0)) $extraDarkGrey;
background: -webkit-linear-gradient(top, rgba(255, 255, 255, .2), rgba(255, 255, 255, 0)) $gray-d1;
box-shadow: 0 1px 0 rgba(255, 255, 255, .2) inset;
color: #fff;
color: $white;
&:hover {
background-color: #595f64;
color: #fff;
background-color: $gray-d4;
color: $white;
}
}
......@@ -180,7 +222,7 @@
}
textarea {
min-height: 80px;
min-height: 80px;
}
h5 {
......@@ -225,7 +267,7 @@
.section-item {
position: relative;
display: block;
padding: 6px 8px 8px 16px;
padding: 6px 8px 8px 16px;
background: #edf1f5;
font-size: 13px;
......@@ -296,6 +338,9 @@
}
}
// ====================
// sunsetted mixins
@mixin active {
@include linear-gradient(top, rgba(255, 255, 255, .4), rgba(255, 255, 255, 0));
background-color: rgba(255, 255, 255, .3);
......@@ -389,4 +434,4 @@
.depth2 { z-index: 100; }
.depth3 { z-index: 1000; }
.depth4 { z-index: 10000; }
.depth5 { z-index: 100000; }
\ No newline at end of file
.depth5 { z-index: 100000; }
......@@ -113,7 +113,7 @@ $green-u1: desaturate($green,15%);
$green-u2: desaturate($green,30%);
$green-u3: desaturate($green,45%);
$yellow: rgb(231, 214, 143);
$yellow: rgb(237, 189, 60);
$yellow-l1: tint($yellow,20%);
$yellow-l2: tint($yellow,40%);
$yellow-l3: tint($yellow,60%);
......@@ -149,8 +149,13 @@ $orange-u3: desaturate($orange,45%);
$shadow: rgba(0,0,0,0.2);
$shadow-l1: rgba(0,0,0,0.1);
$shadow-l2: rgba(0,0,0,0.05);
$shadow-d1: rgba(0,0,0,0.4);
// specific UI
$notification-height: ($baseline*10);
// colors - inherited
$baseFontColor: $gray-d2;
$offBlack: #3c3c3c;
......@@ -167,4 +172,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);
\ No newline at end of file
$error-red: rgb(253, 87, 87);
@mixin bounce-in {
// studio animations & keyframes
// ====================
// rotate clockwise
@mixin rotateClockwise {
0% {
@include transform(rotate(0deg));
}
100% {
@include transform(rotate(360deg));
}
}
@-moz-keyframes rotateClockwise { @include rotateClockwise(); }
@-webkit-keyframes rotateClockwise { @include rotateClockwise(); }
@-o-keyframes rotateClockwise { @include rotateClockwise(); }
@keyframes rotateClockwise { @include rotateClockwise();}
@mixin anim-rotateClockwise($duration, $timing: ease-in-out, $count: 1, $delay: 0) {
@include animation-name(rotateClockwise);
@include animation-duration($duration);
@include animation-delay($delay);
@include animation-timing-function($timing);
@include animation-iteration-count($count);
@include animation-fill-mode(both);
}
// ====================
// notifications slide up
@mixin notificationsSlideUp {
0% {
@include transform(translateY(0));
}
90% {
@include transform(translateY(-($notification-height)));
}
100% {
@include transform(translateY(-($notification-height*0.99)));
}
}
@-moz-keyframes notificationsSlideUp { @include notificationsSlideUp(); }
@-webkit-keyframes notificationsSlideUp { @include notificationsSlideUp(); }
@-o-keyframes notificationsSlideUp { @include notificationsSlideUp(); }
@keyframes notificationsSlideUp { @include notificationsSlideUp();}
@mixin anim-notificationsSlideUp($duration, $timing: ease-in-out, $count: 1, $delay: 0) {
@include animation-name(notificationsSlideUp);
@include animation-duration($duration);
@include animation-delay($delay);
@include animation-timing-function($timing);
@include animation-iteration-count($count);
@include animation-fill-mode(both);
}
// ====================
// notifications slide down
@mixin notificationsSlideDown {
0% {
@include transform(translateY(-($notification-height*0.99)));
}
10% {
@include transform(translateY(-($notification-height)));
}
100% {
@include transform(translateY(0));
}
}
@-moz-keyframes notificationsSlideDown { @include notificationsSlideDown(); }
@-webkit-keyframes notificationsSlideDown { @include notificationsSlideDown(); }
@-o-keyframes notificationsSlideDown { @include notificationsSlideDown(); }
@keyframes notificationsSlideDown { @include notificationsSlideDown();}
@mixin anim-notificationsSlideDown($duration, $timing: ease-in-out, $count: 1, $delay: 0) {
@include animation-name(notificationsSlideDown);
@include animation-duration($duration);
@include animation-delay($delay);
@include animation-timing-function($timing);
@include animation-iteration-count($count);
@include animation-fill-mode(both);
}
// ====================
// notifications slide up then down
@mixin notificationsSlideUpDown {
0%, 100% {
@include transform(translateY(0));
}
15%, 85% {
@include transform(translateY(-($notification-height)));
}
20%, 80% {
@include transform(translateY(-($notification-height*0.99)));
}
}
@-moz-keyframes notificationsSlideUpDown { @include notificationsSlideUpDown(); }
@-webkit-keyframes notificationsSlideUpDown { @include notificationsSlideUpDown(); }
@-o-keyframes notificationsSlideUpDown { @include notificationsSlideUpDown(); }
@keyframes notificationsSlideUpDown { @include notificationsSlideUpDown();}
@mixin anim-notificationsSlideUpDown($duration, $timing: ease-in-out, $count: 1, $delay: 0) {
@include animation-name(notificationsSlideUpDown);
@include animation-duration($duration);
@include animation-delay($delay);
@include animation-timing-function($timing);
@include animation-iteration-count($count);
@include animation-fill-mode(both);
}
// ====================
// bounce in
@mixin bounceIn {
0% {
opacity: 0;
@include transform(scale(.3));
@include transform(scale(0.3));
}
50% {
......@@ -14,14 +140,63 @@
}
}
@-moz-keyframes bounce-in { @include bounce-in(); }
@-webkit-keyframes bounce-in { @include bounce-in(); }
@-o-keyframes bounce-in { @include bounce-in(); }
@keyframes bounce-in { @include bounce-in();}
@-moz-keyframes bounceIn { @include bounceIn(); }
@-webkit-keyframes bounceIn { @include bounceIn(); }
@-o-keyframes bounceIn { @include bounceIn(); }
@keyframes bounceIn { @include bounceIn();}
@mixin bounce-in-animation($duration, $timing: ease-in-out) {
@include animation-name(bounce-in);
@mixin anim-bounceIn($duration, $timing: ease-in-out, $count: 1, $delay: 0) {
@include animation-name(bounceIn);
@include animation-duration($duration);
@include animation-delay($delay);
@include animation-timing-function($timing);
@include animation-iteration-count($count);
@include animation-fill-mode(both);
}
// ====================
// bounce in
@mixin bounceOut {
0% {
opacity: 0;
@include transform(scale(0.3));
}
50% {
opacity: 1;
@include transform(scale(1.05));
}
100% {
@include transform(scale(1));
}
0% {
@include transform(scale(1));
}
50% {
opacity: 1;
@include transform(scale(1.05));
}
100% {
opacity: 0;
@include transform(scale(0.3));
}
}
@-moz-keyframes bounceOut { @include bounceOut(); }
@-webkit-keyframes bounceOut { @include bounceOut(); }
@-o-keyframes bounceOut { @include bounceOut(); }
@keyframes bounceOut { @include bounceOut();}
@mixin anim-bounceOut($duration, $timing: ease-in-out, $count: 1, $delay: 0) {
@include animation-name(bounceOut);
@include animation-duration($duration);
@include animation-delay($delay);
@include animation-timing-function($timing);
@include animation-iteration-count($count);
@include animation-fill-mode(both);
}
\ No newline at end of file
......@@ -4,6 +4,7 @@
// bourbon libs and resets
@import 'bourbon/bourbon';
@import 'bourbon/addons/button';
@import "variables";
@import 'vendor/normalize';
@import 'reset';
......
......@@ -97,7 +97,7 @@
color: $blue;
&:hover, &:active {
background: $blue-l3;
background: $blue-l4;
color: $blue-s2;
}
......
......@@ -8,11 +8,11 @@ input[type="password"],
textarea.text {
padding: 6px 8px 8px;
@include box-sizing(border-box);
border: 1px solid $mediumGrey;
border: 1px solid $gray-l2;
border-radius: 2px;
@include linear-gradient($lightGrey, tint($lightGrey, 90%));
background-color: $lightGrey;
@include box-shadow(0 1px 2px rgba(0, 0, 0, .1) inset);
@include linear-gradient($gray-l5, $white);
background-color: $gray-l5;
@include box-shadow(inset 0 1px 2px $shadow-l1);
font-family: 'Open Sans', sans-serif;
font-size: 11px;
color: $baseFontColor;
......@@ -21,7 +21,7 @@ textarea.text {
&::-webkit-input-placeholder,
&:-moz-placeholder,
&:-ms-input-placeholder {
color: #979faf;
color: $gray-l2;
}
&:focus {
......@@ -30,7 +30,72 @@ textarea.text {
}
}
// forms - specific
// ====================
// forms - fields - not editable
.field.is-not-editable {
& label.is-focused {
color: $gray-d2;
}
label, input, textarea {
pointer-events: none;
}
}
// ====================
// field with error
.field.error {
input, textarea {
border-color: $red;
}
}
// ====================
// forms - additional UI
form {
.note {
@include box-sizing(border-box);
.title {
}
.copy {
}
// note with actions
&.has-actions {
@include clearfix();
.title {
}
.copy {
}
.list-actions {
}
}
}
.note-promotion {
}
}
// ====================
// forms - grandfathered
input.search {
padding: 6px 15px 8px 30px;
@include box-sizing(border-box);
......@@ -73,4 +138,4 @@ code {
background-color: #edf1f5;
@include box-shadow(0 1px 2px rgba(0, 0, 0, 0.1) inset);
font-family: Monaco, monospace;
}
\ No newline at end of file
}
......@@ -5,12 +5,12 @@
margin: 0;
padding: $baseline;
border-bottom: 1px solid $gray;
@include box-shadow(0 1px 5px 0 rgba(0,0,0, 0.1));
@include box-shadow(0 1px 5px 0 rgba(0,0,0, 0.2));
background: $white;
height: 76px;
position: relative;
width: 100%;
z-index: 10;
z-index: 1000;
a {
color: $baseFontColor;
......
......@@ -4,7 +4,7 @@
body.signup, body.signin {
.wrapper-content {
margin: 0;
margin: ($baseline*1.5) 0 0 0;
padding: 0 $baseline;
position: relative;
width: 100%;
......@@ -18,7 +18,7 @@ body.signup, body.signin {
width: flex-grid(12);
margin: 0 auto;
color: $gray-d2;
header {
position: relative;
margin-bottom: $baseline;
......@@ -121,7 +121,7 @@ body.signup, body.signin {
@include font-size(16);
height: 100%;
width: 100%;
padding: ($baseline/2);
padding: ($baseline/2);
&.long {
width: 100%;
......@@ -136,15 +136,15 @@ body.signup, body.signin {
}
:-moz-placeholder {
color: $gray-l3;
color: $gray-l3;
}
::-moz-placeholder {
color: $gray-l3;
color: $gray-l3;
}
:-ms-input-placeholder {
color: $gray-l3;
:-ms-input-placeholder {
color: $gray-l3;
}
&:focus {
......
......@@ -147,7 +147,7 @@ body.course.settings {
}
label {
@include font-size(14);
@extend .t-copy-sub1;
@include transition(color, 0.15s, ease-in-out);
margin: 0 0 ($baseline/4) 0;
font-weight: 400;
......@@ -161,7 +161,7 @@ body.course.settings {
@include placeholder($gray-l4);
@include font-size(16);
@include size(100%,100%);
padding: ($baseline/2);
padding: ($baseline/2);
&.long {
}
......@@ -212,7 +212,7 @@ body.course.settings {
padding: $baseline;
&:last-child {
padding-bottom: $baseline;
padding-bottom: $baseline;
}
.actions {
......@@ -238,33 +238,36 @@ body.course.settings {
}
}
// not editable fields
.field.is-not-editable {
& label.is-focused {
color: $gray-d2;
}
}
// field with error
.field.error {
input, textarea {
border-color: $red;
}
}
// specific fields - basic
&.basic {
.list-input {
@include clearfix();
padding: 0 ($baseline/2);
.field {
margin-bottom: 0;
}
}
// course details that should appear more like content than elements to change
.field.is-not-editable {
label {
}
input, textarea {
@extend .t-copy-lead1;
@include box-shadow(none);
border: none;
background: none;
padding: 0;
margin: 0;
font-weight: 600;
}
}
#field-course-organization {
float: left;
width: flex-grid(2, 9);
......@@ -281,6 +284,58 @@ body.course.settings {
float: left;
width: flex-grid(5, 9);
}
// course link note
.note-promotion-courseURL {
@include box-shadow(0 2px 1px $shadow-l1);
@include border-radius(($baseline/5));
margin-top: ($baseline*1.5);
border: 1px solid $gray-l2;
padding: ($baseline/2) 0 0 0;
.title {
@extend .t-copy-sub1;
margin: 0 0 ($baseline/10) 0;
padding: 0 ($baseline/2);
.tip {
display: inline;
margin-left: ($baseline/4);
}
}
.copy {
padding: 0 ($baseline/2) ($baseline/2) ($baseline/2);
.link-courseURL {
@extend .t-copy-lead1;
&:hover {
}
}
}
.list-actions {
@include box-shadow(inset 0 1px 1px $shadow-l1);
border-top: 1px solid $gray-l2;
padding: ($baseline/2);
background: $gray-l5;
.action-primary {
@include blue-button();
@include font-size(13);
font-weight: 600;
.icon {
@extend .t-icon;
@include font-size(16);
display: inline-block;
vertical-align: middle;
}
}
}
}
}
// specific fields - schedule
......@@ -322,7 +377,7 @@ body.course.settings {
}
}
}
// specific fields - overview
#field-course-overview {
......@@ -468,7 +523,7 @@ body.course.settings {
}
}
}
.grade-specific-bar {
height: 50px !important;
}
......@@ -479,7 +534,7 @@ body.course.settings {
li {
position: absolute;
top: 0;
height: 50px;
height: 50px;
text-align: right;
@include border-radius(2px);
......@@ -600,8 +655,8 @@ body.course.settings {
}
#field-course-grading-assignment-shortname,
#field-course-grading-assignment-totalassignments,
#field-course-grading-assignment-gradeweight,
#field-course-grading-assignment-totalassignments,
#field-course-grading-assignment-gradeweight,
#field-course-grading-assignment-droppable {
width: flex-grid(2, 6);
}
......@@ -734,4 +789,4 @@ body.course.settings {
.content-supplementary {
width: flex-grid(3, 12);
}
}
\ No newline at end of file
}
......@@ -49,20 +49,30 @@
<script type="text/javascript" src="${static.url('js/vendor/CodeMirror/htmlmixed.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/CodeMirror/css.js')}"></script>
<script type="text/javascript">
document.write('\x3Cscript type="text/javascript" src="' +
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
document.write('\x3Cscript type="text/javascript" src="' +
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
</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" />
<!-- view -->
<div class="wrapper wrapper-view">
<%include file="widgets/header.html" />
<%block name="view_alerts"></%block>
<%block name="view_banners"></%block>
<%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="view_notifications"></%block>
</div>
<%block name="view_prompts"></%block>
<%block name="jsextra"></%block>
</body>
......
......@@ -26,9 +26,9 @@
// I believe that current (New Section/New Subsection) cause full page reloads which means these aren't needed globally
// but we really should change that behavior.
if (!window.graderTypes) {
window.graderTypes = new CMS.Models.Settings.CourseGraderCollection();
window.graderTypes.course_location = new CMS.Models.Location('${parent_location}');
window.graderTypes.reset(${course_graders|n});
window.graderTypes = new CMS.Models.Settings.CourseGraderCollection();
window.graderTypes.course_location = new CMS.Models.Location('${parent_location}');
window.graderTypes.reset(${course_graders|n});
}
$(".gradable-status").each(function(index, ele) {
......
......@@ -42,13 +42,17 @@ editor.render();
</%block>
<%block name="content">
<div class="wrapper-content wrapper">
<section class="content">
<header class="page">
<div class="wrapper-mast wrapper">
<header class="mast has-subtitle">
<div class="title">
<span class="title-sub">Settings</span>
<h1 class="title-1">Advanced Settings</h1>
</header>
</div>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<article class="content-primary" role="main">
<form id="settings_advanced" class="settings-advanced" method="post" action="">
......@@ -69,7 +73,7 @@ editor.render();
<p class="instructions"><strong>Warning</strong>: Do not modify these policies unless you are familiar with their purpose.</p>
<ul class="list-input course-advanced-policy-list enum">
</ul>
</section>
</form>
......@@ -100,23 +104,61 @@ editor.render();
</aside>
</section>
</div>
</%block>
<%block name="view_notifications">
<!-- notification: change has been made and a save is needed -->
<div class="wrapper wrapper-notification wrapper-notification-warning">
<div class="notification warning">
<div class="copy">
<i class="ss-icon ss-symbolicons-block icon icon-warning">&#x26A0;</i>
<div class="wrapper wrapper-notification wrapper-notification-warning" aria-hidden="true" role="dialog" aria-labelledby="notification-changesMade-title" aria-describedby="notification-changesMade-description">
<div class="notification warning has-actions">
<i class="ss-icon ss-symbolicons-block icon icon-warning">&#x26A0;</i>
<p><strong>Note: </strong>Your changes will not take effect until you <strong>save your
progress</strong>. Take care with policy value formatting, as validation is <strong>not implemented</strong>.</p>
<div class="copy">
<h2 class="title title-3" id="notification-changesMade-title">You've Made Some Changes</h2>
<p id="notification-changesMade-description">Your changes will not take effect until you <strong>save your progress</strong>. Take care with key and value formatting, as validation is <strong>not implemented</strong>.</p>
</div>
<div class="actions">
<nav class="nav-actions">
<h3 class="sr">Notification Actions</h3>
<ul>
<li><a href="#" class="save-button">Save</a></li>
<li><a href="#" class="cancel-button">Cancel</a></li>
<li class="nav-item">
<a href="" class="action-primary save-button">Save Changes</a>
</li>
<li class="nav-item">
<a href="" class="action-secondary cancel-button">Cancel</a>
</li>
</ul>
</nav>
</div>
</div>
</%block>
<%block name="view_alerts">
<!-- alert: save confirmed with close -->
<div class="wrapper wrapper-alert wrapper-alert-confirmation" role="status">
<div class="alert confirmation">
<i class="ss-icon ss-symbolicons-standard icon icon-confirmation">&#x2713;</i>
<div class="copy">
<h2 class="title title-3">Your policy changes have been saved.</h2>
<p>Please note that validation of your policy key and value pairs is not currently in place yet. If you are having difficulties, please review your policy pairs.</p>
</div>
<a href="" rel="view" class="action action-alert-close">
<i class="ss-icon ss-symbolicons-block icon icon-close">&#x2421;</i>
<span class="label">close alert</span>
</a>
</div>
</div>
<!-- alert: error -->
<div class="wrapper wrapper-alert wrapper-alert-error" role="status">
<div class="alert error">
<i class="ss-icon ss-symbolicons-block icon icon-error">&#x26A0;</i>
<div class="copy">
<h2 class="title title-3">There was an error saving your information</h2>
<p>Please see the error below and correct it to ensure there are no problems in rendering your course.</p>
</div>
</div>
</div>
</%block>
\ No newline at end of file
</%block>
......@@ -16,7 +16,6 @@
});
$(document).ready(function() {
$('body').addClass('js');
// tabs
$('.tab-group').tabs();
......
......@@ -116,6 +116,8 @@ urlpatterns += (
url(r'^logout$', 'student.views.logout_user', name='logout'),
# static/proof-of-concept views
url(r'^ux-alerts$', 'contentstore.views.ux_alerts', name='ux-alerts')
)
if settings.ENABLE_JASMINE:
......
......@@ -199,8 +199,8 @@ class PeerGradingModule(PeerGradingFields, XModule):
self.student_data_for_location = response
score_dict = {
'score': int(count_graded >= count_required),
'total': self.max_grade,
'score': int(count_graded >= count_required and count_graded>0) * int(self.weight),
'total': self.max_grade * int(self.weight),
}
return score_dict
......
......@@ -24,6 +24,11 @@ def strip_filenames(descriptor):
"""
print "strip filename from {desc}".format(desc=descriptor.location.url())
descriptor._model_data.pop('filename', None)
if hasattr(descriptor, 'xml_attributes'):
if 'filename' in descriptor.xml_attributes:
del descriptor.xml_attributes['filename']
for d in descriptor.get_children():
strip_filenames(d)
......
......@@ -11,11 +11,15 @@
font-size: ($sizeValue/10) + rem;
}
// ====================
// line-height
@function lh($amount: 1) {
@return $body-line-height * $amount;
}
// ====================
// image-replacement hidden text
@mixin text-hide() {
text-indent: 100%;
......@@ -35,6 +39,8 @@
width: 1px;
}
// ====================
// vertical and horizontal centering
@mixin vertically-and-horizontally-centered ($height, $width) {
left: 50%;
......@@ -46,6 +52,8 @@
top: 150px;
}
// ====================
// sizing
@mixin size($width: $baseline, $height: $baseline) {
height: $height;
......@@ -56,6 +64,8 @@
@include size($size);
}
// ====================
// placeholder styling
@mixin placeholder($color) {
:-moz-placeholder {
......
......@@ -3,17 +3,12 @@
# django management command: dump grades to csv files
# for use by batch processes
import os
import sys
import string
import datetime
import json
import csv
from instructor.views import *
from instructor.views import get_student_grade_summary_data
from courseware.courses import get_course_by_id
from xmodule.modulestore.django import modulestore
from django.conf import settings
from django.core.management.base import BaseCommand
......@@ -45,7 +40,7 @@ class Command(BaseCommand):
request = self.DummyRequest()
try:
course = get_course_by_id(course_id)
except Exception as err:
except Exception:
if course_id in modulestore().courses:
course = modulestore().courses[course_id]
else:
......
......@@ -11,7 +11,6 @@ import requests
from requests.status_codes import codes
import urllib
from collections import OrderedDict
import json
from StringIO import StringIO
......@@ -21,7 +20,6 @@ from django.http import HttpResponse
from django_future.csrf import ensure_csrf_cookie
from django.views.decorators.cache import cache_control
from mitxmako.shortcuts import render_to_response
import requests
from django.core.urlresolvers import reverse
from courseware import grades
......@@ -36,11 +34,7 @@ from django_comment_client.models import (Role,
from django_comment_client.utils import has_forum_access
from psychometrics import psychoanalyze
from student.models import CourseEnrollment, CourseEnrollmentAllowed
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
from xmodule.modulestore.search import path_to_location
import xmodule.graders as xmgraders
import track.views
......@@ -48,14 +42,15 @@ from .offline_gradecalc import student_grades, offline_grades_available
log = logging.getLogger(__name__)
template_imports = {'urllib': urllib}
# internal commands for managing forum roles:
FORUM_ROLE_ADD = 'add'
FORUM_ROLE_REMOVE = 'remove'
def split_by_comma_and_whitespace(s):
"""
Return string s, split by , or whitespace
"""
return re.split(r'[\s,]', s)
......@@ -141,7 +136,7 @@ def instructor_dashboard(request, course_id):
# 'beta', so adding it to get_access_group_name doesn't really make
# sense.
name = course_beta_test_group_name(course.location)
(group, created) = Group.objects.get_or_create(name=name)
(group, _) = Group.objects.get_or_create(name=name)
return group
# process actions from form POST
......@@ -237,13 +232,13 @@ def instructor_dashboard(request, course_id):
if '/' not in problem_to_reset: # allow state of modules other than problem to be reset
problem_to_reset = "problem/" + problem_to_reset # but problem is the default
try:
(org, course_name, run) = course_id.split("/")
(org, course_name, _) = course_id.split("/")
module_state_key = "i4x://" + org + "/" + course_name + "/" + problem_to_reset
module_to_reset = StudentModule.objects.get(student_id=student_to_reset.id,
course_id=course_id,
module_state_key=module_state_key)
msg += "Found module to reset. "
except Exception as e:
except Exception:
msg += "<font color='red'>Couldn't find module with that urlname. </font>"
if "Delete student state for problem" in action:
......@@ -352,7 +347,7 @@ def instructor_dashboard(request, course_id):
return_csv('', datatable, fp=fp)
fp.seek(0)
files = {'datafile': fp}
msg2, dataset = _do_remote_gradebook(request.user, course, 'post-grades', files=files)
msg2, _ = _do_remote_gradebook(request.user, course, 'post-grades', files=files)
msg += msg2
......@@ -423,7 +418,7 @@ def instructor_dashboard(request, course_id):
datatable = {'header': ['username', 'email'] + profkeys}
def getdat(u):
p = u.profile
return [u.username, u.email] + [getattr(p,x,'') for x in profkeys]
return [u.username, u.email] + [getattr(p, x, '') for x in profkeys]
datatable['data'] = [getdat(u) for u in enrolled_students]
datatable['title'] = 'Student profile data for course %s' % course_id
......@@ -433,17 +428,17 @@ def instructor_dashboard(request, course_id):
elif 'Download CSV of all responses to problem' in action:
problem_to_dump = request.POST.get('problem_to_dump','')
if problem_to_dump[-4:]==".xml":
problem_to_dump=problem_to_dump[:-4]
if problem_to_dump[-4:] == ".xml":
problem_to_dump = problem_to_dump[:-4]
try:
(org, course_name, run)=course_id.split("/")
module_state_key="i4x://"+org+"/"+course_name+"/problem/"+problem_to_dump
(org, course_name, run) = course_id.split("/")
module_state_key = "i4x://" + org + "/" + course_name + "/problem/" + problem_to_dump
smdat = StudentModule.objects.filter(course_id=course_id,
module_state_key=module_state_key)
smdat = smdat.order_by('student')
msg += "Found %d records to dump " % len(smdat)
except Exception as err:
msg+="<font color='red'>Couldn't find module with that urlname. </font>"
msg += "<font color='red'>Couldn't find module with that urlname. </font>"
msg += "<pre>%s</pre>" % escape(err)
smdat = []
......@@ -741,7 +736,7 @@ def _list_course_forum_members(course_id, rolename, datatable):
# make sure datatable is set up properly for display first, before checking for errors
datatable['header'] = ['Username', 'Full name', 'Roles']
datatable['title'] = 'List of Forum {0}s in course {1}'.format(rolename, course_id)
datatable['data'] = [];
datatable['data'] = []
try:
role = Role.objects.get(name=rolename, course_id=course_id)
except Role.DoesNotExist:
......@@ -923,7 +918,7 @@ def get_student_grade_summary_data(request, course, course_id, get_grades=True,
datarow = [student.id, student.username, student.profile.name, student.email]
try:
datarow.append(student.externalauthmap.external_email)
except: # ExternalAuthMap.DoesNotExist
except: # ExternalAuthMap.DoesNotExist
datarow.append('')
if get_grades:
......@@ -1040,7 +1035,8 @@ def _do_enroll_students(course, course_id, students, overload=False):
datatable['data'] = [[x, status[x]] for x in status]
datatable['title'] = 'Enrollment of students'
def sf(stat): return [x for x in status if status[x] == stat]
def sf(stat):
return [x for x in status if status[x] == stat]
data = dict(added=sf('added'), rejected=sf('rejected') + sf('exists'),
deleted=sf('deleted'), datatable=datatable)
......@@ -1136,7 +1132,7 @@ def dump_grading_context(course):
'''
msg = "-----------------------------------------------------------------------------\n"
msg += "Course grader:\n"
msg += '%s\n' % course.grader.__class__
graders = {}
if isinstance(course.grader, xmgraders.WeightedSubsectionsGrader):
......@@ -1151,7 +1147,7 @@ def dump_grading_context(course):
gc = course.grading_context
msg += "graded sections:\n"
msg += '%s\n' % gc['graded_sections'].keys()
for (gs, gsvals) in gc['graded_sections'].items():
msg += "--> Section %s:\n" % (gs)
......
......@@ -27,8 +27,6 @@ from mitxmako.shortcuts import render_to_string
log = logging.getLogger(__name__)
template_imports = {'urllib': urllib}
system = ModuleSystem(
ajax_url=None,
track_function=None,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment