diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py
index 1ab78c7c90..8bd55bf60f 100644
--- a/cms/djangoapps/contentstore/views.py
+++ b/cms/djangoapps/contentstore/views.py
@@ -1,7 +1,11 @@
from mitxmako.shortcuts import render_to_response
from keystore.django import keystore
+from django_future.csrf import ensure_csrf_cookie
+from django.http import HttpResponse
+import json
+@ensure_csrf_cookie
def index(request):
# TODO (cpennington): These need to be read in from the active user
org = 'mit.edu'
@@ -20,3 +24,10 @@ def edit_item(request):
'type': item.type,
'name': item.name,
})
+
+
+def save_item(request):
+ item_id = request.POST['id']
+ data = json.loads(request.POST['data'])
+ keystore().update_item(item_id, data)
+ return HttpResponse(json.dumps({}))
diff --git a/cms/envs/common.py b/cms/envs/common.py
index d5e84c836c..fc721ca820 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -22,6 +22,8 @@ Longer TODO:
import sys
import tempfile
import os.path
+import os
+import errno
from path import path
############################ FEATURE CONFIGURATION #############################
@@ -156,7 +158,15 @@ PIPELINE_CSS = {
PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss']
from x_module import XModuleDescriptor
-js_file_dir = tempfile.mkdtemp('js', dir=PROJECT_ROOT / "static")
+js_file_dir = PROJECT_ROOT / "static" / "coffee" / "module"
+try:
+ os.makedirs(js_file_dir)
+except OSError as exc:
+ if exc.errno == errno.EEXIST:
+ pass
+ else:
+ raise
+
module_js_sources = []
for xmodule in XModuleDescriptor.load_classes():
js = xmodule.get_javascript()
@@ -172,7 +182,7 @@ for xmodule in XModuleDescriptor.load_classes():
PIPELINE_JS = {
'main': {
- 'source_filenames': ['coffee/main.coffee'],
+ 'source_filenames': ['coffee/main.coffee', 'coffee/unit.coffee'],
'output_filename': 'js/main.js',
},
'module-js': {
diff --git a/cms/static/.gitignore b/cms/static/.gitignore
deleted file mode 100644
index 61e4416e07..0000000000
--- a/cms/static/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-tmp*js
diff --git a/cms/static/coffee/.gitignore b/cms/static/coffee/.gitignore
index a6c7c2852d..bb90193362 100644
--- a/cms/static/coffee/.gitignore
+++ b/cms/static/coffee/.gitignore
@@ -1 +1,2 @@
*.js
+module
diff --git a/cms/static/coffee/main.coffee b/cms/static/coffee/main.coffee
index b74cd3c7d3..ce7f29cc1e 100644
--- a/cms/static/coffee/main.coffee
+++ b/cms/static/coffee/main.coffee
@@ -3,16 +3,18 @@ bind_edit_links = ->
edit_item($(this).attr('id'))
return false
-edit_item = (id) ->
- $.get('/edit_item', {id: id}, (data) ->
+edit_item = (id) =>
+ $.get('/edit_item', {id: id}, (data) =>
$('#module-html').empty().append(data)
bind_edit_links()
$('section.edit-pane').show()
$('body').addClass('content')
- new window[$('#unit-wrapper').attr('class')] 'module-html'
+ new @Unit('unit-wrapper', id)
)
$ ->
+ $.ajaxSetup
+ headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
$('section.main-content').children().hide()
$('.editable').inlineEdit()
$('.editable-textarea').inlineEdit({control: 'textarea'})
diff --git a/cms/static/coffee/unit.coffee b/cms/static/coffee/unit.coffee
new file mode 100644
index 0000000000..f41bd7f96a
--- /dev/null
+++ b/cms/static/coffee/unit.coffee
@@ -0,0 +1,13 @@
+class @Unit
+ constructor: (@element_id, @module_id) ->
+ @module = new window[$("##{@element_id}").attr('class')] 'module-html'
+
+ $("##{@element_id} .save-update").click( (event) =>
+ event.preventDefault()
+ $.post("save_item", {
+ id: @module_id
+ data: JSON.stringify(@module.save())
+ })
+
+ )
+
diff --git a/cms/static/js/jquery.cookie.js b/cms/static/js/jquery.cookie.js
new file mode 100644
index 0000000000..6d5974a2c5
--- /dev/null
+++ b/cms/static/js/jquery.cookie.js
@@ -0,0 +1,47 @@
+/*!
+ * jQuery Cookie Plugin
+ * https://github.com/carhartl/jquery-cookie
+ *
+ * Copyright 2011, Klaus Hartl
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.opensource.org/licenses/GPL-2.0
+ */
+(function($) {
+ $.cookie = function(key, value, options) {
+
+ // key and at least value given, set cookie...
+ if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
+ options = $.extend({}, options);
+
+ if (value === null || value === undefined) {
+ options.expires = -1;
+ }
+
+ if (typeof options.expires === 'number') {
+ var days = options.expires, t = options.expires = new Date();
+ t.setDate(t.getDate() + days);
+ }
+
+ value = String(value);
+
+ return (document.cookie = [
+ encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
+ options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+ options.path ? '; path=' + options.path : '',
+ options.domain ? '; domain=' + options.domain : '',
+ options.secure ? '; secure' : ''
+ ].join(''));
+ }
+
+ // key and possibly options given, get cookie...
+ options = value || {};
+ var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
+
+ var pairs = document.cookie.split('; ');
+ for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
+ if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
+ }
+ return null;
+ };
+})(jQuery);
diff --git a/cms/templates/base.html b/cms/templates/base.html
index 3d35f513ab..12df2b7a28 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -34,6 +34,7 @@
<%static:js group='module-js'/>
+