Commit 260d00f3 by Filippo Valsorda

Support incremental editing in the Studio view

parent 9b1c33f0
......@@ -7,6 +7,7 @@ import logging
import json
import webob
import copy
import urllib
from xblock.core import XBlock
from xblock.fields import Scope, String, Dict, Float
......@@ -111,6 +112,8 @@ class DragAndDropBlock(XBlock):
js_templates = load_resource('/templates/html/js_templates.html')
context = {
'js_templates': js_templates,
'self': self,
'data': urllib.quote(json.dumps(self.data)),
}
fragment = Fragment()
......
......@@ -174,8 +174,6 @@
}
.xblock--drag-and-drop .drag-builder .zone {
width: 200px;
height: 100px;
border: 1px dotted #666;
}
......
......@@ -39,7 +39,6 @@ function DragAndDropEditBlock(runtime, element) {
_fn.tpl.init();
_fn.build.clickHandlers();
_fn.build.form.zone.add();
},
clickHandlers: function() {
var $fbkTab = _fn.build.$el.feedback.tab,
......@@ -47,8 +46,20 @@ function DragAndDropEditBlock(runtime, element) {
$itemTab = _fn.build.$el.items.tab;
$(element).one('click', '.continue-button', function(e) {
// $fbkTab -> $zoneTab
e.preventDefault();
_fn.build.form.feedback(_fn.build.$el.feedback.form);
for (var i = 0; i < _fn.data.zones.length; i++) {
_fn.build.form.zone.add(_fn.data.zones[i]);
}
if (_fn.data.zones.length === 0) {
_fn.build.form.zone.add();
}
if (_fn.data.targetImg) {
_fn.$target.css('background', 'url(' + _fn.data.targetImg + ') no-repeat');
}
$fbkTab.addClass('hidden');
$zoneTab.removeClass('hidden');
......@@ -57,9 +68,16 @@ function DragAndDropEditBlock(runtime, element) {
$.placeholder.shim();
$(this).one('click', function(e) {
// $zoneTab -> $itemTab
e.preventDefault();
_fn.build.form.zone.setAll();
for (var i = 0; i < _fn.data.items.length; i++) {
_fn.build.form.item.add(_fn.data.items[i]);
}
if (_fn.data.items.length === 0) {
_fn.build.form.item.add();
}
$zoneTab.addClass('hidden');
$itemTab.removeClass('hidden');
......@@ -71,6 +89,8 @@ function DragAndDropEditBlock(runtime, element) {
$('.save-button', element).parent()
.removeClass('hidden')
.one('click', function(e) {
// $itemTab -> submit
e.preventDefault();
_fn.build.form.submit();
});
......@@ -78,7 +98,9 @@ function DragAndDropEditBlock(runtime, element) {
});
$zoneTab
.on('click', '.add-zone', _fn.build.form.zone.add)
.on('click', '.add-zone', function(e) {
_fn.build.form.zone.add();
})
.on('click', '.remove-zone', _fn.build.form.zone.remove)
.on('click', '.target-image-form button', function(e) {
e.preventDefault();
......@@ -91,14 +113,15 @@ function DragAndDropEditBlock(runtime, element) {
});
$itemTab
.on('click', '.add-item', _fn.build.form.item.add)
.on('click', '.add-item', function(e) {
_fn.build.form.item.add();
})
.on('click', '.remove-item', _fn.build.form.item.remove);
},
form: {
zone: {
count: 0,
formCount: 0,
dropdown: '',
list: [],
obj: [],
getObjByIndex: function(num) {
......@@ -107,7 +130,7 @@ function DragAndDropEditBlock(runtime, element) {
return _fn.build.form.zone.obj[i];
}
},
add: function(e) {
add: function(oldZone) {
var inputTemplate = _fn.tpl.zoneInput,
zoneTemplate = _fn.tpl.zoneElement,
name = 'zone-',
......@@ -115,9 +138,7 @@ function DragAndDropEditBlock(runtime, element) {
num,
obj;
if (e) {
e.preventDefault();
}
if (!oldZone) oldZone = {};
_fn.build.form.zone.count++;
_fn.build.form.zone.formCount++;
......@@ -126,23 +147,19 @@ function DragAndDropEditBlock(runtime, element) {
// Update zone obj
zoneObj = {
title: 'Zone ' + num,
title: oldZone.title || 'Zone ' + num,
id: name,
active: false,
index: num,
width: 200,
height: 100,
x: 0,
y: 0
width: oldZone.width || 200,
height: oldZone.height || 100,
x: oldZone.x || 0,
y: oldZone.y || 0
};
_fn.build.form.zone.obj.push(zoneObj);
// Add fields to zone position form
$elements.zones.form.append(inputTemplate({
title: 'Zone ' + num,
name: name
}));
$elements.zones.form.append(inputTemplate(zoneObj));
_fn.build.form.zone.enableDelete();
// Add zone div to target
......@@ -192,7 +209,6 @@ function DragAndDropEditBlock(runtime, element) {
});
_fn.build.form.zone.list = zones;
_fn.build.form.createDropdown(zones);
},
clickHandler: function(num) {
var $div = $('#zone-' + num, element),
......@@ -205,10 +221,6 @@ function DragAndDropEditBlock(runtime, element) {
$div.find('p').html(text);
record.title = text;
if (!record.active) {
record.active = true;
}
}).on('keyup', '.width', function(e) {
var width = $(e.currentTarget).val(),
record = _fn.build.form.zone.getObjByIndex(num);
......@@ -241,31 +253,31 @@ function DragAndDropEditBlock(runtime, element) {
len = arr.length;
for (i=0; i<len; i++) {
if (arr[i].active) {
clean.push(arr[i]);
}
}
return clean;
}
},
createDropdown: function(arr) {
createDropdown: function(selected) {
var tpl = _fn.tpl.zoneDropdown,
i,
len = arr.length,
is_sel,
arr = _fn.build.form.zone.list,
dropdown = [],
html;
for (i=0; i<len; i++) {
dropdown.push(tpl({ value: arr[i] }));
for (i=0; i<arr.length; i++) {
if (arr[i] == selected) is_sel = 'selected';
else is_sel = '';
dropdown.push(tpl({ value: arr[i], selected: is_sel }));
}
// Add option to include dummy answers
dropdown.push(tpl({ value: 'none' }));
html = dropdown.join('');
_fn.build.form.zone.dropdown = new Handlebars.SafeString(html);
_fn.build.$el.items.form.find('.zone-select').html(html);
return new Handlebars.SafeString(html);
},
feedback: function($form) {
_fn.data.feedback = {
......@@ -275,16 +287,27 @@ function DragAndDropEditBlock(runtime, element) {
},
item: {
count: 0,
add: function(e) {
add: function(oldItem) {
var $form = _fn.build.$el.items.form,
tpl = _fn.tpl.itemInput;
tpl = _fn.tpl.itemInput,
ctx = {};
if (e) {
e.preventDefault();
}
if (oldItem) ctx = oldItem;
ctx.dropdown = _fn.build.form.createDropdown(ctx.zone);
if (!oldItem) ctx.width = '190';
else ctx.width = oldItem.size.width.substr(0,
oldItem.size.width.length - 2);
if (ctx.width == 'au') ctx.width = '0';
if (!oldItem) ctx.height = '0';
else ctx.height = oldItem.size.height.substr(0,
oldItem.size.height.length - 2);
if (ctx.height == 'au') ctx.height = '0';
_fn.build.form.item.count++;
$form.append(tpl({ dropdown: _fn.build.form.zone.dropdown }));
$form.append(tpl(ctx));
_fn.build.form.item.enableDelete();
// Placeholder shim for IE9
......@@ -386,7 +409,5 @@ function DragAndDropEditBlock(runtime, element) {
runtime.notify('cancel', {});
});
$.ajax(runtime.handlerUrl(element, 'get_data')).done(function(data){
dragAndDrop.builder(data);
});
dragAndDrop.builder(window.DragAndDropV2BlockPreviousData);
}
......@@ -3,25 +3,32 @@
<div class="xblock--drag-and-drop editor-with-buttons">
{{ js_templates|safe }}
<section class="drag-builder">
<script type="text/javascript">
var DragAndDropV2BlockPreviousData = JSON.parse(decodeURIComponent('{{ data|safe }}'));
</script>
<section class="drag-builder">
<div class="tab feedback-tab">
<p class="tab-content">
Note: don't edit the question if students already answered it! Delete it and create a new one.
</p>
<section class="tab-content">
<form class="feedback-form">
<h3>Question title</h3>
<input class="display-name" />
<input class="display-name" value="{{ self.display_name }}" />
<h3>Maximum score</h3>
<input class="weight" value="1"/>
<input class="weight" value="1" value="{{ self.weight }}"/>
<h3>Question text</h3>
<textarea class="question-text"></textarea>
<textarea class="question-text">{{ self.question_text }}</textarea>
<h3>Introduction Feedback</h3>
<textarea class="intro-feedback"></textarea>
<textarea class="intro-feedback">{{ self.data.feedback.start }}</textarea>
<h3>Final Feedback</h3>
<textarea class="final-feedback"></textarea>
<textarea class="final-feedback">{{ self.data.feedback.finish }}</textarea>
</form>
</section>
</div>
......
......@@ -23,35 +23,35 @@
</script>
<script id="zone-input-tpl" type="text/html">
<div class="zone-row {{ name }}">
<div class="zone-row {{ id }}">
<label>Text</label>
<input type="text" class="title" placeholder="{{ title }}" />
<input type="text" class="title" value="{{ title }}" />
<a href="#" class="remove-zone hidden">
<div class="icon remove"></div>
</a>
<div class="layout">
<label>width</label>
<input type="text" class="size width" value="200" />
<input type="text" class="size width" value="{{ width }}" />
<label>height</label>
<input type="text" class="size height" value="100" />
<input type="text" class="size height" value="{{ height }}" />
<br />
<label>x</label>
<input type="text" class="coord x" value="0" />
<input type="text" class="coord x" value="{{ x }}" />
<label>y</label>
<input type="text" class="coord y" value="0" />
<input type="text" class="coord y" value="{{ y }}" />
</div>
</div>
</script>
<script id="zone-dropdown-tpl" type="text/html">
<option value="{{ value }}">{{ value }}</option>
<option value="{{ value }}" {{ selected }}>{{ value }}</option>
</script>
<script id="item-input-tpl" type="text/html">
<div class="item">
<div class="row">
<label>Text</label>
<input type="text" class="item-text"></input>
<input type="text" class="item-text" value="{{ displayName }}"/>
<label>Zone</label>
<select class="zone-select">{{ dropdown }}</select>
<a href="#" class="remove-item hidden">
......@@ -60,21 +60,21 @@
</div>
<div class="row">
<label>Background image URL (alternative to the text)</label>
<textarea class="background-image"></textarea>
<textarea class="background-image">{{ backgroundImage }}</textarea>
</div>
<div class="row">
<label>Success Feedback</label>
<textarea class="success-feedback"></textarea>
<textarea class="success-feedback">{{ feedback.correct }}</textarea>
</div>
<div class="row">
<label>Error Feedback</label>
<textarea class="error-feedback"></textarea>
<textarea class="error-feedback">{{ feedback.incorrect }}</textarea>
</div>
<div class="row">
<label>Width (px - 0 for auto)</label>
<input type="text" class="item-width" value="190"></input>
<input type="text" class="item-width" value="{{ width }}"></input>
<label>Height (px - 0 for auto)</label>
<input type="text" class="item-height" value="0"></input>
<input type="text" class="item-height" value="{{ height }}"></input>
</div>
</div>
</script>
......@@ -5,7 +5,6 @@
"width": 200,
"title": "Zone A",
"height": 100,
"active": true,
"y": "200",
"x": "100",
"id": "zone-1"
......@@ -15,7 +14,6 @@
"width": 200,
"title": "Zone B",
"height": 100,
"active": true,
"y": 0,
"x": 0,
"id": "zone-2"
......
......@@ -45,8 +45,7 @@ def test_templates_contents():
student_fragment = block.render('student_view', Mock())
assert_in('<section class="xblock--drag-and-drop">',
student_fragment.content)
assert_in('<option value="{{ value }}">{{ value }}</option>',
student_fragment.content)
assert_in('{{ value }}', student_fragment.content)
assert_in("Test Drag &amp; Drop", student_fragment.content)
assert_in("Question Drag &amp; Drop", student_fragment.content)
assert_in("(5 Points Possible)", student_fragment.content)
......@@ -54,8 +53,7 @@ def test_templates_contents():
studio_fragment = block.render('studio_view', Mock())
assert_in('<div class="xblock--drag-and-drop editor-with-buttons">',
studio_fragment.content)
assert_in('<option value="{{ value }}">{{ value }}</option>',
studio_fragment.content)
assert_in('{{ value }}', studio_fragment.content)
def test_studio_submit():
block = make_block()
......
......@@ -6,7 +6,6 @@
"id": "zone-1",
"height": 100,
"y": "200",
"active": true,
"x": "100",
"width": 200
},
......@@ -16,7 +15,6 @@
"id": "zone-2",
"height": 100,
"y": 0,
"active": true,
"x": 0,
"width": 200
}
......
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