Commit 866f7529 by Jonathan Piacenti

Studio view and images implemented for Surveys.

parent 21ab57d0
...@@ -78,10 +78,18 @@ li.poll-result .poll-image { ...@@ -78,10 +78,18 @@ li.poll-result .poll-image {
margin-left: 0; margin-left: 0;
} }
.poll-image img{ .poll-image-td {
width: 25%;
}
.poll-image img, .poll-image-td img{
width: 100%; width: 100%;
} }
.poll-image-td{
display: inline-block;
}
.poll-percent-container { .poll-percent-container {
display: table-cell; display: table-cell;
text-align: left; text-align: left;
...@@ -154,7 +162,9 @@ li.poll-result .poll-image { ...@@ -154,7 +162,9 @@ li.poll-result .poll-image {
th.survey-answer { th.survey-answer {
text-align: center; text-align: center;
width: 2em; width: 7%;
line-height: 1em;
padding-bottom: .25em;
} }
.poll-header { .poll-header {
...@@ -168,6 +178,7 @@ th.survey-answer { ...@@ -168,6 +178,7 @@ th.survey-answer {
.survey-question { .survey-question {
font-weight: bold; font-weight: bold;
vertical-align: middle;
} }
.survey-choice { .survey-choice {
......
<script id="answer-form-component" type="text/html"> <script id="poll-form-component" type="text/html">
{{#each items}} {{#each items}}
<li class="field comp-setting-entry is-set poll-{{noun}}-studio-item"> <li class="field comp-setting-entry is-set poll-{{noun}}-studio-item">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
......
...@@ -11,6 +11,12 @@ ...@@ -11,6 +11,12 @@
</thead> </thead>
{{#each tally}} {{#each tally}}
<tr class="survey-row"> <tr class="survey-row">
{{#if img}}
<div class="poll-image-td">
<img src="{{img}}" />
</div>
{{/if}}
{% endif %}
<td class="survey-question">{{{text}}}</td> <td class="survey-question">{{{text}}}</td>
{{#each answers}} {{#each answers}}
<td class="survey-percentage survey-option{{#if choice}} survey-choice{{/if}}{{#if top}} poll-top-choice{{/if}}">{{percent}}%</td> <td class="survey-percentage survey-option{{#if choice}} survey-choice{{/if}}{{#if top}} poll-top-choice{{/if}}">{{percent}}%</td>
......
...@@ -3,6 +3,13 @@ ...@@ -3,6 +3,13 @@
<form id="poll-form"> <form id="poll-form">
<ul class="list-input settings-list" id="poll-line-items"> <ul class="list-input settings-list" id="poll-line-items">
<li class="field comp-setting-entry is-set"> <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>
<input class="input setting-input" name="display_name" id="poll-display-name" value="{{ display_name }}" type="text" />
</div>
</li>
{% if not multiquestion %}
<li class="field comp-setting-entry is-set">
<h2><label for="poll-question-editor">Question/Prompt</label></h2> <h2><label for="poll-question-editor">Question/Prompt</label></h2>
<a href="//daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Syntax</a> is supported. <a href="//daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Syntax</a> is supported.
<div id="poll-question-editor-container"> <div id="poll-question-editor-container">
...@@ -10,6 +17,7 @@ ...@@ -10,6 +17,7 @@
</div> </div>
<span class="tip setting-help">Enter the prompt for the user.</span> <span class="tip setting-help">Enter the prompt for the user.</span>
</li> </li>
{% endif %}
<li class="field comp-setting-entry is-set"> <li class="field comp-setting-entry is-set">
<h2><label for="poll-feedback-editor">Feedback</label></h2> <h2><label for="poll-feedback-editor">Feedback</label></h2>
<a href="//daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Syntax</a> is supported. <a href="//daringfireball.net/projects/markdown/syntax" target="_blank">Markdown Syntax</a> is supported.
...@@ -29,15 +37,29 @@ ...@@ -29,15 +37,29 @@
If you delete an answer, any votes for that answer will also be deleted. Students whose choices are deleted If you delete an answer, any votes for that answer will also be deleted. Students whose choices are deleted
may vote again, but will not lose course progress. may vote again, but will not lose course progress.
</p> </p>
{% if multiquestion %}
<p>
Questions must be similarly cared for. If a question's text is changed, any votes for that question will remain.
If a question is deleted, any student who previously took the survey will be permitted to retake it, but will not
lose course progress.
</p>
{% endif %}
</li> </li>
<li id="poll-answer-marker"></li> <li id="poll-answer-marker"></li>
<li id="poll-answer-end-marker"> <li id="poll-answer-end-marker"></li>
<li id="poll-question-marker"></li>
<li id="poll-question-end-marker"></li>
</ul> </ul>
<div class="xblock-actions"> <div class="xblock-actions">
<ul> <ul>
<li class="action-item" id="poll-add-answer"> <li class="action-item" id="poll-add-answer">
<a href="#" class="button action-button" class="poll-add-answer-link" onclick="return false;">Add Answer</a> <a href="#" class="button action-button" class="poll-add-item-link" onclick="return false;">Add Answer</a>
</li>
{% if multiquestion %}
<li class="action-item" id="poll-add-question">
<a href="#" class="button action-button" class="poll-add-item-link" onclick="return false;">Add Question</a>
</li> </li>
{% endif %}
<li class="action-item"> <li class="action-item">
<input id="poll-submit-options" type="submit" class="button action-primary save-button" value="Save" onclick="return false;" /> <input id="poll-submit-options" type="submit" class="button action-primary save-button" value="Save" onclick="return false;" />
</li> </li>
......
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
{% for key, question in questions %} {% for key, question in questions %}
<tr class="survey-row"> <tr class="survey-row">
<td class="survey-question"> <td class="survey-question">
{% if question.img %}
<div class="poll-image-td">
<img src="{{question.img}}" />
</div>
{% endif %}
{{question.label}} {{question.label}}
</td> </td>
{% for answer, answer_details in answers %} {% for answer, answer_details in answers %}
......
...@@ -2,49 +2,60 @@ ...@@ -2,49 +2,60 @@
function PollEditUtil(runtime, element, pollType) { function PollEditUtil(runtime, element, pollType) {
var self = this; var self = this;
// These URLs aren't validated in real time, so even if they don't exist for a type of block
// we can create a reference to them.
this.loadAnswers = runtime.handlerUrl(element, 'load_answers');
this.loadQuestions = runtime.handlerUrl(element, 'load_questions');
this.init = function () { this.init = function () {
// Set up the editing form for a Poll or Survey. // Set up the editing form for a Poll or Survey.
self.loadAnswers = runtime.handlerUrl(element, 'load_answers'); var temp = $('#poll-form-component', element).html();
var temp = $('#answer-form-component', element).html();
self.answerTemplate = Handlebars.compile(temp); self.answerTemplate = Handlebars.compile(temp);
$(element).find('.cancel-button', element).bind('click', function() { $(element).find('.cancel-button', element).bind('click', function() {
runtime.notify('cancel', {}); runtime.notify('cancel', {});
}); });
var mapping = self.mappings[pollType]['buttons']; var button_mapping = self.mappings[pollType]['buttons'];
for (var key in mapping) { for (var key in button_mapping) {
if (mapping.hasOwnProperty(key)) { if (button_mapping.hasOwnProperty(key)) {
$(key, element).click( $(key, element).click(
// The nature of the closure forces us to make a custom function here. // The nature of the closure forces us to make a custom function here.
function (context_key, topMarker, bottomMarker) { function (context_key) {
return function () { return function () {
// The degree of precision on date should be precise enough to avoid // The degree of precision on date should be precise enough to avoid
// collisions in the real world. // collisions in the real world.
var bottom = $(bottomMarker); var bottom = $(button_mapping[context_key]['bottomMarker']);
$(self.answerTemplate(mapping[context_key]['itemList'])).before(bottom); var new_item = $(self.answerTemplate(button_mapping[context_key]['itemList']));
var new_item = bottom.prev(); bottom.before(new_item);
self.empowerDeletes(new_item); self.empowerDeletes(new_item);
self.empowerArrows( self.empowerArrows(
new_item, mapping[context_key]['topMarker'], new_item, button_mapping[context_key]['topMarker'],
mapping[context_key]['bottomMarker'] button_mapping[context_key]['bottomMarker']
); );
new_item.fadeOut(250).fadeIn(250); new_item.fadeOut(250).fadeIn(250);
} }
}(key, self.mappings[pollType]) }(key)
) )
} }
} }
$(element).find('.save-button', element).bind('click', self.pollSubmitHandler); $(element).find('.save-button', element).bind('click', self.pollSubmitHandler);
var mapping = self.mappings[pollType]['onLoad'];
for (var task in mapping) {
function load (taskItem){
$(function ($) { $(function ($) {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: self.loadAnswers, url: taskItem['url'],
data: JSON.stringify({}), data: JSON.stringify({}),
success: self.displayAnswers success: taskItem['function']
}); });
}); });
}
load(mapping[task]);
}
}; };
this.extend = function (obj1, obj2) { this.extend = function (obj1, obj2) {
...@@ -65,32 +76,6 @@ function PollEditUtil(runtime, element, pollType) { ...@@ -65,32 +76,6 @@ function PollEditUtil(runtime, element, pollType) {
return self.extend({'key': new Date().getTime(), 'text': '', 'img': ''}, extra) return self.extend({'key': new Date().getTime(), 'text': '', 'img': ''}, extra)
}; };
// This object is used to swap out values which differ between Survey and Poll blocks.
this.mappings = {
'poll': {
'buttons': {
'#poll-add-answer': {
'itemList': {'items': [self.makeNew({'image': true, 'noun': 'answer'})]},
'topMarker': '#poll-answer-marker', 'bottomMarker': '#poll-answer-end-marker'
}
},
'onLoad': {
}
},
'survey': {
'buttons': {
'#poll-add-answer': {
'itemList': {'items': [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'})]}
}
}
}
};
this.empowerDeletes = function (scope) { this.empowerDeletes = function (scope) {
// Activates the delete buttons on rendered line items. // Activates the delete buttons on rendered line items.
$('.poll-delete-answer', scope).click(function () { $('.poll-delete-answer', scope).click(function () {
...@@ -122,9 +107,44 @@ function PollEditUtil(runtime, element, pollType) { ...@@ -122,9 +107,44 @@ function PollEditUtil(runtime, element, pollType) {
self.displayItems(data, '#poll-answer-marker', '#poll-answer-end-marker') self.displayItems(data, '#poll-answer-marker', '#poll-answer-end-marker')
}; };
this.displayQuestions = function (data) {
self.displayItems(data, "#poll-question-marker", '#poll-question-end-marker')
};
// This object is used to swap out values which differ between Survey and Poll blocks.
this.mappings = {
'poll': {
'buttons': {
'#poll-add-answer': {
'itemList': {'items': [self.makeNew({'image': true, 'noun': 'answer'})]},
'topMarker': '#poll-answer-marker', 'bottomMarker': '#poll-answer-end-marker'
}
},
'onLoad': [{'url': self.loadAnswers, 'function': self.displayAnswers}],
'gather': [{'prefix': 'answer', 'field': 'answers'}]
},
'survey': {
'buttons': {
'#poll-add-answer': {
'itemList': {'items': [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'})]},
'topMarker': '#poll-question-marker', 'bottomMarker': '#poll-question-end-marker'
}
},
'onLoad': [
{'url': self.loadQuestions, 'function': self.displayQuestions},
{'url': self.loadAnswers, 'function': self.displayAnswers}
],
'gather': [{'prefix': 'answer', 'field': 'answers'}, {'prefix': 'question', 'field': 'questions'}]
}
};
this.displayItems = function(data, topMarker, bottomMarker) { this.displayItems = function(data, topMarker, bottomMarker) {
// Loads the initial set of items that the block needs to edit. // Loads the initial set of items that the block needs to edit.
$('#poll-answer-end-marker').before(self.answerTemplate(data)); $(bottomMarker).before(self.answerTemplate(data));
self.empowerDeletes(element, topMarker, bottomMarker); self.empowerDeletes(element, topMarker, bottomMarker);
self.empowerArrows(element, topMarker, bottomMarker); self.empowerArrows(element, topMarker, bottomMarker);
}; };
...@@ -142,31 +162,44 @@ function PollEditUtil(runtime, element, pollType) { ...@@ -142,31 +162,44 @@ function PollEditUtil(runtime, element, pollType) {
alert(data['errors'].join('\n')); alert(data['errors'].join('\n'));
}; };
this.pollSubmitHandler = function() { this.gather = function (scope, tracker, data, prefix, field) {
// Take all of the fields, serialize them, and pass them to the
// server for saving.
var handlerUrl = runtime.handlerUrl(element, 'studio_submit');
var data = {'answers': []};
var tracker = [];
$('#poll-form input', element).each(function() {
var key = 'label'; var key = 'label';
if (this.name.indexOf('answer-') >= 0){ var name = scope.name.replace(prefix + '-', '');
var name = this.name.replace('answer-', ''); if (scope.name.indexOf('img-') == 0){
if (this.name.indexOf('img-') == 0){
name = name.replace('img-', ''); name = name.replace('img-', '');
key = 'img' key = 'img'
} }
if (! (scope.name.indexOf(prefix + '-') >= 0)) {
return
}
if (tracker.indexOf(name) == -1){ if (tracker.indexOf(name) == -1){
tracker.push(name); tracker.push(name);
data['answers'].push({'key': name}) data[field].push({'key': name})
} }
var index = tracker.indexOf(name); var index = tracker.indexOf(name);
data['answers'][index][key] = this.value; console.log(data[field]);
return console.log(index);
} data[field][index][key] = scope.value;
data[this.name] = this.value return true
};
this.pollSubmitHandler = function () {
// Take all of the fields, serialize them, and pass them to the
// server for saving.
var handlerUrl = runtime.handlerUrl(element, 'studio_submit');
var data = {};
var tracker;
var gatherings = self.mappings[pollType]['gather'];
for (var gathering in gatherings) {
tracker = [];
var field = gatherings[gathering]['field'];
var prefix = gatherings[gathering]['prefix'];
data[field] = [];
$('#poll-form input', element).each(function () {
self.gather(this, tracker, data, prefix, field)
}); });
data['title'] = $('#poll-title', element).val(); }
data['display_name'] = $('#poll-display-name', element).val();
data['question'] = $('#poll-question-editor', element).val(); data['question'] = $('#poll-question-editor', element).val();
data['feedback'] = $('#poll-feedback-editor', element).val(); data['feedback'] = $('#poll-feedback-editor', element).val();
......
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