diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py
index 6f428ee3e8..74ff6657ea 100644
--- a/cms/djangoapps/contentstore/views.py
+++ b/cms/djangoapps/contentstore/views.py
@@ -104,12 +104,14 @@ def edit_item(request):
item = modulestore().get_item(item_location)
item.get_html = wrap_xmodule(item.get_html, item, "xmodule_edit.html")
+
return render_to_response('unit.html', {
'contents': item.get_html(),
'js_module': item.js_module_name,
'category': item.category,
'url_name': item.url_name,
'previews': get_module_previews(request, item),
+ 'metadata': item.metadata
})
@@ -284,6 +286,19 @@ def save_item(request):
children = request.POST['children']
modulestore().update_children(item_location, children)
+ # cdodge: also commit any metadata which might have been passed along in the
+ # POST from the client, if it is there
+ # note, that the postback is not the complete metadata, as there's system metadata which is
+ # not presented to the end-user for editing. So let's fetch the original and
+ # 'apply' the submitted metadata, so we don't end up deleting system metadata
+ if request.POST['metadata']:
+ posted_metadata = request.POST['metadata']
+ # fetch original
+ existing_item = modulestore().get_item(item_location)
+ # update existing metadata with submitted metadata (which can be partial)
+ existing_item.metadata.update(posted_metadata)
+ modulestore().update_metadata(item_location, existing_item.metadata)
+
# Export the course back to github
# This uses wildcarding to find the course, which requires handling
# multiple courses returned, but there should only ever be one
diff --git a/cms/static/coffee/src/models/module.coffee b/cms/static/coffee/src/models/module.coffee
index e2f911e9bd..52357795ed 100644
--- a/cms/static/coffee/src/models/module.coffee
+++ b/cms/static/coffee/src/models/module.coffee
@@ -3,14 +3,26 @@ class CMS.Models.Module extends Backbone.Model
defaults:
data: ''
children: ''
+ metadata: {}
loadModule: (element) ->
elt = $(element).find('.xmodule_edit').first()
@module = XModule.loadModule(elt)
+ # find the metadata edit region which should be setup server side,
+ # so that we can wire up posting back those changes
+ @metadata_elt = $(element).find('.metadata_edit')
editUrl: ->
"/edit_item?#{$.param(id: @get('id'))}"
save: (args...) ->
@set(data: @module.save()) if @module
+ # cdodge: package up metadata which is separated into a number of input fields
+ # there's probably a better way to do this, but at least this lets me continue to move onwards
+ if @metadata_elt
+ _metadata = {}
+ # walk through the set of elments which have the 'xmetadata_name' attribute and
+ # build up a object to pass back to the server on the subsequent POST
+ _metadata[$(el).data("metadata-name")]=el.value for el in $('[data-metadata-name]', @metadata_elt)
+ @set(metadata: _metadata)
super(args...)
diff --git a/cms/templates/widgets/html-edit.html b/cms/templates/widgets/html-edit.html
index 1e86c6c734..9f7196b6e4 100644
--- a/cms/templates/widgets/html-edit.html
+++ b/cms/templates/widgets/html-edit.html
@@ -1,3 +1,4 @@
+<%include file="metadata-edit.html" />
diff --git a/cms/templates/widgets/metadata-edit.html b/cms/templates/widgets/metadata-edit.html
new file mode 100644
index 0000000000..62d5563047
--- /dev/null
+++ b/cms/templates/widgets/metadata-edit.html
@@ -0,0 +1,10 @@
+% if metadata:
+
+% endif
diff --git a/cms/templates/widgets/raw-edit.html b/cms/templates/widgets/raw-edit.html
index fbd1757be5..9488552be5 100644
--- a/cms/templates/widgets/raw-edit.html
+++ b/cms/templates/widgets/raw-edit.html
@@ -1,3 +1,4 @@
+<%include file="metadata-edit.html" />
diff --git a/cms/templates/widgets/sequence-edit.html b/cms/templates/widgets/sequence-edit.html
index 242bfeae21..e9d796784d 100644
--- a/cms/templates/widgets/sequence-edit.html
+++ b/cms/templates/widgets/sequence-edit.html
@@ -29,6 +29,7 @@
+ <%include file="metadata-edit.html" />
diff --git a/common/djangoapps/util/json_request.py b/common/djangoapps/util/json_request.py
index 391905e574..169a7e3fb4 100644
--- a/common/djangoapps/util/json_request.py
+++ b/common/djangoapps/util/json_request.py
@@ -6,7 +6,9 @@ import json
def expect_json(view_function):
@wraps(view_function)
def expect_json_with_cloned_request(request, *args, **kwargs):
- if request.META['CONTENT_TYPE'] == "application/json":
+ # cdodge: fix postback errors in CMS. The POST 'content-type' header can include additional information
+ # e.g. 'charset', so we can't do a direct string compare
+ if request.META['CONTENT_TYPE'].lower().startswith("application/json"):
cloned_request = copy.copy(request)
cloned_request.POST = cloned_request.POST.copy()
cloned_request.POST.update(json.loads(request.body))
diff --git a/common/lib/xmodule/xmodule/editing_module.py b/common/lib/xmodule/xmodule/editing_module.py
index 67a4d66dad..833d994b99 100644
--- a/common/lib/xmodule/xmodule/editing_module.py
+++ b/common/lib/xmodule/xmodule/editing_module.py
@@ -17,13 +17,13 @@ class EditingDescriptor(MakoModuleDescriptor):
js = {'coffee': [resource_string(__name__, 'js/src/raw/edit.coffee')]}
js_module_name = "RawDescriptor"
- def get_context(self):
- return {
- 'module': self,
- 'data': self.definition.get('data', ''),
- # TODO (vshnayder): allow children and metadata to be edited.
- #'children' : self.definition.get('children, ''),
- # TODO: show both own metadata and inherited?
- #'metadata' : self.own_metadata,
- }
+ # 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.
+ def get_context(self):
+ _context = MakoModuleDescriptor.get_context(self)
+ # Add our specific template information (the raw data body)
+ _context.update({ 'data' : self.definition.get('data','') })
+ return _context
+
diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py
index eedac99aa8..f5f2fae23b 100644
--- a/common/lib/xmodule/xmodule/mako_module.py
+++ b/common/lib/xmodule/xmodule/mako_module.py
@@ -1,4 +1,5 @@
from x_module import XModuleDescriptor, DescriptorSystem
+import logging
class MakoDescriptorSystem(DescriptorSystem):
@@ -31,8 +32,18 @@ class MakoModuleDescriptor(XModuleDescriptor):
"""
Return the context to render the mako template with
"""
- return {'module': self}
+ return {'module': self,
+ 'metadata': self.metadata,
+ 'editable_metadata_fields' : self.editable_metadata_fields
+ }
def get_html(self):
return self.system.render_template(
self.mako_template, self.get_context())
+
+ # cdodge: encapsulate a means to expose "editable" metadata fields (i.e. not internal system metadata)
+ @property
+ def editable_metadata_fields(self):
+ subset = [name for name in self.metadata.keys() if name not in self.system_metadata_fields]
+ return subset
+
diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py
index 841936cf17..8592d4b38c 100644
--- a/common/lib/xmodule/xmodule/seq_module.py
+++ b/common/lib/xmodule/xmodule/seq_module.py
@@ -9,6 +9,7 @@ from xmodule.x_module import XModule
from xmodule.progress import Progress
from xmodule.exceptions import NotFoundError
from pkg_resources import resource_string
+from .editing_module import EditingDescriptor
log = logging.getLogger("mitx.common.lib.seq_module")
@@ -95,7 +96,8 @@ class SequenceModule(XModule):
'element_id': self.location.html_id(),
'item_id': self.id,
'position': self.position,
- 'tag': self.location.category}
+ 'tag': self.location.category
+ }
self.content = self.system.render_template('seq_module.html', params)
self.rendered = True
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index 8846926e05..90982d1955 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -352,6 +352,10 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
'data_dir'
)
+ # cdodge: this is a list of metadata names which are 'system' metadata
+ # and should not be edited by an end-user
+ system_metadata_fields = [ 'data_dir' ]
+
# A list of descriptor attributes that must be equal for the descriptors to
# be equal
equality_attributes = ('definition', 'metadata', 'location',