Commit 6930813b by solashirai Committed by Piotr Mitros

touching up rough looks and unnecessary code

parent 28295120
This is the repository for the Crowd Sourced Hinter XBlock. The Crowd Sourced Hinter serves to provide students with hints when they incorrectly answer a problem within a course (currently tested for text and numerical input type questions).
This XBlock is still under construction. Functionalities to set default hints, properly moderate flagged hints, and improvements to user interface are to be done soon.
backlog: https://docs.google.com/a/edx.org/document/d/1lOBLZWohwRmnfgwz53gc4b4GdfP4EER3UNohdYfcEJU/edit#
This XBlock is still under construction. To be implemented are methods to properly moderate reported hints (currently a staff member must answer each question to view crude moderation options).
An example of a student recieving a hint
![CrowdSourcedHinter Hint Screenshot](crowdsourcedhinter_hint.png)
......@@ -18,11 +16,9 @@ The name of the module to set in the advanced settings tab is "crowdxblock" (thi
After creating a new unit, add the crowdsourcedhinter XBlock into a course just like any other XBlock. The name of the crowd sourced hinter may not show up in studio for some unknown reason, but an empty space where its name should be will be clickable (problem to be identified/fixed...).
Testing the functionality of the crowd sourced hinter works best when switching between different users and answering the same problem.
What It Does:
The two key features of the crowd sourced hinter are the abilities to show students hints and to have the students themselves create hints to be shown to future students.
When a student incorrectly answers a text input type problem, the crowd sourced hinter will look through its database to search for a hint that has been stored for that exact incorrect answer input (i.e. when the database is large enough, two different incorrect answers would not receive the same hint). If hints exist for a student's incorrect answer, this hint is shown to the student. The student then may have the opportunity to input their answer again, which may prompt another hint to be displayed.
After a student re-submits an answer correctly, they can rate hints as well as submit new hints. Rating hints works by upvoting, downvoting, or flagging the hints (flagged hints are not shown to students). Students can submit new hints for each incorrect answer that has been made, and this hint will be stored only for that specific incorrect answer.
After a student re-submits an answer correctly, they can rate hints as well as submit new hints. Rating hints works by upvoting, downvoting, or reporting hints. Students can submit new hints for each incorrect answer that has been made, and this hint will be stored only for that specific incorrect answer.
crowdsourcedhinter_feedback.png

22.4 KB | W: | H:

crowdsourcedhinter_feedback.png

33.3 KB | W: | H:

crowdsourcedhinter_feedback.png
crowdsourcedhinter_feedback.png
crowdsourcedhinter_feedback.png
crowdsourcedhinter_feedback.png
  • 2-up
  • Swipe
  • Onion skin
crowdsourcedhinter_hint.png

18.9 KB | W: | H:

crowdsourcedhinter_hint.png

39.8 KB | W: | H:

crowdsourcedhinter_hint.png
crowdsourcedhinter_hint.png
crowdsourcedhinter_hint.png
crowdsourcedhinter_hint.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -76,7 +76,7 @@ class CrowdsourceHinter(XBlock):
frag.add_javascript_url('//cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js')
frag.add_css(self.resource_string("static/css/crowdsourcehinter.css"))
frag.add_javascript(self.resource_string("static/js/src/crowdsourcehinter.js"))
frag.initialize_js('CrowdsourceHinter')
frag.initialize_js('CrowdsourceHinter', {'hinting_element': self.Element})
return frag
def studio_view(self, context=None):
......@@ -108,20 +108,6 @@ class CrowdsourceHinter(XBlock):
"""
return self.xmodule_runtime.user_is_staff
def convert_keys_to_string(dictionary):
"""Recursively converts dictionary keys to strings."""
if not isinstance(dictionary, dict):
return dictionary
return dict((str(k), convert_keys_to_string(v))
for k, v in dictionary.items())
@XBlock.json_handler
def get_element(self, data, suffix=''):
"""
Returns the self.element so that the javascript Logger.listen will be using the correct element.
"""
return unicode(self.Element);
@XBlock.json_handler
def is_user_staff(self, _data, _suffix=''):
"""
......@@ -146,9 +132,6 @@ class CrowdsourceHinter(XBlock):
or another random hint for an incorrect answer
or 'Sorry, there are no more hints for this answer.' if no more hints exist
"""
print(self.initial_hints)
print(self.generic_hints)
print str(data["submittedanswer"])
# populate hint_database with hints from initial_hints if there are no hints in hint_database.
# this probably will occur only on the very first run of a unit containing this block.
if not bool(self.hint_database):
......@@ -169,10 +152,9 @@ class CrowdsourceHinter(XBlock):
answer = answer[eqplace:]
remaining_hints = str(self.find_hints(answer))
if remaining_hints != str(0):
print(self.hint_database)
best_hint = max(self.hint_database[str(answer)].iteritems(), key=operator.itemgetter(1))[0]
if self.show_best:
# if set to show best, only the best hint will be shown. Different hitns will not be shown
# if set to show best, only the best hint will be shown. Different hints will not be shown
# for multiple submissions/hint requests
if best_hint not in self.Flagged.keys():
self.Used.append(best_hint)
......@@ -191,7 +173,7 @@ class CrowdsourceHinter(XBlock):
not_used = random.choice(temporary_hints_list)
self.Used.append(not_used)
return {'HintsToUse': not_used, "StudentAnswer": answer}
else:
# find generic hints for the student if no specific hints exist
if len(self.generic_hints) != 0:
not_used = random.choice(self.generic_hints)
self.Used.append(not_used)
......@@ -367,7 +349,6 @@ class CrowdsourceHinter(XBlock):
self.hint_database[str(answer_data)][str(data_hint)] += 1
else:
self.hint_database[str(answer_data)][str(data_hint)] -= 1
print("Ratings changed : " + str(self.hint_database))
@XBlock.json_handler
def give_hint(self, data, suffix=''):
......@@ -391,13 +372,6 @@ class CrowdsourceHinter(XBlock):
self.hint_database[str(answer)][str(submission)] += 1
return
def convert_keys_to_string(dictionary):
"""Recursively converts dictionary keys to strings."""
if not isinstance(dictionary, dict):
return dictionary
return dict((str(k), convert_keys_to_string(v))
for k, v in dictionary.items())
@XBlock.json_handler
def studiodata(self, data, suffix=''):
"""
......@@ -431,5 +405,4 @@ class CrowdsourceHinter(XBlock):
block.generic_hints.append(str(xmlText["generic_hints"]))
block.initial_hints = copy.copy(xmlText["initial_hints"])
block.Element = str(xmlText["hinting_element"])
print block.Element, block.initial_hints
return block
......@@ -35,7 +35,8 @@
.csh_rating_data {
display: flex;
flex-direction: column;
flex-direction: row;
align-self: flex-end;
}
.csh_rate_hint {
......@@ -85,6 +86,7 @@ div[data-rate="downvote"] {
}
.csh_rate_hint{ cursor: pointer }
.csh_staff_rate{ cursor: pointer }
.csh_rate_hint{ color: #948f8f; }
.csh_hintsarea {
......
......@@ -4,11 +4,11 @@
<div class="csh_hint"><b>{{hint}}</b></div>
</div>
<div class='csh_rating_data'>
<div role="button" class="csh_rate_hint" data-rate="upvote" data-icon="arrow-u" title="This hint was helpful">
<b>+</b>
<div role="button" class="csh_rate_hint" data-rate="upvote" data-icon="arrow-u">
<b>Rate as Helpful</b>
</div>
<div role="button" class="csh_rate_hint" data-rate="downvote" title="This hint was not helpful.">
<b>-</b>
<div role="button" class="csh_rate_hint" data-rate="downvote">
<b>Rate as Unhelpful</b>
</div>
<div role="button" class="csh_rate_hint" data-rate="flag" data-icon="flag" title="Report this hint.">
<b></b>
......@@ -19,13 +19,14 @@
<script type="x-tmpl/mustache" id="show_flagged_feedback">
<div class="csh_hint_value" value ="{{hint}}">
<div class="csh_hint">{{hint}}</div>
<div role="button" class="csh_staff_rate" data-rate="unflag" aria-label="unflag">
<b>Unflag Hint</b>
<u><b>Return hint for use in the hinter</b></u>
</div>
<div class="csh_hint">{{hint}}</div>
<div role="button" class="csh_staff_rate" data-rate="remove" aria-label="remove">
<b>Remove Hint</b>
<u><b>Permanently remove hint.</b></u>
</div>
<div>--------</div>
</div>
</script>
......@@ -46,13 +47,14 @@
<script type="x-tmpl/mustache" id="show_answer_feedback">
<div class="csh_student_answer">
<h class="csh_answer_text" answer={{answer}}>
<i> Your original answer: </i>{{answer}} <br> <i>The hint you viewed: </i></h>
<i> Improve hints for this question by leaving feedback on this hint or contributing your own! </i> <br>
<i> Your original answer was: {{answer}} </i></h>
</div>
</script>
<script type="x-tmpl/mustache" id="add_hint_creation">
<div>
<input type ="button" class="csh_student_hint_creation" value="Submit a New Hint">
<input type ="button" class="csh_student_hint_creation" value="Contribute a New Hint">
</input>
</div>
</script>
......@@ -84,7 +86,7 @@
</p>
<div class="csh_feedback">
<div class="csh_flagged_hints">
<span>Flagged</span>
<span>moderate reported hints</span>
</div>
</div>
</div>
......
function CrowdsourceHinter(runtime, element){
function CrowdsourceHinter(runtime, element, data){
//executeHinter is used to disable the hinter after switching units in an edX course
//If the code is not made to stop running, the hinter will act up after switching from and back to
//a certain unit.
......@@ -11,16 +11,6 @@ function CrowdsourceHinter(runtime, element){
var hinting_element;
var isStaff = false;
$(".csh_HintsToUse", element).text("");
$.ajax({
type: "POST",
url: runtime.handlerUrl(element, 'get_element'),
data: JSON.stringify("helloworld"),
success: function(result){
console.log("hinting_element being set", String(result));
hinting_element = String(result);
Logger.listen('problem_graded', result, get_event_data);
}
});
function stopScript(){
//This function is used to prevent a particular instance of the hinter from acting after
......@@ -36,6 +26,7 @@ function CrowdsourceHinter(runtime, element){
function get_event_data(event_type, data, element){
onStudentSubmission(data);
}
Logger.listen('problem_graded', data.hinting_element, get_event_data);
function onStudentSubmission(problem_graded_event_data){
//This function will determine whether or not the student correctly answered the question.
......@@ -138,7 +129,7 @@ function CrowdsourceHinter(runtime, element){
//Set up the student feedback stage. Each student answer and all answer-specific hints for that answer are shown
//to the student, as well as an option to create a new hint for an answer.
if(isStaff){
$('.crowdsourcehinter_block').attr('class', 'crowdsourcehinter_block_is_staff');
$('.crowdsourcehinter_block', element).attr('class', 'crowdsourcehinter_block_is_staff');
$.each(result, function(index, value) {
if(value == "Flagged") {
//index represents the flagged hint's text
......@@ -181,11 +172,11 @@ function CrowdsourceHinter(runtime, element){
$(element).on('click', '.csh_student_hint_creation', function(){
//Click event for the creation of a new hint. This button will bring up the text input.
$('.csh_student_hint_creation').each(function(){
$('.csh_student_hint_creation', element).each(function(){
$(this).show();
});
$('.csh_student_text_input').remove();
$('.csh_submit_new').remove();
$('.csh_student_text_input', element).remove();
$('.csh_submit_new', element).remove();
$(this).hide();
student_answer = $(this).parent().parent().find('.csh_answer_text').attr('answer');
$(".csh_student_answer", element).each(function(){
......@@ -203,12 +194,11 @@ function CrowdsourceHinter(runtime, element){
$(element).on('click', '.csh_submit_new', function(){
//Click event to submit a new hint for an answer.
if($(this).parent().find('.csh_student_text_input').val() != null){
if($(this).parent().parent().find('.csh_student_text_input').val() != null){
var answerdata = unescape($(this).attr('answer'));
var newhint = unescape($('.csh_student_text_input').val());
Logger.log('crowd_hinter.submit_new.click.event', {"student_answer": answerdata, "new_hint_submission": newhint});
console.log(answerdata, newhint);
$('.csh_submitbutton').show();
$('.csh_submitbutton', element).show();
$.ajax({
type: "POST",
url: runtime.handlerUrl(element, 'give_hint'),
......@@ -222,7 +212,7 @@ function CrowdsourceHinter(runtime, element){
});
}
});
$(this).parent().find('.csh_student_text_input').remove();
$(this).parent().parent().find('.csh_student_text_input').remove();
$(this).remove();
}
})
......
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