Commit 54aa05a2 by solashirai

initial commit

parent 5234a920
*.pyc
*~
*.egg-info/
This is the repository for the Crowdsource Hinter XBlock. The Crowdsource Hinter serves to provide students with hints when they incorrectly answer a problem within a course. The hinter is compatible with numerical input and text input type problems.
This XBlock is still a prototype.
An example of a student recieving a hint
![CrowdSourceHinter Hint Screenshot](crowdsourcehinter_hint.png)
An example of after a student corrects their answer
![CrowdSourceHinter Screenshot](crowdsourcehinter_correct.png)
To bring the crowd sourced hinter into a demo course:
Follow https://github.com/edx/edx-platform/wiki/Installing-a-new-XBlock for basic xblock installation. The name of the module to set in the advanced settings tab is "crowdsourcehinter".
In studio view, edit the hinter so that the "Problem Element" is set to the "data-usage-id" of the problem block (findable by inspecting element of the problem block). If no problem element is set manually, the hinter will default to respond to the first problem block on the page.
![CrowdSourceHinter Installation Screenshot](crowdsourcehinter_setup.png)
The two key features of the crowdsource 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 problem, the 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 for their usefulness or contribute a new hint to be used by other students. Rating hints works by upvoting, downvoting, or reporting hints. The new hint that is contributed by a student is specific to the incorrect answer that they make (currently the first incorrect answer will be prompted for contributing new hints).
from .crowdsourcehinter import CrowdsourceHinter
This static directory is for files that should be included in your kit as plain
static files.
You can ask the runtime for a URL that will retrieve these files with:
url = self.runtime.local_resource_url(self, "static/js/lib.js")
The default implementation is very strict though, and will not serve files from
the static directory. It will serve files from a directory named "public".
Create a directory alongside this one named "public", and put files there.
Then you can get a url with code like this:
url = self.runtime.local_resource_url(self, "public/js/lib.js")
The sample code includes a function you can use to read the content of files
in the static directory, like this:
frag.add_javascript(self.resource_string("static/js/my_block.js"))
/* CSS for Crowdsource Hinter */
.crowdsourcehinter_block .csh_feedback {
}
.crowdsourcehinter_block .csh_vote {
padding-top: 2px;
padding-bottom: 2px;
}
.csh_reveal_info{
color: blue;
}
.csh_reveal_info:hover{
color: blue;
text-decoration: underline;
}
.csh_hint_value{
display: flex;
/* margin-left: 10px; */
flex-direction: column;
}
.crowdsourcehinter_block {
}
.csh_hint_reveal{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.csh_hint_rating_on_incorrect{
display: flex;
flex-direction: row;
justify-content: space-between;
flex-shrink: 0;
}
.csh_hint_data{
display: flex;
flex-direction: column;
}
.csh_rating_data {
display: flex;
flex-direction: row;
align-self: flex-end;
flex-shrink: 0;
}
.csh_rate_hint, .csh_report_hint, .csh_rate_hint_completed, .csh_rate_hint_text {
align-self: flex-end;
margin-left: 10px;
}
div[data-rate="report"]{
font-weight: bold;
}
.csh_hint_text[rating="upvote"]{
color: green;
}
.csh_hint_text[rating="downvote"]{
color: red;
}
.csh_hint[rating="upvote"]{
color: green;
}
.csh_hint[rating="downvote"]{
color: red;
}
.csh_student_hint_creation {
height: 40px;
vertical-align: middle;
font-weight: 600;
align-self: flex-end;
box-shadow: 0px 0px 8px 4px #C7BEBE inset, 0px 0px 8px 4px #C7BEBE inset;
background-clip: padding-box;
font-size: 0.8125em;
}
.csh_rate_hint[data-rate="upvote"] {
color: green;
font-weight: bold;
transition: background .4s ease-in
}
.csh_rate_hint[data-rate="upvote"]:hover {
background-color: #BCBCBC;
}
.csh_rate_hint[data-rate="downvote"] {
color: red;
font-weight: bold;
transition: background .4s ease-in
}
.csh_rate_hint[data-rate="downvote"]:hover {
background-color: #BCBCBC;
}
.csh_report_hint {
transition: background .4s ease-in
}
.csh_report_hint:hover {
background-color: #BCBCBC;
}
.csh_reported_hints {
background-color: red;
}
.crowdsourcehinter_block .csh_reported_hints {
visibility: hidden;
display: none;
}
.crowdsourcehinter_block_is_staff .csh_reported_hints {
visibility: visible;
}
.csh_user_info{
padding-left: 22px ;
text-indent: -22px ;
}
.csh_rating{
margin-right: 5px;
}
.csh_rate_hint{ cursor: pointer }
.csh_report_hint{ cursor: pointer }
.csh_staff_rate{ cursor: pointer }
.csh_rate_hint{ color: #948f8f; }
.csh_reveal_info{ cursor: pointer }
.csh_hintsarea {
display: flex;
flex-direction: colomn;
}
.csh_student_text_input{
width: 100%;
}
<script type='x-tmpl/mustache' id='show_hint_rating_ux'>
<div class='csh_hint_value' value="{{hintText}}">
<div class='csh_hint_data'>
<div class="csh_hint">You received the following hint: <b>{{hintText}}</b></div>
</div>
<div class='csh_rating_data'>
<div role="button" class="csh_rate_hint" data-rate="upvote">
<b>Rate as Helpful</b>
</div>
<div role="button" class="csh_rate_hint" data-rate="downvote">
<b>Rate as Unhelpful</b>
</div>
<div role="button" class="csh_report_hint" data-icon="report" title="Report this hint.">
<b></b>
</div>
</div>
</div>
</script>
<script type="x-tmpl/mustache" id="show_reported_moderation">
<div class="csh_hint_value" value ="{{reportedHintText}}">
<div class="csh_hint">{{reportedHintText}}</div>
<div role="button" class="csh_staff_rate" data-rate="unreport" aria-label="unreport">
<u><b>Return hint for use in the hinter</b></u>
</div>
<div role="button" class="csh_staff_rate" data-rate="remove" aria-label="remove">
<u><b>Permanently remove hint.</b></u>
</div>
<div>--------</div>
</div>
</script>
<script type="x-tmpl/mustache" id="hint_text_input">
<p>
<input type="text" name="studentinput" class="csh_student_text_input">
</p>
<p>
<input answer="{{student_answer}}" type="button" class="csh_submit_new" value="Submit Hint">
</p>
</script>
<script type="x-tmpl/mustache" id="show_no_hints">
<div class="csh_hint_value"> This specific mistake doesn't appear to have any hints yet. You can contribute a hint to help other students who make the same mistake in the future.
</div>
</script>
<script type="x-tmpl/mustache" id="show_student_submission">
<div class="csh_student_answer">
<h class="csh_answer_text" answer={{answer}}>
<div role="button" class="csh_reveal_info">Help us improve hints for this problem </div>
<div class="csh_user_info" style="display: none;"> <br> Submitting an incorrect answer for this problem provides you with a hint specific to the mistake that you made - these hints are made by other students who made the same mistake as you did. Help to make the hints for this problem better by rating the hint that you received, or if you might have better advice to give other students, submit a new hint! <br> If you choose to submit a new hint, keep in mind that the hints are specific to one incorrect answer; specific advice (perhaps on some aspect of the problem that you overlooked) is more helpful than generic advice.</div>
<br>
Your original answer was: <b>{{answer}}</b></h>
</div>
</script>
<script type="x-tmpl/mustache" id="add_hint_creation">
<div>
<input type ="button" class="csh_student_hint_creation" value="Contribute a New Hint">
</input>
</div>
</script>
<div class="crowdsourcehinter_block">
<div class='csh_hint_reveal'>
<div class='csh_hint_text' student_answer = '' hint_received='' rating=''>
</div>
<div class='csh_hint_rating_on_incorrect'>
<div class="csh_rate_hint_text">
This hint was:
</div>
<div role="button" class="csh_rate_hint" data-rate="upvote" title="This hint was helpful!">
<b> Helpful </b>
</div>
<div role="button" class="csh_rate_hint" data-rate="downvote" title="This hint was not very helpful.">
<b> Unhelpful </b>
</div>
<div role="button" class="csh_report_hint" title="Report this hint">
<b></b>
</div>
</div>
</div>
<section class="csh_correct"></section>
<div class="csh_student_submission">
<div class="csh_reported_hints">
<span>moderate reported hints</span>
</div>
</div>
</div>
<div class="crowdsourcehinter_edit_block">
<p>
Generic hints should be in the form of a python list. e.x. ['generic hint text']
</p>
<p>
Generic Hints: <textarea type="text" class="csh_generic_hints" value = "{{generic}}"/>
</p>
<p>
Initial hints should be a python dictionary, with keys representing anticipated incorrect answers and values being hints. e.x {"incorrect answer example 1": "hint for incorrect answer 1"}. The rating of initial hints defaults to 0.
</p>
<p>
Initial Hints: <textarea type="text" class="csh_initial_hints" value = "{{initial}}"/>
</p>
<p>
This is the element of the problem for which the hinter is working. This is the "data-usage-id" of the problem block. It should look something like i4x://edX/DemoX/problem/f958789435cf47218ff32f0d600f1184
</p>
<p>
Problem Element: <textarea type="text" class="csh_hinting_element" value = "{{hinting_element}}"/>
</p>
<p>
<input type="button" class="csh_apply_settings" value="Apply Settings">
</p>
<div class='csh_check_success'/>
</div>
function CrowdsourceHinterStudio(runtime, element, data){
//set text area values to be what is currently in the hinter. to be replaced by above code.
$('.csh_initial_hints', element).val(data.initial);
$('.csh_generic_hints', element).val(data.generic);
$('.csh_hinting_element', element).val(data.element);
/**
* Apply settings for initial hints, generic hints, and the element for which the hinter is
* working.
*/
function apply_settings(){ return function(apply_settings_button){
var initial = unescape($('.csh_initial_hints').val());
var generic = unescape($('.csh_generic_hints').val());
var hinting_element = unescape($('.csh_hinting_element').val());
$.ajax({
type: "POST",
url: runtime.handlerUrl(element, 'set_initial_settings'),
data: JSON.stringify({"initial_hints": initial, "generic_hints": generic, "element": hinting_element}),
success: function(result){
if(result.success){
$('.csh_check_success', element).text('hints successfully added to the database');
} else {
$('.csh_check_success', element).text('there was a problem adding your hints to the database. check the format on your hints.');
}
Logger.log('crowd_hinter.staff_edit_hinter', {"generic_hints": generic, "initial_hint": initial, "element": hinting_element, "successfully_set_hints": result.success});
}
});
}}
$(element).on('click', '.csh_apply_settings', apply_settings($(this)));
}
"""Setup for Crowdsource Hinter XBlock."""
import os
from setuptools import setup
def package_data(pkg, roots):
"""Generic function to find package_data.
All of the files under each of the `roots` will be declared as package
data for package `pkg`.
"""
data = []
for root in roots:
for dirname, _, files in os.walk(os.path.join(pkg, root)):
for fname in files:
data.append(os.path.relpath(os.path.join(dirname, fname), pkg))
return {pkg: data}
setup(
name='crowdsourcehinter-xblock',
version='0.1',
description='crowdsourcehinter XBlock', # TODO: write a better description.
packages=[
'crowdsourcehinter',
],
install_requires=[
'XBlock',
],
entry_points={
'xblock.v1': [
'crowdsourcehinter = crowdsourcehinter:CrowdsourceHinter',
]
},
package_data=package_data("crowdsourcehinter", ["static", "public"]),
)
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