Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
9e2c5ab4
Commit
9e2c5ab4
authored
Apr 20, 2016
by
asadiqbal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WL-399 Functional and UI changes
parent
a6da7159
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
556 additions
and
10 deletions
+556
-10
cms/static/js/models/settings/course_details.js
+3
-1
cms/static/js/spec/views/settings/main_spec.js
+5
-1
cms/static/js/views/instructor_info.js
+92
-0
cms/static/js/views/learning_info.js
+54
-0
cms/static/js/views/settings/main.js
+73
-6
cms/static/sass/views/_settings.scss
+178
-0
cms/templates/js/course-instructor-details.underscore
+43
-0
cms/templates/js/course-settings-learning-fields.underscore
+8
-0
cms/templates/js/mock/mock-settings-page.underscore
+32
-0
cms/templates/settings.html
+30
-2
common/lib/xmodule/xmodule/course_module.py
+24
-0
common/test/acceptance/pages/studio/settings_advanced.py
+2
-0
openedx/core/djangoapps/models/course_details.py
+12
-0
No files found.
cms/static/js/models/settings/course_details.js
View file @
9e2c5ab4
...
...
@@ -25,7 +25,9 @@ var CourseDetails = Backbone.Model.extend({
course_image_asset_path
:
''
,
// the full URL (/c4x/org/course/num/asset/filename)
pre_requisite_courses
:
[],
entrance_exam_enabled
:
''
,
entrance_exam_minimum_score_pct
:
'50'
entrance_exam_minimum_score_pct
:
'50'
,
learning_info
:
[],
instructor_info
:
{}
},
validate
:
function
(
newattrs
)
{
...
...
cms/static/js/spec/views/settings/main_spec.js
View file @
9e2c5ab4
...
...
@@ -35,7 +35,11 @@ define([
entrance_exam_enabled
:
''
,
entrance_exam_minimum_score_pct
:
'50'
,
license
:
null
,
language
:
''
language
:
''
,
learning_info
:
[],
instructor_info
:
{
'instructors'
:
[]
}
},
mockSettingsPage
=
readFixtures
(
'mock/mock-settings-page.underscore'
);
...
...
cms/static/js/views/instructor_info.js
0 → 100644
View file @
9e2c5ab4
// Backbone Application View: Instructor Information
define
([
// jshint ignore:line
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
,
'js/utils/templates'
,
"js/models/uploads"
,
"js/views/uploads"
],
function
(
$
,
_
,
Backbone
,
gettext
,
TemplateUtils
,
FileUploadModel
,
FileUploadDialog
)
{
'use strict'
;
var
InstructorInfoView
=
Backbone
.
View
.
extend
({
events
:
{
'click .remove-instructor-data'
:
'removeInstructor'
,
'click .action-upload-instructor-image'
:
"uploadInstructorImage"
},
initialize
:
function
(
options
)
{
// Set up the initial state of the attributes set for this model instance
_
.
bindAll
(
this
,
'render'
);
this
.
template
=
this
.
loadTemplate
(
'course-instructor-details'
);
this
.
model
=
options
.
model
;
},
loadTemplate
:
function
(
name
)
{
// Retrieve the corresponding template for this model
return
TemplateUtils
.
loadTemplate
(
name
);
},
render
:
function
()
{
// Assemble the render view for this model.
$
(
"span.course-instructor-details-fields"
).
empty
();
var
self
=
this
;
var
instructors
=
this
.
model
.
get
(
'instructor_info'
)[
'instructors'
];
$
.
each
(
instructors
,
function
(
index
,
data
)
{
$
(
self
.
el
).
append
(
self
.
template
({
data
:
data
,
index
:
index
,
instructors
:
instructors
.
length
}));
});
},
removeInstructor
:
function
(
event
)
{
/*
* Remove course Instructor fields.
* */
event
.
preventDefault
();
var
index
=
event
.
currentTarget
.
getAttribute
(
'data-index'
),
existing_info
=
_
.
clone
(
this
.
model
.
get
(
'instructor_info'
));
existing_info
[
'instructors'
].
splice
(
index
,
1
);
this
.
model
.
set
(
'instructor_info'
,
existing_info
);
this
.
model
.
trigger
(
"change:instructor_info"
,
this
.
model
);
this
.
render
();
},
uploadInstructorImage
:
function
(
event
)
{
/*
* Upload instructor image.
* */
event
.
preventDefault
();
var
index
=
event
.
currentTarget
.
getAttribute
(
'data-index'
),
info
=
_
.
clone
(
this
.
model
.
get
(
'instructor_info'
)),
instructor
=
info
.
instructors
[
index
];
var
upload
=
new
FileUploadModel
({
title
:
gettext
(
"Upload instructor image."
),
message
:
gettext
(
"Files must be in JPEG or PNG format."
),
mimeTypes
:
[
'image/jpeg'
,
'image/png'
]
});
var
self
=
this
;
var
modal
=
new
FileUploadDialog
({
model
:
upload
,
onSuccess
:
function
(
response
)
{
var
options
=
{
'instructor_image_asset_path'
:
response
.
asset
.
url
};
instructor
.
image
=
options
.
instructor_image_asset_path
;
self
.
model
.
set
(
'instructor_info'
,
info
);
self
.
model
.
trigger
(
"change:instructor_info"
);
self
.
render
();
}
});
modal
.
show
();
}
});
return
InstructorInfoView
;
});
cms/static/js/views/learning_info.js
0 → 100644
View file @
9e2c5ab4
// Backbone Application View: Course Learning Information
define
([
// jshint ignore:line
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
,
'js/utils/templates'
],
function
(
$
,
_
,
Backbone
,
gettext
,
TemplateUtils
)
{
'use strict'
;
var
LearningInfoView
=
Backbone
.
View
.
extend
({
events
:
{
'click .delete-course-learning-info'
:
"removeLearningInfo"
},
initialize
:
function
(
options
)
{
// Set up the initial state of the attributes set for this model instance
_
.
bindAll
(
this
,
'render'
);
this
.
template
=
this
.
loadTemplate
(
'course-settings-learning-fields'
);
this
.
model
=
options
.
model
;
},
loadTemplate
:
function
(
name
)
{
// Retrieve the corresponding template for this model
return
TemplateUtils
.
loadTemplate
(
name
);
},
render
:
function
()
{
// rendering for this model
$
(
"li.course-settings-learning-fields"
).
empty
();
var
self
=
this
;
var
learning_information
=
this
.
model
.
get
(
'learning_info'
);
$
.
each
(
learning_information
,
function
(
index
,
info
)
{
$
(
self
.
el
).
append
(
self
.
template
({
index
:
index
,
info
:
info
,
info_count
:
learning_information
.
length
}));
});
},
removeLearningInfo
:
function
(
event
)
{
/*
* Remove course learning fields.
* */
event
.
preventDefault
();
var
index
=
event
.
currentTarget
.
getAttribute
(
'data-index'
),
existing_info
=
_
.
clone
(
this
.
model
.
get
(
'learning_info'
));
existing_info
.
splice
(
index
,
1
);
this
.
model
.
set
(
'learning_info'
,
existing_info
);
this
.
render
();
}
});
return
LearningInfoView
;
});
cms/static/js/views/settings/main.js
View file @
9e2c5ab4
define
([
"js/views/validation"
,
"codemirror"
,
"underscore"
,
"jquery"
,
"jquery.ui"
,
"js/utils/date_utils"
,
"js/models/uploads"
,
"js/views/uploads"
,
"js/views/license"
,
"js/models/license"
,
define
([
"js/views/validation"
,
"codemirror"
,
"underscore"
,
"jquery"
,
"jquery.ui"
,
"js/utils/date_utils"
,
"js/
models/uploads"
,
"js/
views/uploads"
,
"js/views/license"
,
"js/models/license"
,
"common/js/components/views/feedback_notification"
,
"jquery.timepicker"
,
"date"
,
"gettext"
,
'edx-ui-toolkit/js/utils/string-utils'
],
"js/views/learning_info"
,
"js/views/instructor_info"
,
"edx-ui-toolkit/js/utils/string-utils"
],
function
(
ValidatingView
,
CodeMirror
,
_
,
$
,
ui
,
DateUtils
,
FileUploadModel
,
FileUploadDialog
,
LicenseView
,
LicenseModel
,
NotificationView
,
timepicker
,
date
,
gettext
,
StringUtils
)
{
timepicker
,
date
,
gettext
,
LearningInfoView
,
InstructorInfoView
,
StringUtils
)
{
var
DetailsView
=
ValidatingView
.
extend
({
// Model class is CMS.Models.Settings.CourseDetails
...
...
@@ -21,7 +21,9 @@ var DetailsView = ValidatingView.extend({
// would love to move to a general superclass, but event hashes don't inherit in backbone :-(
'focus :input'
:
"inputFocus"
,
'blur :input'
:
"inputUnfocus"
,
'click .action-upload-image'
:
"uploadImage"
'click .action-upload-image'
:
"uploadImage"
,
'click .add-course-learning-info'
:
"addLearningFields"
,
'click .add-course-instructor-info'
:
"addInstructorFields"
},
initialize
:
function
(
options
)
{
...
...
@@ -43,6 +45,8 @@ var DetailsView = ValidatingView.extend({
this
.
listenTo
(
this
.
model
,
'invalid'
,
this
.
handleValidationError
);
this
.
listenTo
(
this
.
model
,
'change'
,
this
.
showNotificationBar
);
this
.
listenTo
(
this
.
model
,
'change:instructor_info'
,
this
.
showNotificationBar
);
this
.
listenTo
(
this
.
model
,
'change:learning_info'
,
this
.
showNotificationBar
);
this
.
selectorToField
=
_
.
invert
(
this
.
fieldToSelectorMap
);
// handle license separately, to avoid reimplementing view logic
this
.
licenseModel
=
new
LicenseModel
({
"asString"
:
this
.
model
.
get
(
'license'
)});
...
...
@@ -60,6 +64,16 @@ var DetailsView = ValidatingView.extend({
closeIcon
:
true
}).
show
();
}
this
.
learning_info_view
=
new
LearningInfoView
({
el
:
$
(
".course-settings-learning-fields"
),
model
:
this
.
model
});
this
.
instructor_info_view
=
new
InstructorInfoView
({
el
:
$
(
".course-instructor-details-fields"
),
model
:
this
.
model
});
},
render
:
function
()
{
...
...
@@ -126,6 +140,8 @@ var DetailsView = ValidatingView.extend({
}
this
.
licenseView
.
render
();
this
.
learning_info_view
.
render
();
this
.
instructor_info_view
.
render
();
return
this
;
},
...
...
@@ -146,7 +162,36 @@ var DetailsView = ValidatingView.extend({
'course_image_asset_path'
:
'course-image-url'
,
'pre_requisite_courses'
:
'pre-requisite-course'
,
'entrance_exam_enabled'
:
'entrance-exam-enabled'
,
'entrance_exam_minimum_score_pct'
:
'entrance-exam-minimum-score-pct'
'entrance_exam_minimum_score_pct'
:
'entrance-exam-minimum-score-pct'
,
'course_settings_learning_fields'
:
'course-settings-learning-fields'
,
'add_course_learning_info'
:
'add-course-learning-info'
,
'add_course_instructor_info'
:
'add-course-instructor-info'
,
'course_learning_info'
:
'course-learning-info'
},
addLearningFields
:
function
()
{
/*
* Add new course learning fields.
* */
var
existing_info
=
_
.
clone
(
this
.
model
.
get
(
'learning_info'
)),
info
=
''
;
existing_info
[
existing_info
.
length
]
=
info
;
this
.
model
.
set
(
'learning_info'
,
existing_info
);
this
.
learning_info_view
.
render
();
},
addInstructorFields
:
function
()
{
/*
* Add new course instructor fields.
* */
var
existing_info
=
_
.
clone
(
this
.
model
.
get
(
'instructor_info'
)),
index
=
existing_info
.
instructors
.
length
,
data
=
JSON
.
parse
(
'{"name": "","title": "","organization": "","image": "","bio": ""}'
);
existing_info
.
instructors
[
index
]
=
data
;
this
.
model
.
set
(
'instructor_info'
,
existing_info
);
this
.
model
.
trigger
(
"change:instructor_info"
);
this
.
instructor_info_view
.
render
();
},
updateTime
:
function
(
e
)
{
...
...
@@ -164,7 +209,29 @@ var DetailsView = ValidatingView.extend({
$
(
e
.
currentTarget
).
attr
(
'title'
,
currentTimeText
);
},
updateModel
:
function
(
event
)
{
var
value
;
var
index
=
event
.
currentTarget
.
getAttribute
(
'data-index'
);
switch
(
event
.
currentTarget
.
id
)
{
case
'course-learning-info-'
+
index
:
value
=
$
(
event
.
currentTarget
).
val
();
var
learning_info
=
_
.
clone
(
this
.
model
.
get
(
'learning_info'
));
learning_info
[
index
]
=
value
;
this
.
model
.
set
(
'learning_info'
,
learning_info
);
break
;
case
'course-instructor-name-'
+
index
:
case
'course-instructor-title-'
+
index
:
case
'course-instructor-organization-'
+
index
:
case
'course-instructor-bio-'
+
index
:
value
=
$
(
event
.
currentTarget
).
val
();
var
field
=
event
.
currentTarget
.
getAttribute
(
'data-field'
),
instructor_info
=
_
.
clone
(
this
.
model
.
get
(
'instructor_info'
));
instructor_info
[
'instructors'
][
index
][
field
]
=
value
;
this
.
model
.
set
(
'instructor_info'
,
instructor_info
);
this
.
model
.
trigger
(
"change:instructor_info"
);
break
;
case
'course-language'
:
this
.
setField
(
event
);
break
;
case
'course-image-url'
:
this
.
setField
(
event
);
var
url
=
$
(
event
.
currentTarget
).
val
();
...
...
cms/static/sass/views/_settings.scss
View file @
9e2c5ab4
...
...
@@ -838,6 +838,184 @@
}
}
.add-new-data
{
background-color
:
$green
;
border-color
:
$green
;
color
:
$white
;
display
:
inline-block
;
padding
:
10px
20px
;
border-radius
:
3px
;
margin-bottom
:
10px
;
&
:hover
{
background-color
:
$green-l1
;
border-color
:
$green-l1
;
box-shadow
:
0
2px
1px
rgba
(
0
,
0
,
0
,
0
.2
);
}
&
.add-course-learning-info
{
margin-top
:
10px
;
}
}
&
.course-learning-info
{
.list-input
{
.course-settings-learning-fields
{
.field
{
.input-learning-info
{
width
:
88%
;
display
:
inline-block
;
}
.input-learning-info-stretch
{
width
:
100%
;
display
:
inline-block
;
}
input
[
type
=
"button"
]
{
width
:
10%
;
margin-left
:
1%
;
font-size
:
14px
;
display
:
inline-block
;
}
}
}
}
}
&
.instructor-types
{
.list-input
{
.course-instructor-details-fields
{
.field
{
width
:
30%
;
&
.field-course-instructor-bio
{
width
:
95%
;
}
&
.current-instructor-image
{
width
:
100%
;
text-align
:
left
;
padding
:
0
;
.action-upload-instructor-image
{
float
:
right
;
width
:
20%
;
border-radius
:
5px
;
background-color
:
$white
;
border
:
1px
solid
lighten
(
$blue
,
24%
);
padding
:
10px
20px
;
color
:
lighten
(
$blue
,
24%
);
font-weight
:
600
;
font-size
:
12px
;
margin-top
:
5px
;
&
:hover
{
background-color
:
lighten
(
$blue
,
24%
);
color
:
$white
;
}
}
.wrapper-instructor-image
{
margin
:
15px
auto
;
}
.new-instructor-image-url
{
width
:
65%
;
display
:
inline-block
;
}
}
}
}
&
:last-child
{
margin-bottom
:
0
;
}
}
.field-group
{
@include
clearfix
();
width
:
flex-grid
(
9
,
9
);
margin-bottom
:
(
$baseline
*
1
.5
);
border-bottom
:
1px
solid
$gray-l5
;
padding-bottom
:
(
$baseline
*
1
.5
);
&
:last-child
{
border
:
none
;
padding-bottom
:
0
;
}
.field
{
display
:
inline-block
;
vertical-align
:
top
;
width
:
flex-grid
(
3
,
6
);
margin-bottom
:
(
$baseline
/
2
);
margin-right
:
flex-gutter
();
}
// specific fields - course image
.field-course-instructor-image
{
margin-bottom
:
(
$baseline
/
2
);
padding
:
(
$baseline
/
2
)
$baseline
;
background
:
$gray-l5
;
text-align
:
center
;
.wrapper-instructor-image
{
display
:
block
;
width
:
375px
;
height
:
200px
;
overflow
:
hidden
;
margin
:
0
auto
;
border
:
1px
solid
$gray-l4
;
box-shadow
:
0
1px
1px
$shadow-l1
;
padding
:
(
$baseline
/
2
);
background
:
$white
;
}
.instructor-image
{
display
:
block
;
width
:
100%
;
min-height
:
100%
;
}
.msg
{
@extend
%t-copy-sub2
;
display
:
block
;
margin-top
:
(
$baseline
/
2
);
color
:
$gray-l3
;
}
}
.field-course-instructor-name
,
.field-course-instructor-title
,
.field-course-instructor-bio
,
.field-course-instructor-organization
{
width
:
flex-grid
(
2
,
4
);
}
.wrapper-input
{
@include
clearfix
();
width
:
flex-grid
(
9
,
9
);
.input
{
float
:
left
;
width
:
flex-grid
(
6
,
9
);
margin-right
:
flex-gutter
();
}
.action-upload-image
{
@extend
%ui-btn-flat-outline
;
float
:
right
;
width
:
flex-grid
(
2
,
9
);
margin-top
:
(
$baseline
/
4
);
padding
:
(
$baseline
/
2
)
$baseline
;
}
}
}
.actions
{
float
:
left
;
width
:
flex-grid
(
9
,
9
);
.new-button
{
@extend
%btn-primary-green
;
}
.delete-button
{
margin
:
0
;
}
}
}
// specific fields - advanced settings
&
.advanced-policies
{
...
...
cms/templates/js/course-instructor-details.underscore
0 → 100644
View file @
9e2c5ab4
<li class="field-group">
<div class="field text field-course-instructor-name">
<label for="course-instructor-name-<%- index %>"><%= gettext("Name") %></label>
<input type="text" class="long" id="course-instructor-name-<%- index %>" value="<%- data['name'] %>" data-index=<%- index %> data-field="name" placeholder="<%= gettext('Instructor Name') %>" />
<span class="tip tip-stacked"><%= gettext("Please provide a instructor name")%></span>
</div>
<div class="field text field-course-instructor-title">
<label for="course-instructor-title-<%- index %>"><%= gettext("Title") %></label>
<input type="text" class="long" id="course-instructor-title-<%- index %>" value="<%- data['title'] %>" data-index=<%- index %> data-field="title" placeholder="<%= gettext('Instructor Title') %>" />
<span class="tip tip-stacked"><%= gettext("Please provide a instructor title")%></span>
</div>
<div class="field text field-course-instructor-organization">
<label for="course-instructor-organization-<%- index %>"><%= gettext("Organization") %></label>
<input type="text" class="long" id="course-instructor-organization-<%- index %>" value = "<%- data['organization'] %>" data-index=<%- index %> data-field="organization" placeholder="<%= gettext('Organization Name') %>" />
<span class="tip tip-stacked"><%= gettext("Please provide a valid organization name")%></span>
</div>
<div class="field text field-course-instructor-bio">
<label for="course-instructor-bio-<%- index %>"><%= gettext("Bio") %></label>
<textarea class="short text" id="course-instructor-bio-<%- index %>" data-index=<%- index %> data-field="bio" placeholder="<%= gettext('Instructor Bio Details') %>" ><%- data['bio'] %></textarea>
<span class="tip tip-stacked"><%= gettext("Please provide a instructor bio details")%></span>
</div>
<div class="field image field-course-instructor-image current-instructor-image">
<label for="course-instructor-image-<%- index %>"><%= gettext("Image") %></label>
<span class="wrapper-instructor-image">
<img class="instructor-image" id="instructor-image" src="<%= data['image']%>" alt="<%= gettext('Instructor Image') %>" />
</span>
<input type="text" dir="ltr" class="long new-instructor-image-url" id="course-instructor-image-<%- index %>" value="<%- data['image'] %>" data-field="image" placeholder="<%= gettext('Instructor Image URL') %>" autocomplete="off" />
<button type="button" class="action action-upload-instructor-image" data-index=<%- index %>><%= gettext("Upload Image") %></button>
<span class="tip tip-stacked"><%= gettext("Please provide a valid path and name to your image (Note: only JPEG or PNG format supported)")%></span>
</div>
<% if (instructors > 1 ) { %>
<div class="actions">
<a href="#" class="button delete-button standard remove-item remove-instructor-data" data-index=<%- index %>><span class="delete-icon"></span><%= gettext("Delete") %></a>
</div>
<% } %>
</li>
\ No newline at end of file
cms/templates/js/course-settings-learning-fields.underscore
0 → 100644
View file @
9e2c5ab4
<div class="field text" id="fields-course-learning-info-<%- index %>">
<label for= "course-learning-info-<%- index %>"> <%- gettext("What You'll Learn") %></label>
<input type="text" class=<% if (info_count > 1) { %>"input-learning-info" <% } else { %> "input-learning-info-stretch" <% } %> id="course-learning-info-<%- index %>" value="<%- info %>" data-index=<%- index %>>
<% if (info_count > 1 ) { %>
<input type="button" value='Delete' class="button delete-button standard remove-item delete-course-learning-info" data-index=<%- index %>>
<% } %>
</div>
\ No newline at end of file
cms/templates/js/mock/mock-settings-page.underscore
View file @
9e2c5ab4
...
...
@@ -107,4 +107,36 @@
</li>
</ol>
</section>
<section class="group-settings course-learning-info">
<header>
<h2 class="title-2">Course Learning Information</h2>
<span class="tip">Provide the course learning details</span>
</header>
<ol class="list-input enum">
<li class="course-settings-learning-fields">
<div class="field text" id="fields-course-learning-info-0">
<label for="course-learning-info-0" class=""> What You'll Learn</label>
<input type="text" class="input-learning-info-stretch" id="course-learning-info-0">
</div>
</li>
<li>
<a href="javascript:void(0)" class="add-course-learning-info">Add Learning Details</a></li>
</ol>
</section>
<section class="group-settings instructor-types">
<header>
<h2 class="title-2">Course Instructors Information</h2>
<span class="tip">Information for course instructors</span>
</header>
<ol class="list-input enum">
<span class="course-instructor-details-fields">
</span>
<li>
<a href="javascript:void(0)" class="add-course-instructor-info add-new-data">
Add Instructor Details</a>
</li>
</ol>
</section>
</form>
cms/templates/settings.html
View file @
9e2c5ab4
...
...
@@ -14,7 +14,7 @@
%
>
<
%
block
name=
"header_extras"
>
% for template_name in ["basic-modal", "modal-button", "upload-dialog", "license-selector"]:
% for template_name in ["basic-modal", "modal-button", "upload-dialog", "license-selector"
, "course-settings-learning-fields", "course-instructor-details"
]:
<script
type=
"text/template"
id=
"${template_name}-tpl"
>
<%
static
:
include
path
=
"js/${template_name}.underscore"
/>
</script>
...
...
@@ -386,10 +386,38 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'
<span
class=
"tip tip-stacked"
>
${_("Enter your YouTube video's ID (along with any restriction parameters)")}
</span>
</div>
</li>
% endif
% endif
</ol>
</section>
<hr
class=
"divide"
/>
<section
class=
"group-settings course-learning-info"
>
<header>
<h2
class=
"title-2"
>
${_("Course Learning Information")}
</h2>
<span
class=
"tip"
>
${_("Provide the course learning details")}
</span>
</header>
<ol
class=
"list-input enum"
>
<li
class=
"course-settings-learning-fields"
></li>
<li>
<a
href=
"javascript:void(0)"
class=
"action action-primary button new-button add-new-data add-course-learning-info"
>
<i
class=
"icon fa fa-plus icon-inline"
></i>
${_("Add Learning Details")}
</a>
</li>
</ol>
</section>
<hr
class=
"divide"
/>
<section
class=
"group-settings instructor-types"
>
<header>
<h2
class=
"title-2"
>
${_("Course Instructors Information")}
</h2>
<span
class=
"tip"
>
${_("Information for course instructors")}
</span>
</header>
<ol
class=
"list-input enum"
>
<span
class=
"course-instructor-details-fields"
></span>
<li>
<a
href=
"javascript:void(0)"
class=
"action action-primary button new-button add-course-instructor-info add-new-data"
>
<i
class=
"icon fa fa-plus icon-inline"
></i>
${_("Add Instructor Details")}
</a>
</li>
</ol>
</section>
% if about_page_editable or is_prerequisite_courses_enabled or is_entrance_exams_enabled:
<hr
class=
"divide"
/>
...
...
common/lib/xmodule/xmodule/course_module.py
View file @
9e2c5ab4
...
...
@@ -774,6 +774,30 @@ class CourseFields(object):
scope
=
Scope
.
settings
)
learning_info
=
List
(
display_name
=
_
(
"Course Learning Information"
),
help
=
_
(
"Specify what student can learn from the course."
),
default
=
[
''
],
scope
=
Scope
.
settings
)
instructor_info
=
Dict
(
display_name
=
_
(
"Course Instructor"
),
help
=
_
(
"Enter the details for Course Instructor"
),
default
=
{
"instructors"
:
[
{
"name"
:
""
,
"title"
:
""
,
"organization"
:
""
,
"image"
:
""
,
"bio"
:
""
,
},
]
},
scope
=
Scope
.
settings
)
class
CourseModule
(
CourseFields
,
SequenceModule
):
# pylint: disable=abstract-method
"""
...
...
common/test/acceptance/pages/studio/settings_advanced.py
View file @
9e2c5ab4
...
...
@@ -217,4 +217,6 @@ class AdvancedSettingsPage(CoursePage):
'enable_proctored_exams'
,
'enable_timed_exams'
,
'enable_subsection_gating'
,
'learning_info'
,
'instructor_info'
]
openedx/core/djangoapps/models/course_details.py
View file @
9e2c5ab4
...
...
@@ -66,6 +66,8 @@ class CourseDetails(object):
'50'
)
# minimum passing score for entrance exam content module/tree,
self
.
self_paced
=
None
self
.
learning_info
=
[]
self
.
instructor_info
=
[]
@classmethod
def
fetch_about_attribute
(
cls
,
course_key
,
attribute
):
...
...
@@ -100,6 +102,8 @@ class CourseDetails(object):
course_details
.
course_image_asset_path
=
course_image_url
(
descriptor
)
course_details
.
language
=
descriptor
.
language
course_details
.
self_paced
=
descriptor
.
self_paced
course_details
.
learning_info
=
descriptor
.
learning_info
course_details
.
instructor_info
=
descriptor
.
instructor_info
# Default course license is "All Rights Reserved"
course_details
.
license
=
getattr
(
descriptor
,
"license"
,
"all-rights-reserved"
)
...
...
@@ -226,6 +230,14 @@ class CourseDetails(object):
descriptor
.
license
=
jsondict
[
'license'
]
dirty
=
True
if
'learning_info'
in
jsondict
:
descriptor
.
learning_info
=
jsondict
[
'learning_info'
]
dirty
=
True
if
'instructor_info'
in
jsondict
:
descriptor
.
instructor_info
=
jsondict
[
'instructor_info'
]
dirty
=
True
if
'language'
in
jsondict
and
jsondict
[
'language'
]
!=
descriptor
.
language
:
descriptor
.
language
=
jsondict
[
'language'
]
dirty
=
True
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment