Commit 37ab2fc1 by David Baumgold Committed by Sarina Canelake

Wrap block with license info in LMS only

parent ca2fee12
define(["backbone", "underscore"], function(Backbone, _) {
var LicenseModel = Backbone.Model.extend({
defaults: {
"type": null,
"options": {},
"custom": false // either `false`, or a string
},
var LicenseModel = Backbone.Model.extend({
defaults: {
"type": null,
"options": {},
"custom": false // either `false`, or a string
},
initialize: function(attributes) {
if(attributes && attributes.asString) {
this.setFromString(attributes.asString);
this.unset("asString");
}
},
initialize: function(attributes) {
if(attributes && attributes.asString) {
this.setFromString(attributes.asString);
this.unset("asString");
}
},
toString: function() {
var custom = this.get("custom");
if (custom) {
return custom;
}
toString: function() {
var custom = this.get("custom");
if (custom) {
return custom;
}
var type = this.get("type"),
options = this.get("options");
var type = this.get("type"),
options = this.get("options");
if (_.isEmpty(options)) {
return type || "";
}
if (_.isEmpty(options)) {
return type || "";
}
// options are where it gets tricky
var optionStrings = _.map(options, function (value, key) {
if(_.isBoolean(value)) {
return value ? key : null
} else {
return key + "=" + value
}
});
// filter out nulls
optionStrings = _.filter(optionStrings, _.identity);
// build license string and return
return type + ": " + optionStrings.join(" ");
},
// options are where it gets tricky
var optionStrings = _.map(options, function (value, key) {
if(_.isBoolean(value)) {
return value ? key : null
} else {
return key + "=" + value
}
});
// filter out nulls
optionStrings = _.filter(optionStrings, _.identity);
// build license string and return
return type + ": " + optionStrings.join(" ");
},
setFromString: function(string, options) {
if (!string) {
// reset to defaults
return this.set(this.defaults, options);
}
setFromString: function(string, options) {
if (!string) {
// reset to defaults
return this.set(this.defaults, options);
}
var colonIndex = string.indexOf(":"),
spaceIndex = string.indexOf(" ");
var colonIndex = string.indexOf(":"),
spaceIndex = string.indexOf(" ");
// a string without a colon could be a custom license, or a license
// type without options
if (colonIndex == -1) {
if (spaceIndex == -1) {
// if there's no space, it's a license type without options
return this.set({
"type": string,
"options": {},
"custom": false
}, options);
} else {
// if there is a space, it's a custom license
return this.set({
"type": null,
"options": {},
"custom": string
}, options);
}
}
// a string without a colon could be a custom license, or a license
// type without options
if (colonIndex == -1) {
if (spaceIndex == -1) {
// if there's no space, it's a license type without options
return this.set({
"type": string,
"options": {},
"custom": false
}, options);
} else {
// if there is a space, it's a custom license
return this.set({
"type": null,
"options": {},
"custom": string
}, options);
}
}
// there is a colon, which indicates a license type with options.
var type = string.substring(0, colonIndex),
optionsObj = {},
optionsString = string.substring(colonIndex + 1);
// there is a colon, which indicates a license type with options.
var type = string.substring(0, colonIndex),
optionsObj = {},
optionsString = string.substring(colonIndex + 1);
_.each(optionsString.split(" "), function(optionString) {
if (_.isEmpty(optionString)) {
return;
}
var eqIndex = optionString.indexOf("=");
if(eqIndex == -1) {
// this is a boolean flag
optionsObj[optionString] = true;
} else {
// this is a key-value pair
var optionKey = optionString.substring(0, eqIndex);
var optionVal = optionString.substring(eqIndex + 1);
optionsObj[optionKey] = optionVal;
}
});
_.each(optionsString.split(" "), function(optionString) {
if (_.isEmpty(optionString)) {
return;
}
var eqIndex = optionString.indexOf("=");
if(eqIndex == -1) {
// this is a boolean flag
optionsObj[optionString] = true;
} else {
// this is a key-value pair
var optionKey = optionString.substring(0, eqIndex);
var optionVal = optionString.substring(eqIndex + 1);
optionsObj[optionKey] = optionVal;
}
});
return this.set({
"type": type, "options": optionsObj, "custom": false,
}, options);
}
});
return this.set({
"type": type, "options": optionsObj, "custom": false,
}, options);
}
});
return LicenseModel;
return LicenseModel;
});
define(["js/models/license"], function(LicenseModel) {
describe("License model constructor", function() {
it("accepts no arguments", function() {
var model = new LicenseModel()
expect(model.get("type")).toBeNull();
expect(model.get("options")).toEqual({});
expect(model.get("custom")).toBeFalsy();
});
describe("License model constructor", function() {
it("accepts no arguments", function() {
var model = new LicenseModel()
expect(model.get("type")).toBeNull();
expect(model.get("options")).toEqual({});
expect(model.get("custom")).toBeFalsy();
});
it("accepts normal arguments", function() {
var model = new LicenseModel({
"type": "creative-commons",
"options": {"fake-boolean": true, "version": "your momma"}
});
expect(model.get("type")).toEqual("creative-commons");
expect(model.get("options")).toEqual({"fake-boolean": true, "version": "your momma"});
})
it("accepts normal arguments", function() {
var model = new LicenseModel({
"type": "creative-commons",
"options": {"fake-boolean": true, "version": "your momma"}
});
expect(model.get("type")).toEqual("creative-commons");
expect(model.get("options")).toEqual({"fake-boolean": true, "version": "your momma"});
})
it("accepts a license string argument", function() {
var model = new LicenseModel({"asString": "all-rights-reserved"});
expect(model.get("type")).toEqual("all-rights-reserved");
expect(model.get("options")).toEqual({});
expect(model.get("custom")).toBeFalsy();
});
it("accepts a license string argument", function() {
var model = new LicenseModel({"asString": "all-rights-reserved"});
expect(model.get("type")).toEqual("all-rights-reserved");
expect(model.get("options")).toEqual({});
expect(model.get("custom")).toBeFalsy();
});
it("accepts a custom license argument", function() {
var model = new LicenseModel({"asString": "Mozilla Public License 2.0"})
expect(model.get("type")).toBeNull();
expect(model.get("options")).toEqual({});
expect(model.get("custom")).toEqual("Mozilla Public License 2.0");
it("accepts a custom license argument", function() {
var model = new LicenseModel({"asString": "Mozilla Public License 2.0"})
expect(model.get("type")).toBeNull();
expect(model.get("options")).toEqual({});
expect(model.get("custom")).toEqual("Mozilla Public License 2.0");
});
});
});
describe("License model", function() {
beforeEach(function() {
this.model = new LicenseModel();
});
describe("License model", function() {
beforeEach(function() {
this.model = new LicenseModel();
});
it("can parse license strings", function() {
this.model.setFromString("creative-commons: BY")
expect(this.model.get("type")).toEqual("creative-commons")
expect(this.model.get("options")).toEqual({"BY": true})
expect(this.model.get("custom")).toBeFalsy();
});
it("can parse license strings", function() {
this.model.setFromString("creative-commons: BY")
expect(this.model.get("type")).toEqual("creative-commons")
expect(this.model.get("options")).toEqual({"BY": true})
expect(this.model.get("custom")).toBeFalsy();
});
it("can stringify a null license", function() {
expect(this.model.toString()).toEqual("");
});
it("can stringify a null license", function() {
expect(this.model.toString()).toEqual("");
});
it("can stringify a simple license", function() {
this.model.set("type", "foobie thinger");
expect(this.model.toString()).toEqual("foobie thinger");
});
it("can stringify a simple license", function() {
this.model.set("type", "foobie thinger");
expect(this.model.toString()).toEqual("foobie thinger");
});
it("can stringify a license with options", function() {
this.model.set({
"type": "abc",
"options": {"ping": "pong", "bing": true, "buzz": true, "beep": false}}
);
expect(this.model.toString()).toEqual("abc: ping=pong bing buzz");
});
it("can stringify a license with options", function() {
this.model.set({
"type": "abc",
"options": {"ping": "pong", "bing": true, "buzz": true, "beep": false}}
);
expect(this.model.toString()).toEqual("abc: ping=pong bing buzz");
});
it("can stringify a custom license", function() {
this.model.set({
"type": "doesn't matter",
"options": {"ignore": "me"},
"custom": "this is my super cool license"
});
expect(this.model.toString()).toEqual("this is my super cool license");
});
})
it("can stringify a custom license", function() {
this.model.set({
"type": "doesn't matter",
"options": {"ignore": "me"},
"custom": "this is my super cool license"
});
expect(this.model.toString()).toEqual("this is my super cool license");
});
})
})
define(["js/views/license", "js/models/license", "js/common_helpers/template_helpers"],
function(LicenseView, LicenseModel, TemplateHelpers) {
describe("License view", function() {
function(LicenseView, LicenseModel, TemplateHelpers) {
describe("License view", function() {
beforeEach(function() {
TemplateHelpers.installTemplate("license-selector", true);
this.model = new LicenseModel();
this.view = new LicenseView({model: this.model});
});
beforeEach(function() {
TemplateHelpers.installTemplate("license-selector", true);
this.model = new LicenseModel();
this.view = new LicenseView({model: this.model});
});
it("renders with no license", function() {
this.view.render();
expect(this.view.$("li[data-license=all-rights-reserved] button"))
.toHaveText("All Rights Reserved");
expect(this.view.$("li[data-license=all-rights-reserved] button"))
.not.toHaveClass("is-selected");
expect(this.view.$("li[data-license=creative-commons] button"))
.toHaveText("Creative Commons");
expect(this.view.$("li[data-license=creative-commons] button"))
.not.toHaveClass("is-selected");
});
it("renders with no license", function() {
this.view.render();
expect(this.view.$("li[data-license=all-rights-reserved] button"))
.toHaveText("All Rights Reserved");
expect(this.view.$("li[data-license=all-rights-reserved] button"))
.not.toHaveClass("is-selected");
expect(this.view.$("li[data-license=creative-commons] button"))
.toHaveText("Creative Commons");
expect(this.view.$("li[data-license=creative-commons] button"))
.not.toHaveClass("is-selected");
});
it("renders with the right license selected", function() {
this.model.set("type", "all-rights-reserved");
expect(this.view.$("li[data-license=all-rights-reserved] button"))
.toHaveClass("is-selected");
expect(this.view.$("li[data-license=creative-commons] button"))
.not.toHaveClass("is-selected");
});
it("renders with the right license selected", function() {
this.model.set("type", "all-rights-reserved");
expect(this.view.$("li[data-license=all-rights-reserved] button"))
.toHaveClass("is-selected");
expect(this.view.$("li[data-license=creative-commons] button"))
.not.toHaveClass("is-selected");
});
it("switches license type on click", function() {
var arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
expect(this.model.get("type")).toBeNull();
arrBtn.click();
expect(this.model.get("type")).toEqual("all-rights-reserved");
// view has re-rendered, so get a new reference to the button
arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
expect(arrBtn).toHaveClass("is-selected");
// now switch to creative commons
var ccBtn = this.view.$("li[data-license=creative-commons] button");
ccBtn.click();
expect(this.model.get("type")).toEqual("creative-commons");
// update references again
arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
ccBtn = this.view.$("li[data-license=creative-commons] button");
expect(arrBtn).not.toHaveClass("is-selected");
expect(ccBtn).toHaveClass("is-selected");
});
it("switches license type on click", function() {
var arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
expect(this.model.get("type")).toBeNull();
arrBtn.click();
expect(this.model.get("type")).toEqual("all-rights-reserved");
// view has re-rendered, so get a new reference to the button
arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
expect(arrBtn).toHaveClass("is-selected");
// now switch to creative commons
var ccBtn = this.view.$("li[data-license=creative-commons] button");
ccBtn.click();
expect(this.model.get("type")).toEqual("creative-commons");
// update references again
arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
ccBtn = this.view.$("li[data-license=creative-commons] button");
expect(arrBtn).not.toHaveClass("is-selected");
expect(ccBtn).toHaveClass("is-selected");
});
it("sets default license options when switching license types", function() {
expect(this.model.get("options")).toEqual({});
var ccBtn = this.view.$("li[data-license=creative-commons] button");
ccBtn.click()
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
var arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
arrBtn.click()
expect(this.model.get("options")).toEqual({});
});
it("sets default license options when switching license types", function() {
expect(this.model.get("options")).toEqual({});
var ccBtn = this.view.$("li[data-license=creative-commons] button");
ccBtn.click()
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
var arrBtn = this.view.$("li[data-license=all-rights-reserved] button");
arrBtn.click()
expect(this.model.get("options")).toEqual({});
});
it("renders license options", function() {
this.model.set({"type": "creative-commons"})
expect(this.view.$("ul.license-options li[data-option=BY]"))
.toContainText("Attribution");
expect(this.view.$("ul.license-options li[data-option=NC]"))
.toContainText("Noncommercial");
expect(this.view.$("ul.license-options li[data-option=ND]"))
.toContainText("No Derivatives");
expect(this.view.$("ul.license-options li[data-option=SA]"))
.toContainText("Share Alike");
expect(this.view.$("ul.license-options li").length).toEqual(4);
});
it("renders license options", function() {
this.model.set({"type": "creative-commons"})
expect(this.view.$("ul.license-options li[data-option=BY]"))
.toContainText("Attribution");
expect(this.view.$("ul.license-options li[data-option=NC]"))
.toContainText("Noncommercial");
expect(this.view.$("ul.license-options li[data-option=ND]"))
.toContainText("No Derivatives");
expect(this.view.$("ul.license-options li[data-option=SA]"))
.toContainText("Share Alike");
expect(this.view.$("ul.license-options li").length).toEqual(4);
});
it("toggles boolean options on click", function() {
this.view.$("li[data-license=creative-commons] button").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
// toggle NC option
this.view.$("li[data-option=NC]").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": false, "ND": true, "SA": false}
);
});
it("toggles boolean options on click", function() {
this.view.$("li[data-license=creative-commons] button").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
// toggle NC option
this.view.$("li[data-option=NC]").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": false, "ND": true, "SA": false}
);
});
it("doesn't toggle disabled options", function() {
this.view.$("li[data-license=creative-commons] button").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
var BY = this.view.$("li[data-option=BY]");
expect(BY).toHaveClass("is-disabled");
// try to toggle BY option
BY.click()
// no change
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
});
it("doesn't toggle disabled options", function() {
this.view.$("li[data-license=creative-commons] button").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
var BY = this.view.$("li[data-option=BY]");
expect(BY).toHaveClass("is-disabled");
// try to toggle BY option
BY.click()
// no change
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
});
it("doesn't allow simultaneous conflicting options", function() {
this.view.$("li[data-license=creative-commons] button").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
// SA and ND conflict
var SA = this.view.$("li[data-option=SA]");
expect(SA).toHaveClass("is-disabled");
// try to turn on SA option, fail
SA.click()
// no change
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
// turn off ND
var ND = this.view.$("li[data-option=ND]");
expect(ND).not.toHaveClass("is-disabled");
ND.click()
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": false, "SA": false}
);
// turn on SA
SA = this.view.$("li[data-option=SA]");
expect(SA).not.toHaveClass("is-disabled");
SA.click()
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": false, "SA": true}
);
// try to turn on ND option, fail
ND = this.view.$("li[data-option=ND]");
expect(ND).toHaveClass("is-disabled");
ND.click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": false, "SA": true}
);
});
it("doesn't allow simultaneous conflicting options", function() {
this.view.$("li[data-license=creative-commons] button").click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
// SA and ND conflict
var SA = this.view.$("li[data-option=SA]");
expect(SA).toHaveClass("is-disabled");
// try to turn on SA option, fail
SA.click()
// no change
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": true, "SA": false}
);
// turn off ND
var ND = this.view.$("li[data-option=ND]");
expect(ND).not.toHaveClass("is-disabled");
ND.click()
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": false, "SA": false}
);
// turn on SA
SA = this.view.$("li[data-option=SA]");
expect(SA).not.toHaveClass("is-disabled");
SA.click()
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": false, "SA": true}
);
// try to turn on ND option, fail
ND = this.view.$("li[data-option=ND]");
expect(ND).toHaveClass("is-disabled");
ND.click();
expect(this.model.get("options")).toEqual(
{"ver": "4.0", "BY": true, "NC": true, "ND": false, "SA": true}
);
});
it("has no preview by default", function () {
this.view.render();
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)
});
it("has no preview by default", function () {
this.view.render();
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)
});
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("");
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");
});
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("");
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");
});
})
})
})
define(["js/views/baseview", "underscore"], function(BaseView, _) {
var defaultLicenseInfo = {
"all-rights-reserved": {
"name": gettext("All Rights Reserved"),
"tooltip": gettext("You reserve all rights for your work")
},
"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",
"options": {
"ver": {
"name": gettext("Version"),
"type": "string",
"default": "4.0",
var defaultLicenseInfo = {
"all-rights-reserved": {
"name": gettext("All Rights Reserved"),
"tooltip": gettext("You reserve all rights for your work")
},
"BY": {
"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."),
"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."),
},
"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."),
"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."),
"conflictsWith": ["ND"]
"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",
"options": {
"ver": {
"name": gettext("Version"),
"type": "string",
"default": "4.0",
},
"BY": {
"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."),
"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."),
},
"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."),
"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."),
"conflictsWith": ["ND"]
}
},
"option_order": ["BY", "NC", "ND", "SA"]
}
},
"option_order": ["BY", "NC", "ND", "SA"]
}
}
var LicenseView = BaseView.extend({
events: {
"click ul.license-types li button" : "onLicenseClick",
"click ul.license-options li": "onOptionClick"
},
var LicenseView = BaseView.extend({
events: {
"click ul.license-types li button" : "onLicenseClick",
"click ul.license-options li": "onOptionClick"
},
initialize: function(options) {
this.licenseInfo = options.licenseInfo || defaultLicenseInfo;
this.showPreview = !!options.showPreview; // coerce to boolean
this.template = this.loadTemplate("license-selector");
initialize: function(options) {
this.licenseInfo = options.licenseInfo || defaultLicenseInfo;
this.showPreview = !!options.showPreview; // coerce to boolean
this.template = this.loadTemplate("license-selector");
// Rerender when the model changes
this.listenTo(this.model, 'change', this.render);
this.render();
},
// Rerender when the model changes
this.listenTo(this.model, 'change', this.render);
this.render();
},
getDefaultOptionsForLicenseType: function(licenseType) {
if (!this.licenseInfo[licenseType]) {
// custom license type, no options
return {};
}
if (!this.licenseInfo[licenseType].options) {
// defined license type without options
return {};
}
var defaults = {};
_.each(this.licenseInfo[licenseType].options, function(value, key) {
defaults[key] = value.default;
})
return defaults;
},
getDefaultOptionsForLicenseType: function(licenseType) {
if (!this.licenseInfo[licenseType]) {
// custom license type, no options
return {};
}
if (!this.licenseInfo[licenseType].options) {
// defined license type without options
return {};
}
var defaults = {};
_.each(this.licenseInfo[licenseType].options, function(value, key) {
defaults[key] = value.default;
})
return defaults;
},
render: function() {
this.$el.html(this.template({
model: this.model.attributes,
licenseString: this.model.toString() || "",
licenseInfo: this.licenseInfo,
showPreview: this.showPreview,
previewButton: false,
}));
return this;
},
render: function() {
this.$el.html(this.template({
model: this.model.attributes,
licenseString: this.model.toString() || "",
licenseInfo: this.licenseInfo,
showPreview: this.showPreview,
previewButton: false,
}));
return this;
},
onLicenseClick: function(e) {
var $li = $(e.srcElement || e.target).closest('li');
var licenseType = $li.data("license");
this.model.set({
"type": licenseType,
"options": this.getDefaultOptionsForLicenseType(licenseType)
});
},
onLicenseClick: function(e) {
var $li = $(e.srcElement || e.target).closest('li');
var licenseType = $li.data("license");
this.model.set({
"type": licenseType,
"options": this.getDefaultOptionsForLicenseType(licenseType)
});
},
onOptionClick: function(e) {
var licenseType = this.model.get("type"),
licenseOptions = $.extend({}, this.model.get("options")),
$li = $(e.srcElement || e.target).closest('li');
onOptionClick: function(e) {
var licenseType = this.model.get("type"),
licenseOptions = $.extend({}, this.model.get("options")),
$li = $(e.srcElement || e.target).closest('li');
var optionKey = $li.data("option")
var licenseInfo = this.licenseInfo[licenseType];
var optionInfo = licenseInfo.options[optionKey];
if (optionInfo.disabled) {
// we're done here
return;
}
var currentOptionValue = licenseOptions[optionKey];
if (optionInfo.type === "boolean") {
// toggle current value
currentOptionValue = !currentOptionValue;
licenseOptions[optionKey] = currentOptionValue;
}
// check for conflicts
if (currentOptionValue && optionInfo.conflictsWith &&
_.any(optionInfo.conflictsWith, function (key) { return licenseOptions[key];})) {
// conflict! don't set new options
// need some feedback here
return;
} else {
this.model.set({"options": licenseOptions})
// Backbone has trouble identifying when objects change, so we'll
// fire the change event manually.
this.model.trigger("change change:options")
var optionKey = $li.data("option")
var licenseInfo = this.licenseInfo[licenseType];
var optionInfo = licenseInfo.options[optionKey];
if (optionInfo.disabled) {
// we're done here
return;
}
var currentOptionValue = licenseOptions[optionKey];
if (optionInfo.type === "boolean") {
// toggle current value
currentOptionValue = !currentOptionValue;
licenseOptions[optionKey] = currentOptionValue;
}
// check for conflicts
if (currentOptionValue && optionInfo.conflictsWith &&
_.any(optionInfo.conflictsWith, function (key) { return licenseOptions[key];})) {
// conflict! don't set new options
// need some feedback here
return;
} else {
this.model.set({"options": licenseOptions})
// Backbone has trouble identifying when objects change, so we'll
// fire the change event manually.
this.model.trigger("change change:options")
}
}
}
});
return LicenseView;
});
return LicenseView;
});
......@@ -6,7 +6,8 @@ define(
"js/views/video/transcripts/metadata_videolist",
"js/views/video/translations_editor"
],
function(BaseView, _, MetadataModel, AbstractEditor, FileUpload, UploadDialog, LicenseModel, LicenseView, VideoList, VideoTranslations) {
function(BaseView, _, MetadataModel, AbstractEditor, FileUpload, UploadDialog,
LicenseModel, LicenseView, VideoList, VideoTranslations) {
var Metadata = {};
Metadata.Editor = BaseView.extend({
......
<div class="license-wrapper">
<label class="label setting-label" for="list-license-types">
<%= gettext("License Type") %>
</label>
<ul class="license-types" id="list-license-types">
<% var link_start_tpl = '<a href="{url}" target="_blank">'; %>
<% _.each(licenseInfo, function(license, licenseType) { %>
<li data-license="<%- licenseType %>">
<button name="license-<%- licenseType %>" class="action license-button
<% if(model.type === licenseType) { print("is-selected"); } %>"
name="license-<%- licenseType %>"
<% if (license.tooltip) { %>data-tooltip="<%- license.tooltip %>"<% } %>>
<%- license.name %>
</button>
<p class="tip">
<% if(license.url) { %>
<a href="<%- license.url %>" target="_blank">
<%= gettext("Learn more about {license_name}")
.replace("{license_name}", license.name)
%>
</a>
<% } else { %>
&nbsp;
<% } %>
</p>
</li>
<% }) %>
</ul>
<label class="label setting-label" for="list-license-types">
<%= gettext("License Type") %>
</label>
<ul class="license-types" id="list-license-types">
<% var link_start_tpl = '<a href="{url}" target="_blank">'; %>
<% _.each(licenseInfo, function(license, licenseType) { %>
<li data-license="<%- licenseType %>">
<button name="license-<%- licenseType %>"
class="action license-button <% if(model.type === licenseType) { print("is-selected"); } %>"
<% if (license.tooltip) { %>data-tooltip="<%- license.tooltip %>"<% } %>>
<%- license.name %>
</button>
<p class="tip">
<% if(license.url) { %>
<a href="<%- license.url %>" target="_blank">
<%= gettext("Learn more about {license_name}")
.replace("{license_name}", license.name)
%>
</a>
<% } else { %>
&nbsp;
<% } %>
</p>
</li>
<% }) %>
</ul>
<% var license = licenseInfo[model.type]; %>
<% if(license && !_.isEmpty(license.options)) { %>
<div class="wrapper-license-options">
<label class="label setting-label" for="list-license-options">
<%- gettext("Options for {license_name}").replace("{license_name}", license.name) %>
</label>
<p class='tip tip-inline'>
<%- gettext("The following options are available for the {license_name} license.")
.replace("{license_name}", license.name) %>
</p>
<ul class="license-options" id="list-license-options">
<% _.each(license.option_order, function(optionKey) { %>
<% var optionInfo = license.options[optionKey]; %>
<% if (optionInfo.type == "boolean") { %>
<% var optionSelected = model.options[optionKey]; %>
<% var optionDisabled = optionInfo.disabled ||
(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"); } %>"
>
<i 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"><%- optionInfo.name %></h4>
<div class="explanation"><%- optionInfo.help %></div>
</li>
<% } // could implement other types here %>
<% }) %>
</ul>
</div>
<div class="wrapper-license-options">
<label class="label setting-label" for="list-license-options">
<%- gettext("Options for {license_name}").replace("{license_name}", license.name) %>
</label>
<p class='tip tip-inline'>
<%- gettext("The following options are available for the {license_name} license.")
.replace("{license_name}", license.name) %>
</p>
<ul class="license-options" id="list-license-options">
<% _.each(license.option_order, function(optionKey) { %>
<% var optionInfo = license.options[optionKey]; %>
<% if (optionInfo.type == "boolean") { %>
<% var optionSelected = model.options[optionKey]; %>
<% var optionDisabled = optionInfo.disabled ||
(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"); } %>"
>
<i 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"><%- optionInfo.name %></h4>
<div class="explanation"><%- optionInfo.help %></div>
</li>
<% } // could implement other types here %>
<% }) %>
</ul>
</div>
<% } %>
<% if (showPreview) { %>
<div class="license-preview-wrapper">
<label class="label setting-label" for="license-preview">
<%= gettext("License Display") %>
</label>
<p class="tip">
<%= gettext("The following message will be displayed at the bottom of the courseware pages within your course.") %>
</p>
<div id="license-preview">
<% // keep this synchronized with the contents of common/templates/license.html %>
<% if (model.type === "all-rights-reserved") { %>
© <span class="license-text"><%= gettext("All Rights Reserved") %></span>
<% } else if (model.type === "creative-commons") {
var possible = ["by", "nc", "nd", "sa"];
var enabled = _.filter(possible, function(option) {
return model.options[option] === true || model.options[option.toUpperCase()] === true;
});
var version = model.options.ver || "4.0";
if (_.isEmpty(enabled)) {
enabled = ["zero"];
version = model.options.ver || "1.0";
}
%>
<a rel="license" href="//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 : "" %>"
/>
<% } else { %>
<i class="icon-cc"></i>
<% _.each(enabled, function(option) { %>
<i class="icon-cc-<%- option %>"></i>
<% }); %>
<span class="license-text"><%= gettext("Some Rights Reserved") %></span>
<% } %>
<% } else { %>
<%= typeof licenseString == "string" ? licenseString : "" %>
<% } %>
</a>
</div>
<div class="license-preview-wrapper">
<label class="label setting-label" for="license-preview">
<%= gettext("License Display") %>
</label>
<p class="tip">
<%= gettext("The following message will be displayed at the bottom of the courseware pages within your course.") %>
</p>
<div id="license-preview">
<% // keep this synchronized with the contents of common/templates/license.html %>
<% if (model.type === "all-rights-reserved") { %>
© <span class="license-text"><%= gettext("All Rights Reserved") %></span>
<% } else if (model.type === "creative-commons") {
var possible = ["by", "nc", "nd", "sa"];
var enabled = _.filter(possible, function(option) {
return model.options[option] === true || model.options[option.toUpperCase()] === true;
});
var version = model.options.ver || "4.0";
if (_.isEmpty(enabled)) {
enabled = ["zero"];
version = model.options.ver || "1.0";
}
%>
<a rel="license" href="//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 : "" %>"
/>
<% } else { %>
<i class="icon-cc"></i>
<% _.each(enabled, function(option) { %>
<i class="icon-cc-<%- option %>"></i>
<% }); %>
<span class="license-text"><%= gettext("Some Rights Reserved") %></span>
<% } %>
<% } else { %>
<%= typeof licenseString == "string" ? licenseString : "" %>
<% } %>
</a>
</div>
<% } %>
</div>
......@@ -200,15 +200,6 @@ class CapaFields(object):
scope=Scope.settings
)
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(CapaFields, self).non_editable_metadata_fields
non_editable_fields.append(CapaFields.data)
return non_editable_fields
class CapaMixin(CapaFields):
"""
......
......@@ -41,15 +41,6 @@ class DiscussionFields(object):
)
sort_key = String(scope=Scope.settings)
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(DiscussionFields, self).non_editable_metadata_fields
non_editable_fields.append(DiscussionFields.data)
return non_editable_fields
class DiscussionModule(DiscussionFields, XModule):
js = {
......
......@@ -22,6 +22,15 @@ class EditingDescriptor(EditingFields, MakoModuleDescriptor):
"""
mako_template = "widgets/raw-edit.html"
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(EditingDescriptor, self).non_editable_metadata_fields
non_editable_fields.append(self.fields['data'])
return non_editable_fields
# cdodge: a little refactoring here, since we're basically doing the same thing
# here as with our parent class, let's call into it to get the basic fields
# set and then add our additional fields. Trying to keep it DRY.
......
......@@ -55,15 +55,6 @@ class HtmlFields(object):
scope=Scope.settings
)
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(HtmlFields, self).non_editable_metadata_fields
non_editable_fields.append(HtmlFields.data)
return non_editable_fields
class HtmlModuleMixin(HtmlFields, XModule):
"""
......@@ -312,15 +303,6 @@ class AboutFields(object):
scope=Scope.content
)
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(AboutFields, self).non_editable_metadata_fields
non_editable_fields.append(AboutFields.data)
return non_editable_fields
@XBlock.tag("detached")
class AboutModule(AboutFields, HtmlModuleMixin):
......@@ -358,15 +340,6 @@ class StaticTabFields(object):
help=_("HTML for the additional pages")
)
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(StaticTabFields, self).non_editable_metadata_fields
non_editable_fields.append(StaticTabFields.data)
return non_editable_fields
@XBlock.tag("detached")
class StaticTabModule(StaticTabFields, HtmlModuleMixin):
......@@ -401,15 +374,6 @@ class CourseInfoFields(object):
scope=Scope.content
)
@property
def non_editable_metadata_fields(self):
"""
`data` should not be editable in the Studio settings editor.
"""
non_editable_fields = super(CourseInfoFields, self).non_editable_metadata_fields
non_editable_fields.append(CourseInfoFields.data)
return non_editable_fields
@XBlock.tag("detached")
class CourseInfoModule(CourseInfoFields, HtmlModuleMixin):
......
......@@ -51,3 +51,14 @@ class LicenseMixin(XBlockMixin):
"""
if getattr(self, "license", None):
node.set('license', self.license)
def wrap_with_license(block, view, frag, context): # pylint: disable=unused-argument
"""
In the LMS, display the custom license underneath the XBlock.
"""
license = getattr(block, "license", None) # pylint: disable=redefined-builtin
if license:
context = {"license": license}
frag.content += block.runtime.render_template('license_wrapper.html', context)
return frag
......@@ -15,12 +15,6 @@ class RawDescriptor(XmlDescriptor, XMLEditingDescriptor):
"""
data = String(help="XML data for the module", default="", scope=Scope.content)
@property
def non_editable_metadata_fields(self):
non_editable_fields = super(RawDescriptor, self).non_editable_metadata_fields
non_editable_fields.append(RawDescriptor.data)
return non_editable_fields
@classmethod
def definition_from_xml(cls, xml_object, system):
return {'data': etree.tostring(xml_object, pretty_print=True, encoding='unicode')}, []
......@@ -50,12 +44,6 @@ class EmptyDataRawDescriptor(XmlDescriptor, XMLEditingDescriptor):
"""
data = String(default='', scope=Scope.content)
@property
def non_editable_metadata_fields(self):
non_editable_fields = super(EmptyDataRawDescriptor, self).non_editable_metadata_fields
non_editable_fields.append(EmptyDataRawDescriptor.data)
return non_editable_fields
@classmethod
def definition_from_xml(cls, xml_object, system):
if len(xml_object) == 0 and len(xml_object.items()) == 0:
......
<div class="xblock-license">
<%include file="license.html" args="license=license" />
</div>
......@@ -5,9 +5,4 @@
</script>
% endif
${content}
% if license:
<div class="xblock-license">
<%include file="license.html" args="license=license" />
</div>
% endif
</div>
......@@ -67,6 +67,7 @@ from openedx.core.lib.xblock_utils import (
)
from xmodule.lti_module import LTIModule
from xmodule.x_module import XModuleDescriptor
from xmodule.mixin import wrap_with_license
from xblock_django.user_service import DjangoXBlockUserService
from util.json_request import JsonResponse
from util.sandboxing import can_execute_unsafe_code, get_python_lib_zip
......@@ -533,6 +534,9 @@ def get_module_system_for_user(user, field_data_cache,
# to the Fragment content coming out of the xblocks that are about to be rendered.
block_wrappers = []
if settings.FEATURES.get("LICENSING", False):
block_wrappers.append(wrap_with_license)
# Wrap the output display in a single div to allow for the XModule
# javascript to be bound correctly
if wrap_xmodule_display is True:
......
......@@ -122,18 +122,12 @@ def wrap_xblock(
if block.name:
data['name'] = block.name
if settings.FEATURES.get("LICENSING", False):
license = getattr(block, "license", None)
else:
license = None
template_context = {
'content': block.display_name if display_name_only else frag.content,
'classes': css_classes,
'display_name': block.display_name_with_default,
'data_attributes': u' '.join(u'data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value))
for key, value in data.iteritems()),
'license': license,
}
if hasattr(frag, 'json_init_args') and frag.json_init_args is not 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