Commit 3a006d53 by Piotr Mitros

Studio view

parent 73dc9e64
...@@ -39,14 +39,17 @@ class RateXBlock(XBlock): ...@@ -39,14 +39,17 @@ class RateXBlock(XBlock):
this. this.
""" """
default_prompt = {'string':"Please provide us feedback on this section.", default_prompt = {'freeform':"Please provide us feedback on this section.",
'likert':"Please rate your overall experience with this section.", 'likert':"Please rate your overall experience with this section.",
'mouseovers':["Excellent", "Good", "Average", "Fair", "Poor"], 'mouseovers':["Excellent", "Good", "Average", "Fair", "Poor"],
'icons':[u"😁",u"😊",u"😐",u"☹",u"😟"]} 'icons':[u"😁",u"😊",u"😐",u"☹",u"😟"]}
# This is a list of prompts. If we have multiple elements in the
# list, one will be chosen at random. This is currently not
# exposed in the UX. If the prompt is missing any portions, we
# will default to the ones in default_prompt.
prompts = List( prompts = List(
default=[default_prompt, default=[{'freeform':"What could be improved to make this section more clear?",
{'string':"What could be improved to make this section more clear?",
'likert':"Was this section clear or confusing?."}], 'likert':"Was this section clear or confusing?."}],
scope=Scope.settings, scope=Scope.settings,
help="Freeform user prompt", help="Freeform user prompt",
...@@ -58,7 +61,6 @@ class RateXBlock(XBlock): ...@@ -58,7 +61,6 @@ class RateXBlock(XBlock):
help="Random number generated for p. -1 if uninitialized" help="Random number generated for p. -1 if uninitialized"
) )
user_vote = Integer( user_vote = Integer(
default=-1, scope=Scope.user_state, default=-1, scope=Scope.user_state,
help="How user voted. -1 if didn't vote" help="How user voted. -1 if didn't vote"
...@@ -88,20 +90,29 @@ class RateXBlock(XBlock): ...@@ -88,20 +90,29 @@ class RateXBlock(XBlock):
data = pkg_resources.resource_string(__name__, path) data = pkg_resources.resource_string(__name__, path)
return data.decode("utf8") return data.decode("utf8")
def get_prompt(self, index):
"""
Return the current prompt dictionary, doing appropriate
randomization if necessary, and falling back to defaults when
necessary.
"""
prompt = dict(self.default_prompt)
prompt.update(self.prompts[index])
return prompt
def student_view(self, context=None): def student_view(self, context=None):
""" """
The primary view of the RateXBlock, shown to students The primary view of the RateXBlock, shown to students
when viewing courses. when viewing courses.
""" """
if self.prompt_choice < 0 or self.prompt_choice >= len(self.prompts):
self.prompt_choice = random.randint(0, len(self.prompts)-1)
prompt = self.get_prompt(self.prompt_choice)
# Figure out which prompt we show. We set self.prompt_choice to # Figure out which prompt we show. We set self.prompt_choice to
# the index of the prompt. We set it if it is out of range (either # the index of the prompt. We set it if it is out of range (either
# uninitiailized, or incorrect due to changing list length). Then, # uninitiailized, or incorrect due to changing list length). Then,
# we grab the prompt, prepopulated with defaults. # we grab the prompt, prepopulated with defaults.
if self.prompt_choice < 0 or self.prompt_choice >= len(self.prompts):
self.prompt_choice = random.randint(0, len(self.prompts)-1)
prompt = dict(self.default_prompt)
prompt.update(self.prompts[self.prompt_choice])
# Now, we render the RateXBlock. This may be redundant, since we # Now, we render the RateXBlock. This may be redundant, since we
# don't always show it. # don't always show it.
...@@ -110,7 +121,7 @@ class RateXBlock(XBlock): ...@@ -110,7 +121,7 @@ class RateXBlock(XBlock):
indexes = range(len(prompt['icons'])) indexes = range(len(prompt['icons']))
active_vote = ["checked" if i == self.user_vote else "" for i in indexes] active_vote = ["checked" if i == self.user_vote else "" for i in indexes]
scale = u"".join(scale_item.format(level=level, icon=icon, i=i, active=active) for (level,icon,i,active) in zip(prompt['mouseovers'], prompt['icons'], indexes, active_vote)) scale = u"".join(scale_item.format(level=level, icon=icon, i=i, active=active) for (level,icon,i,active) in zip(prompt['mouseovers'], prompt['icons'], indexes, active_vote))
rendered = html.format(self=self, scale=scale, string_prompt = prompt['string'], likert_prompt = prompt['likert']) rendered = html.format(self=self, scale=scale, freeform_prompt = prompt['freeform'], likert_prompt = prompt['likert'])
# We initialize self.p_r if not initialized -- this sets whether # We initialize self.p_r if not initialized -- this sets whether
# or not we show it. From there, if it is less than odds of showing, # or not we show it. From there, if it is less than odds of showing,
...@@ -131,6 +142,29 @@ class RateXBlock(XBlock): ...@@ -131,6 +142,29 @@ class RateXBlock(XBlock):
frag.initialize_js('RateXBlock') frag.initialize_js('RateXBlock')
return frag return frag
def studio_view(self, context):
"""
Create a fragment used to display the edit view in the Studio.
"""
html_str = pkg_resources.resource_string(__name__, "static/html/studio_view.html")
prompt = self.get_prompt(0)
frag = Fragment(unicode(html_str).format(**prompt))
js_str = pkg_resources.resource_string(__name__, "static/js/src/studio.js")
frag.add_javascript(unicode(js_str))
frag.initialize_js('RateBlock')
return frag
@XBlock.json_handler
def studio_submit(self, data, suffix=''):
"""
Called when submitting the form in Studio.
"""
print data
self.prompts[0]['freeform'] = data.get('freeform')
self.prompts[0]['likert'] = data.get('likert')
return {'result': 'success'}
@XBlock.json_handler @XBlock.json_handler
def vote(self, data, suffix=''): def vote(self, data, suffix=''):
""" """
...@@ -155,7 +189,7 @@ class RateXBlock(XBlock): ...@@ -155,7 +189,7 @@ class RateXBlock(XBlock):
@XBlock.json_handler @XBlock.json_handler
def feedback(self, data, suffix=''): def feedback(self, data, suffix=''):
tracker.emit('edx.ratexblock.string_feedback', tracker.emit('edx.ratexblock.freeform_feedback',
{'old_feedback' : self.user_feedback, {'old_feedback' : self.user_feedback,
'new_feedback' : data['feedback']}) 'new_feedback' : data['feedback']})
self.user_feedback = data['feedback'] self.user_feedback = data['feedback']
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
border-radius:5px; border-radius:5px;
} }
.rate_block .rate_string_input { .rate_block .rate_freeform_input {
margin-bottom: 1em; margin-bottom: 1em;
} }
......
<div class="rate_block"> <div class="rate_block">
<div class="rate_header">{string_prompt}</div> <div class="rate_header">{freeform_prompt}</div>
<div class="rate_string_input"> <div class="rate_freeform_input">
<textarea class="rate_string_area" rows="4" cols="30">{self.user_feedback}</textarea> <textarea class="rate_freeform_area" rows="4" cols="30">{self.user_feedback}</textarea>
<div class="rate_thank_you">Thank you!</div> <div class="rate_thank_you">Thank you!</div>
</div> </div>
<div class="rate_likert_header">{likert_prompt}</div> <div class="rate_likert_header">{likert_prompt}</div>
......
<div class="wrapper-comp-settings is-active editor-with-buttons" id="settings-tab">
<ul class="list-input settings-list">
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="freeform">Freeform prompt</label>
<input class="input setting-input" name="freeform" id="freeform" value="{freeform}" type="text" />
</div>
<span class="tip setting-help">Example: Please provide us feedback on this section.</span>
</li>
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="likert">Likert prompt</label>
<input class="input setting-input" name="likert" id="likert" value="{likert}" type="text" />
</div>
<span class="tip setting-help">Example: Please rate your overall experience with this section.</span>
</li>
<div class="xblock-actions">
<ul>
<li class="action-item">
<a href="#" class="button action-primary save-button">Save</a>
</li>
<li class="action-item">
<a href="#" class="button cancel-button">Cancel</a>
</li>
</ul>
</div>
</div>
...@@ -27,14 +27,14 @@ function RateXBlock(runtime, element) { ...@@ -27,14 +27,14 @@ function RateXBlock(runtime, element) {
Logger.log("edx.ratexblock.likert_rate", {"vote":vote}) Logger.log("edx.ratexblock.likert_rate", {"vote":vote})
}); });
$('.rate_string_area', element).change(function(eventObject) { $('.rate_freeform_area', element).change(function(eventObject) {
$('.rate_thank_you', element).css('visibility','hidden'); $('.rate_thank_you', element).css('visibility','hidden');
var feedback_string = eventObject.currentTarget.value; var feedback_freeform = eventObject.currentTarget.value;
Logger.log("edx.ratexblock.string_feedback", {"feedback":feedback_string}) Logger.log("edx.ratexblock.freeform_feedback", {"feedback":feedback_freeform})
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: feedback_handler, url: feedback_handler,
data: JSON.stringify({"feedback": feedback_string}), data: JSON.stringify({"feedback": feedback_freeform}),
success: function() {$('.rate_thank_you', element).css('visibility','visible')}, success: function() {$('.rate_thank_you', element).css('visibility','visible')},
}); });
}); });
......
function RateBlock(runtime, element) {
$(element).find('.save-button').bind('click', function() {
var handlerUrl = runtime.handlerUrl(element, 'studio_submit');
var data = {
likert: $(element).find('input[name=likert]').val(),
freeform: $(element).find('input[name=freeform]').val()
};
runtime.notify('save', {state: 'start'});
$.post(handlerUrl, JSON.stringify(data)).done(function(response) {
runtime.notify('save', {state: 'end'});
});
});
$(element).find('.cancel-button').bind('click', function() {
runtime.notify('cancel', {});
});
}
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