Courseware license (Creative Commons): FED
Use native checkboxes for courseware license options In Studio settings editor for video module, don't show license if feature-flagged off Don't let Scope.contents fields leak to Studio editor JS gettext() must all be on the same line for i18n Add docstrings for bok-choy tests Remove LicenseMixin from HTMLDescriptor Responding to UX review feedback Add aria-pressed attribute Use https links instead of protocol-relative links for links to creativecommons.org Remove license from course outline page in Studio
This commit is contained in:
committed by
Sarina Canelake
parent
8fbaa66d33
commit
a3887e951c
@@ -339,3 +339,4 @@ if FEATURES['ENABLE_COURSEWARE_INDEX'] or FEATURES['ENABLE_LIBRARY_INDEX']:
|
||||
SEARCH_ENGINE = "search.elastic.ElasticSearchEngine"
|
||||
|
||||
XBLOCK_SETTINGS = ENV_TOKENS.get('XBLOCK_SETTINGS', {})
|
||||
XBLOCK_SETTINGS.setdefault("VideoDescriptor", {})["licensing_enabled"] = FEATURES.get("LICENSING", False)
|
||||
|
||||
@@ -143,6 +143,9 @@ FEATURES = {
|
||||
# Toggle course entrance exams feature
|
||||
'ENTRANCE_EXAMS': False,
|
||||
|
||||
# Toggle platform-wide course licensing
|
||||
'LICENSING': False,
|
||||
|
||||
# Enable the courseware search functionality
|
||||
'ENABLE_COURSEWARE_INDEX': False,
|
||||
|
||||
@@ -945,3 +948,9 @@ ELASTIC_FIELD_MAPPINGS = {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
|
||||
XBLOCK_SETTINGS = {
|
||||
"VideoDescriptor": {
|
||||
"licensing_enabled": FEATURES.get("LICENSING", False)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,9 @@ FEATURES['MILESTONES_APP'] = True
|
||||
################################ ENTRANCE EXAMS ################################
|
||||
FEATURES['ENTRANCE_EXAMS'] = True
|
||||
|
||||
################################ COURSE LICENSES ################################
|
||||
FEATURES['LICENSING'] = True
|
||||
|
||||
################################ SEARCH INDEX ################################
|
||||
FEATURES['ENABLE_COURSEWARE_INDEX'] = True
|
||||
FEATURES['ENABLE_LIBRARY_INDEX'] = True
|
||||
|
||||
@@ -138,19 +138,19 @@ define(["js/views/license", "js/models/license", "js/common_helpers/template_hel
|
||||
|
||||
it("has no preview by default", function () {
|
||||
this.view.render();
|
||||
expect(this.view.$("#license-preview").length).toEqual(0)
|
||||
expect(this.view.$(".license-preview").length).toEqual(0)
|
||||
this.view.$("li[data-license=creative-commons] button").click();
|
||||
expect(this.view.$("#license-preview").length).toEqual(0)
|
||||
expect(this.view.$(".license-preview").length).toEqual(0)
|
||||
});
|
||||
|
||||
it("displays a preview if showPreview is true", function() {
|
||||
this.view = new LicenseView({model: this.model, showPreview: true});
|
||||
this.view.render()
|
||||
expect(this.view.$("#license-preview").length).toEqual(1)
|
||||
expect(this.view.$("#license-preview")).toHaveText("");
|
||||
expect(this.view.$(".license-preview").length).toEqual(1)
|
||||
expect(this.view.$(".license-preview")).toHaveText("");
|
||||
this.view.$("li[data-license=creative-commons] button").click();
|
||||
expect(this.view.$("#license-preview").length).toEqual(1)
|
||||
expect(this.view.$("#license-preview")).toContainText("Some Rights Reserved");
|
||||
expect(this.view.$(".license-preview").length).toEqual(1)
|
||||
expect(this.view.$(".license-preview")).toContainText("Some Rights Reserved");
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) {
|
||||
"creative-commons": {
|
||||
"name": gettext("Creative Commons"),
|
||||
"tooltip": gettext("You waive some rights for your work, such that others can use it too"),
|
||||
"url": "//creativecommons.org/about",
|
||||
"url": "https://creativecommons.org/about",
|
||||
"options": {
|
||||
"ver": {
|
||||
"name": gettext("Version"),
|
||||
@@ -18,31 +18,27 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) {
|
||||
"name": gettext("Attribution"),
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"help": gettext("Allow others to copy, distribute, display and perform " +
|
||||
"your copyrighted work but only if they give credit the way you request."),
|
||||
"help": gettext("Allow others to copy, distribute, display and perform your copyrighted work but only if they give credit the way you request. Currently, this option is required."),
|
||||
"disabled": true,
|
||||
},
|
||||
"NC": {
|
||||
"name": gettext("Noncommercial"),
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"help": gettext("Allow others to copy, distribute, display and perform " +
|
||||
"your work - and derivative works based upon it - but for noncommercial purposes only."),
|
||||
"help": gettext("Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only."),
|
||||
},
|
||||
"ND": {
|
||||
"name": gettext("No Derivatives"),
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"help": gettext("Allow others to copy, distribute, display and perform " +
|
||||
"only verbatim copies of your work, not derivative works based upon it."),
|
||||
"help": gettext("Allow others to copy, distribute, display and perform only verbatim copies of your work, not derivative works based upon it. This option is incompatible with \"Share Alike\"."),
|
||||
"conflictsWith": ["SA"]
|
||||
},
|
||||
"SA": {
|
||||
"name": gettext("Share Alike"),
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"help": gettext("Allow others to distribute derivative works only under " +
|
||||
"a license identical to the license that governs your work."),
|
||||
"help": gettext("Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with \"No Derivatives\"."),
|
||||
"conflictsWith": ["ND"]
|
||||
}
|
||||
},
|
||||
@@ -132,6 +128,7 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) {
|
||||
// fire the change event manually.
|
||||
this.model.trigger("change change:options")
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -276,12 +276,13 @@ var DetailsView = ValidatingView.extend({
|
||||
this.model.fetch({
|
||||
success: function() {
|
||||
self.render();
|
||||
_.each(self.codeMirrors,
|
||||
function(mirror) {
|
||||
var ele = mirror.getTextArea();
|
||||
var field = self.selectorToField[ele.id];
|
||||
mirror.setValue(self.model.get(field));
|
||||
});
|
||||
_.each(self.codeMirrors, function(mirror) {
|
||||
var ele = mirror.getTextArea();
|
||||
var field = self.selectorToField[ele.id];
|
||||
mirror.setValue(self.model.get(field));
|
||||
});
|
||||
self.licenseModel.setFromString(self.model.get("license"), {silent: true});
|
||||
self.licenseView.render()
|
||||
},
|
||||
reset: true,
|
||||
silent: true});
|
||||
|
||||
@@ -172,107 +172,6 @@ form {
|
||||
}
|
||||
}
|
||||
|
||||
// +Forms - License selector UI
|
||||
// ====================
|
||||
.license-img {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
ul.license-types {
|
||||
text-align: middle;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.action.license-button {
|
||||
@include grey-button;
|
||||
@extend %t-action2;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
text-align: center;
|
||||
|
||||
width: 220px;
|
||||
height: 40px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&.is-selected {
|
||||
@include blue-button;
|
||||
}
|
||||
}
|
||||
|
||||
.tip {
|
||||
@extend %t-copy-sub2;
|
||||
}
|
||||
}
|
||||
.wrapper-license-options {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.tip {
|
||||
@extend %t-copy-sub2;
|
||||
}
|
||||
#list-license-options {
|
||||
padding-bottom: 10px;
|
||||
|
||||
li {
|
||||
line-height: 1.5;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding: ($baseline / 2) 0 ($baseline * 0.4);
|
||||
&.is-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
&.last {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.fa {
|
||||
vertical-align: top;
|
||||
}
|
||||
.fa-square-o {
|
||||
display: inline-block;
|
||||
margin: ($baseline * 0.15) 15px 0px;
|
||||
}
|
||||
.fa-square-o.is-disabled {
|
||||
color: $gray;
|
||||
}
|
||||
.fa-check-square-o {
|
||||
color: $blue;
|
||||
display: none;
|
||||
margin: ($baseline * 0.15) 14px 0px 16px;
|
||||
}
|
||||
.fa-check-square-o.is-disabled {
|
||||
color: $gray;
|
||||
}
|
||||
&.is-selected {
|
||||
.fa-check-square-o {
|
||||
display: inline-block;
|
||||
}
|
||||
.fa-square-o {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.option-name {
|
||||
@extend %t-action3;
|
||||
@extend %t-strong;
|
||||
display: inline-block;
|
||||
width: 15%;
|
||||
vertical-align: top;
|
||||
}
|
||||
.explanation {
|
||||
@extend %t-action4;
|
||||
display: inline-block;
|
||||
width: 75%;
|
||||
vertical-align: top;
|
||||
color: $gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// +Form - Create New
|
||||
// ====================
|
||||
// form styling for creating a new content item (course, user, textbook)
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
// studio - elements - xblock rendering
|
||||
// ==========================
|
||||
|
||||
// styling for xblocks at various levels of nesting: page level,
|
||||
// Table of Contents
|
||||
// * +Layout - Xblocks
|
||||
// * +Licensing - Xblocks
|
||||
// * +Pagination - Xblocks
|
||||
// * +Messaging - Xblocks
|
||||
// * +Case: Page Level
|
||||
// * +Case: Nesting Level
|
||||
// * +Case: Element / Component Level
|
||||
// * +Case: Experiment Groups - Edited
|
||||
// * +Editing - Xblocks
|
||||
// * +Case - Special Xblock Type Overrides
|
||||
|
||||
// extends - UI archetypes - xblock rendering
|
||||
|
||||
// +Layout - Xblocks
|
||||
// ====================
|
||||
// styling for xblocks at various levels of nesting: page level,
|
||||
.wrapper-xblock {
|
||||
margin: ($baseline/2);
|
||||
border: 1px solid $gray-l4;
|
||||
@@ -45,7 +58,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// secondary header for meta-information and associated actions
|
||||
// UI: secondary header for meta-information and associated actions
|
||||
.xblock-header-secondary {
|
||||
overflow: hidden;
|
||||
border-top: 1px solid $gray-l3;
|
||||
@@ -103,28 +116,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
// +Licensing - Xblocks
|
||||
// ====================
|
||||
.xblock-license,
|
||||
.xmodule_display.xmodule_HtmlModule .xblock-license {
|
||||
text-align: $bi-app-right;
|
||||
.xmodule_display.xmodule_HtmlModule .xblock-license,
|
||||
.xmodule_VideoModule .xblock-license {
|
||||
@include text-align(right);
|
||||
@extend %t-title7;
|
||||
display: block;
|
||||
width: auto;
|
||||
border-top: 1px solid $gray-l3;
|
||||
margin: 0 15px;
|
||||
padding: 5px;
|
||||
font-size: 80%;
|
||||
color: $gray-l3;
|
||||
padding: ($baseline/4) 0;
|
||||
color: $gray;
|
||||
text-align: $bi-app-right;
|
||||
|
||||
.license-label,
|
||||
.license-value,
|
||||
.license-actions {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $gray-l3;
|
||||
color: $gray;
|
||||
|
||||
&:hover {
|
||||
color: $ui-link-color;
|
||||
}
|
||||
}
|
||||
span {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: xblocks video
|
||||
.xmodule_VideoModule .xblock-license {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
// +Pagination - Xblocks
|
||||
.container-paging-header {
|
||||
.meta-wrap {
|
||||
margin: $baseline ($baseline/2);
|
||||
@@ -154,12 +187,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ====================
|
||||
|
||||
//UI: default internal xblock content styles
|
||||
|
||||
// ====================
|
||||
// TO-DO: clean-up / remove this reset
|
||||
// internal headings for problems and video components
|
||||
h2 {
|
||||
@extend %t-title5;
|
||||
@@ -220,6 +250,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// +Messaging - Xblocks
|
||||
// ====================
|
||||
// xblock message area, for general information as well as validation
|
||||
.wrapper-xblock-message {
|
||||
|
||||
@@ -281,7 +313,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: page level - outer most level
|
||||
// +Case: Page Level
|
||||
// ====================
|
||||
&.level-page {
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
@@ -325,7 +358,9 @@
|
||||
|
||||
}
|
||||
|
||||
// CASE: nesting level - element wrapper level
|
||||
// +Case: Nesting Level
|
||||
// ====================
|
||||
// element wrapper level
|
||||
&.level-nesting {
|
||||
@include transition(all $tmg-f2 linear 0s);
|
||||
border: 1px solid $gray-l3;
|
||||
@@ -359,7 +394,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: element/component level
|
||||
// +Case: Element / Component Level
|
||||
// ====================
|
||||
&.level-element {
|
||||
@include transition(all $tmg-f2 linear 0s);
|
||||
box-shadow: none;
|
||||
@@ -416,7 +452,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: edited experiment groups: active and inactive
|
||||
// +Case: Experiment Groups - Edited
|
||||
// ====================
|
||||
// edited experiment groups: active and inactive
|
||||
.wrapper-groups {
|
||||
|
||||
.title {
|
||||
@@ -456,8 +494,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// +Editing - Xblocks
|
||||
// ====================
|
||||
// XBlock editing
|
||||
|
||||
// xblock Editor tab wrapper
|
||||
.wrapper-comp-editor {
|
||||
@@ -807,7 +845,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: special xblock type overrides
|
||||
|
||||
// +Case - Special Xblock Type Overrides
|
||||
// ====================
|
||||
// TO-DO - remove this reset styling from base _xblocks.scss file
|
||||
|
||||
// Latex Compiler
|
||||
// make room for the launch compiler button
|
||||
|
||||
@@ -217,27 +217,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// course content license
|
||||
// --------------------
|
||||
.course-license {
|
||||
@extend .content-primary;
|
||||
@include text-align(right);
|
||||
display: block;
|
||||
float: $bi-app-right;
|
||||
width: auto;
|
||||
|
||||
.license-label,
|
||||
.license-value,
|
||||
.license-actions {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
// REMOVE BEFORE MERGE - removed outline styling here from cms
|
||||
|
||||
.wrapper-dnd {
|
||||
clear: both;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// studio - views - course settings
|
||||
// ====================
|
||||
// Table of Contents
|
||||
// * +Settings - Base / All
|
||||
// * +Settings - Licenses
|
||||
|
||||
// +Settings - Base / All
|
||||
// ====================
|
||||
.view-settings {
|
||||
@include text-align(left);
|
||||
@include direction();
|
||||
@@ -104,10 +109,11 @@
|
||||
margin-top: ($baseline/4);
|
||||
color: $gray-d1;
|
||||
}
|
||||
.tip-inline{
|
||||
display: inline;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.tip-inline {
|
||||
display: inline;
|
||||
@include margin-left($baseline/4);
|
||||
}
|
||||
|
||||
.message-error {
|
||||
@extend %t-copy-sub1;
|
||||
@@ -149,6 +155,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#heading-entrance-exam{
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -156,6 +163,7 @@
|
||||
label[for="entrance-exam-enabled"] {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin: 0 0 ($baseline*2) 0;
|
||||
|
||||
@@ -978,3 +986,100 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// +Settings - Licenses
|
||||
// ====================
|
||||
.view-settings {
|
||||
|
||||
.license-img {
|
||||
padding: ($baseline/5);
|
||||
}
|
||||
|
||||
.license-types {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
||||
.license-type {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.action.license-button {
|
||||
@include grey-button;
|
||||
@extend %t-action2;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 220px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
|
||||
&.is-selected {
|
||||
@include blue-button;
|
||||
}
|
||||
}
|
||||
|
||||
.tip {
|
||||
@extend %t-copy-sub2;
|
||||
}
|
||||
}
|
||||
.wrapper-license-options {
|
||||
margin-bottom: ($baseline/2);
|
||||
|
||||
.tip {
|
||||
@extend %t-copy-sub2;
|
||||
}
|
||||
.license-options {
|
||||
padding-bottom: ($baseline/2);
|
||||
|
||||
.license-option {
|
||||
line-height: 1.5;
|
||||
border-bottom: 1px solid $gray-l4;
|
||||
padding: ($baseline/2) 0 ($baseline*0.4);
|
||||
|
||||
&.is-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
vertical-align: top;
|
||||
width: auto;
|
||||
min-width: auto;
|
||||
height: auto;
|
||||
border: 0;
|
||||
margin: ($baseline*0.15) 15px 0px;
|
||||
}
|
||||
|
||||
.option-name {
|
||||
@extend %t-action3;
|
||||
@extend %t-strong;
|
||||
display: inline-block;
|
||||
width: 15%;
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
}
|
||||
.explanation {
|
||||
@extend %t-action4;
|
||||
display: inline-block;
|
||||
width: 75%;
|
||||
vertical-align: top;
|
||||
color: $gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.license-preview a {
|
||||
color: $gray;
|
||||
|
||||
&:hover {
|
||||
color: $ui-link-color;
|
||||
}
|
||||
}
|
||||
.list-input.settings-list ul.license-options li {
|
||||
// to make sure the padding is correctly overridden
|
||||
padding: ($baseline / 2) 0 ($baseline * 0.4);
|
||||
}
|
||||
}
|
||||
@@ -109,13 +109,6 @@ from contentstore.utils import reverse_usage_url
|
||||
</div>
|
||||
</div>
|
||||
|
||||
% if settings.FEATURES.get("LICENSING", False):
|
||||
<div class="course-license">
|
||||
<h2 class="license-label">${_("License:")}</h2>
|
||||
<p class="license-value"><%include file="license.html" args="license=context_course.license" /></p>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
<div class="wrapper-dnd">
|
||||
<%
|
||||
course_locator = context_course.location
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<div class="license-wrapper">
|
||||
<div class="wrapper-license">
|
||||
<h3 class="label setting-label">
|
||||
<%= gettext("License Type") %>
|
||||
</h3>
|
||||
<ul class="license-types">
|
||||
<% var link_start_tpl = '<a href="{url}" target="_blank">'; %>
|
||||
<% _.each(licenseInfo, function(license, licenseType) { %>
|
||||
<li data-license="<%- licenseType %>">
|
||||
<li class="license-type" data-license="<%- licenseType %>">
|
||||
<button name="license-<%- licenseType %>"
|
||||
class="action license-button <% if(model.type === licenseType) { print("is-selected"); } %>"
|
||||
aria-pressed="<%- (model.type === licenseType).toString() %>"
|
||||
<% if (license.tooltip) { %>data-tooltip="<%- license.tooltip %>"<% } %>>
|
||||
<%- license.name %>
|
||||
</button>
|
||||
@@ -45,31 +46,23 @@
|
||||
(optionInfo.conflictsWith && _.any(optionInfo.conflictsWith, function(key) {return model.options[key];}));
|
||||
%>
|
||||
<li data-option="<%- optionKey %>"
|
||||
class="action-item license-button
|
||||
<% if (optionSelected) { print("is-selected"); } %>
|
||||
<% if (optionDisabled) { print("is-disabled"); } else { print("is-clickable"); } %>"
|
||||
class="action-item license-option
|
||||
<% if (optionSelected) { print("is-selected"); } %>
|
||||
<% if (optionDisabled) { print("is-disabled"); } else { print("is-clickable"); } %>"
|
||||
>
|
||||
<i aria-hidden="true"
|
||||
class="fa fa-fw
|
||||
<% if(optionSelected) { print("fa-check-square-o"); } else { print("fa-square-o"); } %>
|
||||
<% if(optionDisabled) { print("is-disabled"); } %>
|
||||
"></i>
|
||||
<h4 class="option-name">
|
||||
<input type="checkbox"
|
||||
id="<%- model.type %>-<%- optionKey %>"
|
||||
name="<%- model.type %>-<%- optionKey %>"
|
||||
aria-describedby="<%- optionKey %>-explanation"
|
||||
<% if(optionSelected) { print('checked="checked"'); } %>
|
||||
<% if(optionDisabled) { print('disabled="disabled"'); } %>
|
||||
/>
|
||||
<label for="<%- model.type %>-<%- optionKey %>" class="option-name">
|
||||
<%- optionInfo.name %>
|
||||
<%
|
||||
var states = [];
|
||||
if (optionSelected) {
|
||||
states.push(gettext("selected"));
|
||||
}
|
||||
if (optionDisabled) {
|
||||
states.push(gettext("disabled"));
|
||||
}
|
||||
if (states) {
|
||||
%>
|
||||
<span class="sr">, <%- states.join(", ") %></span>
|
||||
<% } %>
|
||||
</h4>
|
||||
<div class="explanation"><%- optionInfo.help %></div>
|
||||
</label>
|
||||
<div id="<%- optionKey %>-explanation" class="explanation">
|
||||
<%- optionInfo.help %>
|
||||
</div>
|
||||
</li>
|
||||
<% } // could implement other types here %>
|
||||
<% }) %>
|
||||
@@ -78,7 +71,7 @@
|
||||
<% } %>
|
||||
|
||||
<% if (showPreview) { %>
|
||||
<div class="license-preview-wrapper">
|
||||
<div class="wrapper-license-preview">
|
||||
<h4 class="label setting-label">
|
||||
<%= gettext("License Display") %>
|
||||
</h4>
|
||||
@@ -100,7 +93,7 @@
|
||||
version = model.options.ver || "1.0";
|
||||
}
|
||||
%>
|
||||
<a rel="license" href="//creativecommons.org/licenses/<%- enabled.join("-") %>/<%- version %>/">
|
||||
<a rel="license" href="https://creativecommons.org/licenses/<%- enabled.join("-") %>/<%- version %>/">
|
||||
<% if (previewButton) { %>
|
||||
<img src="https://licensebuttons.net/l/<%- enabled.join("-") %>/<%- version %>/<%- typeof buttonSize == "string" ? buttonSize : "88x31" %>.png"
|
||||
alt="<%- typeof licenseString == "string" ? licenseString : "" %>"
|
||||
|
||||
@@ -20,7 +20,6 @@ from xmodule.x_module import XModule, DEPRECATION_VSCOMPAT_EVENT
|
||||
from xmodule.xml_module import XmlDescriptor, name_to_pathname
|
||||
from xblock.core import XBlock
|
||||
from xblock.fields import Scope, String, Boolean, List
|
||||
from xmodule.mixin import LicenseMixin
|
||||
|
||||
log = logging.getLogger("edx.courseware")
|
||||
|
||||
@@ -88,7 +87,7 @@ class HtmlModule(HtmlModuleMixin):
|
||||
pass
|
||||
|
||||
|
||||
class HtmlDescriptor(HtmlFields, LicenseMixin, XmlDescriptor, EditingDescriptor): # pylint: disable=abstract-method
|
||||
class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor): # pylint: disable=abstract-method
|
||||
"""
|
||||
Module for putting raw html in a course
|
||||
"""
|
||||
|
||||
@@ -49,6 +49,7 @@ from xmodule.modulestore.edit_info import EditInfoRuntimeMixin
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, DuplicateCourseError, ReferentialIntegrityError
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin, inherit_metadata, InheritanceKeyValueStore
|
||||
from xmodule.modulestore.xml import CourseLocationManager
|
||||
from xmodule.services import SettingsService
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -900,6 +901,7 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase, Mongo
|
||||
|
||||
if self.user_service:
|
||||
services["user"] = self.user_service
|
||||
services["settings"] = SettingsService()
|
||||
|
||||
system = CachingDescriptorSystem(
|
||||
modulestore=self,
|
||||
|
||||
@@ -181,6 +181,15 @@ class SequenceDescriptor(SequenceFields, MakoModuleDescriptor, XmlDescriptor):
|
||||
self.runtime.add_block_as_child_node(child, xml_object)
|
||||
return xml_object
|
||||
|
||||
@property
|
||||
def non_editable_metadata_fields(self):
|
||||
"""
|
||||
`is_entrance_exam` should not be editable in the Studio settings editor.
|
||||
"""
|
||||
non_editable_fields = super(SequenceDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.append(self.fields['is_entrance_exam'])
|
||||
return non_editable_fields
|
||||
|
||||
def index_dictionary(self):
|
||||
"""
|
||||
Return dictionary prepared with module content and type for indexing.
|
||||
|
||||
@@ -473,7 +473,8 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes
|
||||
non_editable_fields = super(SplitTestDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.extend([
|
||||
SplitTestDescriptor.due,
|
||||
SplitTestDescriptor.user_partitions
|
||||
SplitTestDescriptor.user_partitions,
|
||||
SplitTestDescriptor.group_id_to_child,
|
||||
])
|
||||
return non_editable_fields
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ from pkg_resources import resource_string
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from xblock.core import XBlock
|
||||
from xblock.fields import ScopeIds
|
||||
from xblock.runtime import KvsFieldData
|
||||
|
||||
@@ -287,6 +288,7 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
|
||||
})
|
||||
|
||||
|
||||
@XBlock.wants("settings")
|
||||
class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandlers,
|
||||
TabsEditingDescriptor, EmptyDataRawDescriptor):
|
||||
"""
|
||||
@@ -384,6 +386,12 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
|
||||
def editable_metadata_fields(self):
|
||||
editable_fields = super(VideoDescriptor, self).editable_metadata_fields
|
||||
|
||||
settings_service = self.runtime.service(self, 'settings')
|
||||
if settings_service:
|
||||
xb_settings = settings_service.get_settings_bucket(self)
|
||||
if not xb_settings.get("licensing_enabled", False) and "license" in editable_fields:
|
||||
del editable_fields["license"]
|
||||
|
||||
if self.source_visible:
|
||||
editable_fields['source']['non_editable'] = True
|
||||
else:
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
[class^="icon-cc"], [class*=" icon-cc"] {
|
||||
font-family: 'edx-cc';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
|
||||
/* fix buttons height */
|
||||
line-height: 1em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
}
|
||||
|
||||
.icon-cc { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-by { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-nc { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-nc-eu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-nc-jp { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-sa { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-nd { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-pd { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-zero { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-share { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cc-remix { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
@@ -8,46 +8,9 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'edx-cc';
|
||||
src: url('../fonts/edx-cc/edx-cc.svg?52318265#edx-cc') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[class^="icon-cc"]:before, [class*=" icon-cc"]:before {
|
||||
[class^="icon-cc"]:before, [class*=" icon-cc"]:before {
|
||||
font-family: "edx-cc";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.icon-cc:before { content: '\e800'; } /* '' */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// studio - utilities - mixins and extends
|
||||
// common - utilities - mixins and extends
|
||||
// ====================
|
||||
|
||||
// Table of Contents
|
||||
@@ -427,3 +427,4 @@
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ def parse_license(lic):
|
||||
enabled = ["zero"]
|
||||
version = license_options.get("ver", "1.0")
|
||||
%>
|
||||
<a rel="license" href="//creativecommons.org/licenses/${'-'.join(enabled)}/${version}/">
|
||||
<a rel="license" href="https://creativecommons.org/licenses/${'-'.join(enabled)}/${version}/">
|
||||
% if button:
|
||||
<img src="https://licensebuttons.net/l/${'-'.join(enabled)}/${version}/${button_size}.png"
|
||||
alt="${license}"
|
||||
|
||||
@@ -19,6 +19,13 @@ class SettingsPage(CoursePage):
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='body.view-settings').present
|
||||
|
||||
def refresh_and_wait_for_load(self):
|
||||
"""
|
||||
Refresh the page and wait for all resources to load.
|
||||
"""
|
||||
self.browser.refresh()
|
||||
self.wait_for_page()
|
||||
|
||||
def get_elements(self, css_selector):
|
||||
self.wait_for_element_presence(
|
||||
css_selector,
|
||||
@@ -72,16 +79,35 @@ class SettingsPage(CoursePage):
|
||||
'Entrance exam minimum score percent is invisible'
|
||||
)
|
||||
|
||||
def set_course_license(self, license_type):
|
||||
css_selector = (
|
||||
"section.license ul.license-types "
|
||||
"li[data-license={license_type}] button"
|
||||
).format(license_type=license_type)
|
||||
@property
|
||||
def course_license(self):
|
||||
license_types_css = "section.license ul.license-types li.license-type"
|
||||
self.wait_for_element_presence(
|
||||
css_selector,
|
||||
'{license_type} button is present'.format(license_type=license_type)
|
||||
license_types_css,
|
||||
"license type buttons are present",
|
||||
)
|
||||
self.q(css=css_selector).click()
|
||||
selected = self.q(css=license_types_css + " button.is-selected")
|
||||
if selected.is_present():
|
||||
return selected.text[0]
|
||||
return None
|
||||
|
||||
@course_license.setter
|
||||
def course_license(self, license_name):
|
||||
license_types_css = "section.license ul.license-types li.license-type"
|
||||
self.wait_for_element_presence(
|
||||
license_types_css,
|
||||
"license type buttons are present",
|
||||
)
|
||||
button_xpath = (
|
||||
"//section[contains(@class, 'license')]"
|
||||
"//ul[contains(@class, 'license-types')]"
|
||||
"//li[contains(@class, 'license-type')]"
|
||||
"//button[contains(text(),'{license_name}')]"
|
||||
).format(license_name=license_name)
|
||||
button = self.q(xpath=button_xpath)
|
||||
if not button.present:
|
||||
raise Exception("Invalid license name: {name}".format(name=license_name))
|
||||
button.click()
|
||||
|
||||
def save_changes(self, wait_for_confirmation=True):
|
||||
"""
|
||||
|
||||
@@ -424,27 +424,49 @@ class ContentLicenseTest(StudioCourseTest):
|
||||
self.browser,
|
||||
self.course_id,
|
||||
)
|
||||
self.outline_page.visit()
|
||||
self.settings_page.visit()
|
||||
|
||||
def test_empty_license(self):
|
||||
self.assertEqual(self.outline_page.license, "None")
|
||||
"""
|
||||
When I visit the Studio settings page,
|
||||
I see that the course license is "None" by default.
|
||||
Then I visit the LMS courseware page,
|
||||
and I see that there is no course license displayed.
|
||||
"""
|
||||
self.assertIsNone(self.settings_page.course_license)
|
||||
self.lms_courseware.visit()
|
||||
self.assertIsNone(self.lms_courseware.course_license)
|
||||
|
||||
def test_arr_license(self):
|
||||
self.outline_page.edit_course_start_date()
|
||||
self.settings_page.set_course_license("all-rights-reserved")
|
||||
"""
|
||||
When I visit the Studio settings page,
|
||||
and I set the course license to "All Rights Reserved",
|
||||
and I refresh the page,
|
||||
I see that the course license is "All Rights Reserved".
|
||||
Then I visit the LMS courseware page,
|
||||
and I see that the course license is "All Rights Reserved".
|
||||
"""
|
||||
self.settings_page.course_license = "All Rights Reserved"
|
||||
self.settings_page.save_changes()
|
||||
self.outline_page.visit()
|
||||
self.assertEqual(self.outline_page.license, "© All Rights Reserved")
|
||||
self.settings_page.refresh_and_wait_for_load()
|
||||
self.assertEqual(self.settings_page.course_license, "All Rights Reserved")
|
||||
|
||||
self.lms_courseware.visit()
|
||||
self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved")
|
||||
|
||||
def test_cc_license(self):
|
||||
self.outline_page.edit_course_start_date()
|
||||
self.settings_page.set_course_license("creative-commons")
|
||||
"""
|
||||
When I visit the Studio settings page,
|
||||
and I set the course license to "Creative Commons",
|
||||
and I refresh the page,
|
||||
I see that the course license is "Creative Commons".
|
||||
Then I visit the LMS courseware page,
|
||||
and I see that the course license is "Some Rights Reserved".
|
||||
"""
|
||||
self.settings_page.course_license = "Creative Commons"
|
||||
self.settings_page.save_changes()
|
||||
self.outline_page.visit()
|
||||
self.assertEqual(self.outline_page.license, "Some Rights Reserved")
|
||||
self.settings_page.refresh_and_wait_for_load()
|
||||
self.assertEqual(self.settings_page.course_license, "Creative Commons")
|
||||
|
||||
self.lms_courseware.visit()
|
||||
self.assertEqual(self.lms_courseware.course_license, "Some Rights Reserved")
|
||||
|
||||
@@ -28,6 +28,12 @@ class VideoLicenseTest(StudioCourseTest):
|
||||
|
||||
# used by StudioCourseTest.setUp()
|
||||
def populate_course_fixture(self, course_fixture):
|
||||
"""
|
||||
Create a course with a single chapter.
|
||||
That chapter has a single section.
|
||||
That section has a single vertical.
|
||||
That vertical has a single video element.
|
||||
"""
|
||||
video_block = XBlockFixtureDesc('video', "Test Video")
|
||||
vertical = XBlockFixtureDesc('vertical', "Test Vertical")
|
||||
vertical.add_children(video_block)
|
||||
@@ -38,6 +44,11 @@ class VideoLicenseTest(StudioCourseTest):
|
||||
self.course_fixture.add_children(chapter)
|
||||
|
||||
def test_empty_license(self):
|
||||
"""
|
||||
When I visit the LMS courseware,
|
||||
I can see that the video is present
|
||||
but it has no license displayed by default.
|
||||
"""
|
||||
self.lms_courseware.visit()
|
||||
video = self.lms_courseware.q(css=".vert .xblock .video")
|
||||
self.assertTrue(video.is_present())
|
||||
@@ -45,6 +56,13 @@ class VideoLicenseTest(StudioCourseTest):
|
||||
self.assertFalse(video_license.is_present())
|
||||
|
||||
def test_arr_license(self):
|
||||
"""
|
||||
When I edit a video element in Studio,
|
||||
I can set an "All Rights Reserved" license on that video element.
|
||||
When I visit the LMS courseware,
|
||||
I can see that the video is present
|
||||
and that it has "All Rights Reserved" displayed for the license.
|
||||
"""
|
||||
self.studio_course_outline.visit()
|
||||
subsection = self.studio_course_outline.section_at(0).subsection_at(0)
|
||||
subsection.expand_subsection()
|
||||
@@ -65,6 +83,13 @@ class VideoLicenseTest(StudioCourseTest):
|
||||
self.assertEqual(video_license.text[0], "© All Rights Reserved")
|
||||
|
||||
def test_cc_license(self):
|
||||
"""
|
||||
When I edit a video element in Studio,
|
||||
I can set a "Creative Commons" license on that video element.
|
||||
When I visit the LMS courseware,
|
||||
I can see that the video is present
|
||||
and that it has "Some Rights Reserved" displayed for the license.
|
||||
"""
|
||||
self.studio_course_outline.visit()
|
||||
subsection = self.studio_course_outline.section_at(0).subsection_at(0)
|
||||
subsection.expand_subsection()
|
||||
|
||||
@@ -576,6 +576,7 @@ FACEBOOK_APP_SECRET = AUTH_TOKENS.get("FACEBOOK_APP_SECRET")
|
||||
FACEBOOK_APP_ID = AUTH_TOKENS.get("FACEBOOK_APP_ID")
|
||||
|
||||
XBLOCK_SETTINGS = ENV_TOKENS.get('XBLOCK_SETTINGS', {})
|
||||
XBLOCK_SETTINGS.setdefault("VideoDescriptor", {})["licensing_enabled"] = FEATURES.get("LICENSING", False)
|
||||
|
||||
##### CDN EXPERIMENT/MONITORING FLAGS #####
|
||||
CDN_VIDEO_URLS = ENV_TOKENS.get('CDN_VIDEO_URLS', CDN_VIDEO_URLS)
|
||||
|
||||
@@ -1277,7 +1277,6 @@ PIPELINE_CSS = {
|
||||
'source_filenames': [
|
||||
'sass/lms-main.css',
|
||||
'css/edx-cc.css',
|
||||
'css/edx-cc-ie7.css',
|
||||
],
|
||||
'output_filename': 'css/lms-main.css',
|
||||
},
|
||||
|
||||
@@ -137,25 +137,6 @@ a:focus {
|
||||
min-width: 760px;
|
||||
width: flex-grid(12);
|
||||
}
|
||||
.container-footer {
|
||||
max-width: grid-width(12);
|
||||
min-width: 760px;
|
||||
width: flex-grid(12);
|
||||
margin: 0 auto;
|
||||
text-align: $bi-app-right;
|
||||
color: $gray-l2;
|
||||
|
||||
span {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: $gray-l2;
|
||||
}
|
||||
a:active, a:hover {
|
||||
color: $blue;
|
||||
}
|
||||
}
|
||||
|
||||
span.edx {
|
||||
text-transform: none;
|
||||
|
||||
@@ -1,6 +1,40 @@
|
||||
// lms - course - base
|
||||
// ====================
|
||||
|
||||
// Table of Contents
|
||||
// * +Containers
|
||||
// * +Resets - Old, Body
|
||||
// * +Resets - Old, Forms
|
||||
// * +Resets - Old, Images
|
||||
// * +Resets - Old, Misc
|
||||
|
||||
|
||||
// +Containers
|
||||
// ====================
|
||||
|
||||
.content-wrapper {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0;
|
||||
|
||||
> div {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
border: 1px solid $outer-border-color;
|
||||
background: $container-bg;
|
||||
box-shadow: 0 1px 2px $shadow-l2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// +Resets - Old, Body
|
||||
// ====================
|
||||
|
||||
body {
|
||||
min-width: 980px;
|
||||
min-height: 100%;
|
||||
@@ -26,25 +60,8 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0;
|
||||
|
||||
> div {
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
border: 1px solid $outer-border-color;
|
||||
background: $container-bg;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
// +Resets - Old, Forms
|
||||
// ====================
|
||||
form {
|
||||
label {
|
||||
display: block;
|
||||
@@ -102,6 +119,8 @@ button,
|
||||
}
|
||||
|
||||
|
||||
// +Resets - Old, Images
|
||||
// ====================
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
@@ -134,6 +153,9 @@ img {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// +Resets - Old, Misc
|
||||
// ====================
|
||||
.test-class {
|
||||
border: 1px solid #f00;
|
||||
}
|
||||
|
||||
@@ -41,61 +41,63 @@ html.video-fullscreen{
|
||||
}
|
||||
}
|
||||
|
||||
div.course-wrapper {
|
||||
position: relative;
|
||||
.content-wrapper {
|
||||
|
||||
.course-license {
|
||||
position: absolute;
|
||||
margin: 5px auto;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
color: $gray-l3;
|
||||
|
||||
a:link, a:visited {
|
||||
color: $gray-l3;
|
||||
}
|
||||
a:active, a:hover {
|
||||
color: $link-hover;
|
||||
}
|
||||
}
|
||||
|
||||
.xblock-license {
|
||||
.container-footer {
|
||||
margin: 0 auto;
|
||||
max-width: grid-width(12);
|
||||
min-width: 760px;
|
||||
width: flex-grid(12);
|
||||
color: $gray;
|
||||
text-align: $bi-app-right;
|
||||
border-top: 1px solid $gray-l3;
|
||||
margin: 0 15px;
|
||||
padding: 5px;
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
|
||||
.course-license, .xblock-license {
|
||||
@include text-align(right);
|
||||
@extend %t-title7;
|
||||
display: block;
|
||||
width: auto;
|
||||
padding: ($baseline/4) 0;
|
||||
|
||||
span {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&, a {
|
||||
color: $gray-l3;
|
||||
|
||||
&:hover {
|
||||
color: $link-hover;
|
||||
}
|
||||
a:link, a:visited {
|
||||
color: $gray;
|
||||
}
|
||||
}
|
||||
|
||||
.xmodule_display .xblock-license,
|
||||
.xmodule_display .xblock-license a {
|
||||
color: $gray-l3;
|
||||
|
||||
&:hover {
|
||||
a:active, a:hover {
|
||||
color: $link-hover;
|
||||
}
|
||||
}
|
||||
|
||||
.xmodule_VideoModule .xblock-license {
|
||||
border: 0;
|
||||
.license-label,
|
||||
.license-value,
|
||||
.license-actions {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
img {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TO-DO should this be content wrapper?
|
||||
div.course-wrapper {
|
||||
position: relative;
|
||||
|
||||
section.course-content {
|
||||
@extend .content;
|
||||
padding: 40px;
|
||||
padding: ($baseline*2);
|
||||
line-height: 1.6;
|
||||
|
||||
h1 {
|
||||
|
||||
Reference in New Issue
Block a user