Commit cb450d50 by Xavier Antoviaque

Merge pull request #1 from open-craft/fixes

Addressed bugs from QA
parents 1b9c44da 3999ec31
"""TO-DO: Write a description of what this XBlock is."""
from collections import OrderedDict
from django.template import Template, Context
......@@ -104,8 +103,8 @@ class PollBase(XBlock, ResourceMixin, PublishEventMixin):
if image and not image_link:
result['success'] = False
result['errors'].append(
"{0} has no text or img. Please make sure all {0}s "
"have one or the other, or both.".format(noun))
"{0} has no text or img. Please make sure all {1}s "
"have one or the other, or both.".format(noun, noun.lower()))
elif not image:
result['success'] = False
# If there's a bug in the code or the user just forgot to relabel a question,
......@@ -334,11 +333,11 @@ class PollBlock(PollBase):
result['errors'].append("You must specify a question.")
result['success'] = False
answers = self.gather_items(data, result, 'Answer', 'answers')
if not result['success']:
return result
answers = self.gather_items(data, result, 'Answer', 'answers')
self.answers = answers
self.question = question
self.feedback = feedback
......@@ -375,6 +374,9 @@ class PollBlock(PollBase):
class SurveyBlock(PollBase):
display_name = String(default='Survey')
# The display name affects how the block is labeled in the studio,
# but either way we want it to say 'Poll' by default on the page.
block_name = String(default='Poll')
answers = List(
default=(
('Y', 'Yes'), ('N', 'No'),
......@@ -424,7 +426,7 @@ class SurveyBlock(PollBase):
'feedback': markdown(self.feedback) or False,
# The SDK doesn't set url_name.
'url_name': getattr(self, 'url_name', ''),
"display_name": self.display_name,
"block_name": self.block_name,
})
return self.create_fragment(
......@@ -438,7 +440,7 @@ class SurveyBlock(PollBase):
js_template = self.resource_string('/public/handlebars/poll_studio.handlebars')
context.update({
'feedback': self.feedback,
'display_name': self.display_name,
'display_name': self.block_name,
'js_template': js_template,
'multiquestion': True,
})
......@@ -567,7 +569,7 @@ class SurveyBlock(PollBase):
'answers': [
value for value in OrderedDict(self.answers).values()],
'tally': detail, 'total': total, 'feedback': markdown(self.feedback),
'plural': total > 1, 'display_name': self.display_name,
'plural': total > 1, 'block_name': self.block_name,
}
@XBlock.json_handler
......@@ -639,7 +641,7 @@ class SurveyBlock(PollBase):
result = {'success': True, 'errors': []}
feedback = data.get('feedback', '').strip()
display_name = data.get('display_name', '').strip()
block_name = data.get('display_name', '').strip()
answers = self.gather_items(data, result, 'Answer', 'answers', image=False)
questions = self.gather_items(data, result, 'Question', 'questions')
......@@ -650,7 +652,7 @@ class SurveyBlock(PollBase):
self.answers = answers
self.questions = questions
self.feedback = feedback
self.display_name = display_name
self.block_name = block_name
# Tally will not be updated until the next attempt to use it, per
# scoping limitations.
......
......@@ -110,6 +110,7 @@ li.poll-result .poll-image {
margin-top: 1em;
margin-bottom: 1em;
font-size: smaller;
font-weight: bold;
}
.survey-table {
......@@ -143,7 +144,7 @@ li.poll-result .poll-image {
}
.survey-table thead tr th {
font-weight: normal;
font-weight: bold;
font-size: .8rem;
}
......
......@@ -2,11 +2,11 @@
{{#each items}}
<li class="field comp-setting-entry is-set poll-{{noun}}-studio-item">
<div class="wrapper-comp-setting">
<label class="label setting-label poll-setting-label" for="{{noun}}-{{key}}">{{noun}}</label>
<input class="input setting-input" name="{{noun}}-{{key}}" id="{{noun}}-{{key}}" value="{{text}}" type="text" /><br />
<label class="label setting-label poll-setting-label" for="{{noun}}-label-{{key}}">{{noun}}</label>
<input class="input setting-input" name="{{noun}}-label-{{key}}" id="{{noun}}-label-{{key}}" value="{{text}}" type="text" /><br />
{{#if image}}
<label class="label setting-label" for="img-{{noun}}-{{key}}">Image URL</label>
<input class="input setting-input" name="img-{{noun}}-{{key}}" id="img-{{noun}}-{{key}}" value="{{img}}" type="text" />
<label class="label setting-label" for="{{noun}}-img-{{key}}">Image URL</label>
<input class="input setting-input" name="{{noun}}-img-{{key}}" id="{{noun}}-img-{{key}}" value="{{img}}" type="text" />
{{/if}}
<div class="poll-move">
<div class="poll-move-up">&#9650;</div>
......
<script id="survey-results-template" type="text/html">
<h3 class="poll-header">{{display_name}}</h3>
<h3 class="poll-header">{{block_name}}</h3>
<table class="survey-table">
<thead>
<tr>
......
......@@ -2,7 +2,7 @@
<div class="poll-block">
{# If no form is present, the Javascript will load the results instead. #}
{% if not choice %}
<h2 class="poll-header">{{display_name}}</h2>
<h3 class="poll-header">{{display_name}}</h3>
<form>
<div class="poll-question-container">
{{question|safe}}
......
......@@ -5,6 +5,7 @@
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label poll-setting-label" for="display_name">Display Name</label>
<!-- In the case of surveys, this field will actually be used for block_name. -->
<input class="input setting-input" name="display_name" id="poll-display-name" value="{{ display_name }}" type="text" />
</div>
</li>
......
......@@ -2,7 +2,7 @@
<div class="poll-block">
{# If no form is present, the Javascript will load the results instead. #}
{% if not choices %}
<h3 class="poll-header">{{display_name}}</h3>
<h3 class="poll-header">{{block_name}}</h3>
<form>
<table class="survey-table">
<thead>
......
......@@ -25,7 +25,9 @@ function PollEditUtil(runtime, element, pollType) {
// The degree of precision on date should be precise enough to avoid
// collisions in the real world.
var bottom = $(button_mapping[context_key]['bottomMarker']);
var new_item = $(self.answerTemplate(button_mapping[context_key]['itemList']));
var new_item_dict = self.extend({}, button_mapping[context_key]['template']);
new_item_dict['key'] = Date.now();
var new_item = $(self.answerTemplate({'items': [new_item_dict]}));
bottom.before(new_item);
self.empowerDeletes(new_item);
self.empowerArrows(
......@@ -80,7 +82,10 @@ function PollEditUtil(runtime, element, pollType) {
// 'extra' should contain 'image', a boolean value that determines whether
// an image path field should be provided, and 'noun', which should be either
// 'question' or 'answer' depending on what is needed.
return self.extend({'key': new Date().getTime(), 'text': '', 'img': ''}, extra)
// A 'key' element will have to be added after the fact, since it needs to be
// generated with the current time.
return self.extend({'text': '', 'img': ''}, extra)
};
this.empowerDeletes = function (scope) {
......@@ -125,7 +130,7 @@ function PollEditUtil(runtime, element, pollType) {
'poll': {
'buttons': {
'#poll-add-answer': {
'itemList': {'items': [self.makeNew({'image': true, 'noun': 'answer'})]},
'template': self.makeNew({'image': true, 'noun': 'answer'}),
'topMarker': '#poll-answer-marker', 'bottomMarker': '#poll-answer-end-marker'
}
},
......@@ -135,11 +140,11 @@ function PollEditUtil(runtime, element, pollType) {
'survey': {
'buttons': {
'#poll-add-answer': {
'itemList': {'items': [self.makeNew({'image': false, 'noun': 'answer'})]},
'template': self.makeNew({'image': false, 'noun': 'answer'}),
'topMarker': '#poll-answer-marker', 'bottomMarker': '#poll-answer-end-marker'
},
'#poll-add-question': {
'itemList': {'items': [self.makeNew({'image': true, 'noun': 'question'})]},
'template': self.makeNew({'image': true, 'noun': 'question'}),
'topMarker': '#poll-question-marker', 'bottomMarker': '#poll-question-end-marker'
}
},
......@@ -159,25 +164,14 @@ function PollEditUtil(runtime, element, pollType) {
self.empowerArrows(result, topMarker, bottomMarker);
};
this.checkReturn = function(data) {
// Handle the return value JSON from the server.
// It would be better if we could have a different function
// for errors, as AJAX calls normally allow, but our version of XBlock
// does not support status codes other than 200 for JSON encoded
// responses.
if (data['success']) {
window.location.reload(false);
return;
}
alert(data['errors'].join('\n'));
};
this.gather = function (scope, tracker, data, prefix, field) {
var key = 'label';
var name = scope.name.replace(prefix + '-', '');
if (scope.name.indexOf('img-') == 0){
if (name.indexOf('img-') == 0){
name = name.replace('img-', '');
key = 'img'
} else if (name.indexOf('label-') == 0){
name = name.replace('label-', '');
}
if (! (scope.name.indexOf(prefix + '-') >= 0)) {
return
......@@ -191,6 +185,16 @@ function PollEditUtil(runtime, element, pollType) {
return true
};
this.format_errors = function(errors) {
var new_list = [];
for (var line in errors) {
// Javascript has no sane HTML escape method.
// Do this instead.
new_list.push($('<div/>').text(errors[line]).html())
}
return new_list.join('<br />')
};
this.pollSubmitHandler = function () {
// Take all of the fields, serialize them, and pass them to the
// server for saving.
......@@ -211,11 +215,23 @@ function PollEditUtil(runtime, element, pollType) {
data['question'] = $('#poll-question-editor', element).val();
data['feedback'] = $('#poll-feedback-editor', element).val();
runtime.notify('save', {state: 'start', message: "Saving"});
$.ajax({
type: "POST",
url: handlerUrl,
data: JSON.stringify(data),
success: self.checkReturn
// There are issues with using proper status codes at the moment.
// So we pass along a 'success' key for now.
success: function(result) {
if (result['success']) {
runtime.notify('save', {state: 'end'})
} else {
runtime.notify('error', {
'title': 'Error saving poll',
'message': self.format_errors(result['errors'])
});
}
}
});
};
......
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