Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
crowdsourcehinter
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
crowdsourcehinter
Commits
5a1c72ac
Commit
5a1c72ac
authored
Apr 13, 2015
by
solashirai
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code improvement
parent
7b088a39
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
78 additions
and
61 deletions
+78
-61
crowdsourcehinter/crowdsourcehinter.py
+7
-7
crowdsourcehinter/static/html/crowdsourcehinter.html
+1
-1
crowdsourcehinter/static/js/src/crowdsourcehinter.js
+70
-53
No files found.
crowdsourcehinter/crowdsourcehinter.py
View file @
5a1c72ac
...
@@ -102,7 +102,7 @@ class CrowdsourceHinter(XBlock):
...
@@ -102,7 +102,7 @@ class CrowdsourceHinter(XBlock):
frag
.
add_javascript_url
(
'//cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js'
)
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_css
(
self
.
resource_string
(
"static/css/crowdsourcehinter.css"
))
frag
.
add_javascript
(
self
.
resource_string
(
"static/js/src/crowdsourcehinter.js"
))
frag
.
add_javascript
(
self
.
resource_string
(
"static/js/src/crowdsourcehinter.js"
))
frag
.
initialize_js
(
'CrowdsourceHinter'
,
{
'hinting_element'
:
self
.
Element
,
'isStaff'
:
self
.
Element
})
frag
.
initialize_js
(
'CrowdsourceHinter'
,
{
'hinting_element'
:
self
.
Element
,
'isStaff'
:
self
.
xmodule_runtime
.
user_is_staff
})
return
frag
return
frag
@XBlock.json_handler
@XBlock.json_handler
...
@@ -115,7 +115,7 @@ class CrowdsourceHinter(XBlock):
...
@@ -115,7 +115,7 @@ class CrowdsourceHinter(XBlock):
data['submittedanswer']: The string of text that the student submits for a problem.
data['submittedanswer']: The string of text that the student submits for a problem.
returns:
returns:
'Hints
ToUse
': the highest rated hint for an incorrect answer
'Hints': the highest rated hint for an incorrect answer
or another random hint for an incorrect answer
or another random hint for an incorrect answer
or 'Sorry, there are no more hints for this answer.' if no more hints exist
or 'Sorry, there are no more hints for this answer.' if no more hints exist
"""
"""
...
@@ -146,12 +146,12 @@ class CrowdsourceHinter(XBlock):
...
@@ -146,12 +146,12 @@ class CrowdsourceHinter(XBlock):
# currently set by default to True
# currently set by default to True
if
best_hint
not
in
self
.
Reported
.
keys
():
if
best_hint
not
in
self
.
Reported
.
keys
():
self
.
Used
.
append
(
best_hint
)
self
.
Used
.
append
(
best_hint
)
return
{
'Hints
ToUse
'
:
best_hint
,
"StudentAnswer"
:
answer
}
return
{
'Hints'
:
best_hint
,
"StudentAnswer"
:
answer
}
if
best_hint
not
in
self
.
Used
:
if
best_hint
not
in
self
.
Used
:
# choose highest rated hint for the incorrect answer
# choose highest rated hint for the incorrect answer
if
best_hint
not
in
self
.
Reported
.
keys
():
if
best_hint
not
in
self
.
Reported
.
keys
():
self
.
Used
.
append
(
best_hint
)
self
.
Used
.
append
(
best_hint
)
return
{
'Hints
ToUse
'
:
best_hint
,
"StudentAnswer"
:
answer
}
return
{
'Hints'
:
best_hint
,
"StudentAnswer"
:
answer
}
# choose another random hint for the answer.
# choose another random hint for the answer.
temporary_hints_list
=
[]
temporary_hints_list
=
[]
for
hint_keys
in
self
.
hint_database
[
str
(
answer
)]:
for
hint_keys
in
self
.
hint_database
[
str
(
answer
)]:
...
@@ -160,16 +160,16 @@ class CrowdsourceHinter(XBlock):
...
@@ -160,16 +160,16 @@ class CrowdsourceHinter(XBlock):
temporary_hints_list
.
append
(
str
(
hint_keys
))
temporary_hints_list
.
append
(
str
(
hint_keys
))
not_used
=
random
.
choice
(
temporary_hints_list
)
not_used
=
random
.
choice
(
temporary_hints_list
)
self
.
Used
.
append
(
not_used
)
self
.
Used
.
append
(
not_used
)
return
{
'Hints
ToUse
'
:
not_used
,
"StudentAnswer"
:
answer
}
return
{
'Hints'
:
not_used
,
"StudentAnswer"
:
answer
}
# find generic hints for the student if no specific hints exist
# find generic hints for the student if no specific hints exist
if
len
(
self
.
generic_hints
)
!=
0
:
if
len
(
self
.
generic_hints
)
!=
0
:
not_used
=
random
.
choice
(
self
.
generic_hints
)
not_used
=
random
.
choice
(
self
.
generic_hints
)
self
.
Used
.
append
(
not_used
)
self
.
Used
.
append
(
not_used
)
return
{
'Hints
ToUse
'
:
not_used
,
"StudentAnswer"
:
answer
}
return
{
'Hints'
:
not_used
,
"StudentAnswer"
:
answer
}
else
:
else
:
# if there are no more hints left in either the database or defaults
# if there are no more hints left in either the database or defaults
self
.
Used
.
append
(
str
(
"There are no hints for"
+
" "
+
answer
))
self
.
Used
.
append
(
str
(
"There are no hints for"
+
" "
+
answer
))
return
{
'Hints
ToUse
'
:
"Sorry, there are no hints for this answer."
,
"StudentAnswer"
:
answer
}
return
{
'Hints'
:
"Sorry, there are no hints for this answer."
,
"StudentAnswer"
:
answer
}
def
find_hints
(
self
,
answer
):
def
find_hints
(
self
,
answer
):
"""
"""
...
...
crowdsourcehinter/static/html/crowdsourcehinter.html
View file @
5a1c72ac
...
@@ -62,7 +62,7 @@
...
@@ -62,7 +62,7 @@
<div
class=
"crowdsourcehinter_block"
>
<div
class=
"crowdsourcehinter_block"
>
<div
class=
'csh_hint_reveal'
>
<div
class=
'csh_hint_reveal'
>
<div
class=
'csh_Hints
ToUse
'
student_answer =
''
hint_received=
''
>
<div
class=
'csh_Hints'
student_answer =
''
hint_received=
''
>
</div>
</div>
<div
class=
'csh_HintQuickFeedback'
>
<div
class=
'csh_HintQuickFeedback'
>
<div
role=
"button"
class=
"csh_rate_hint"
data-rate=
"upvote"
title=
"This hint was helpful!"
>
<div
role=
"button"
class=
"csh_rate_hint"
data-rate=
"upvote"
title=
"This hint was helpful!"
>
...
...
crowdsourcehinter/static/js/src/crowdsourcehinter.js
View file @
5a1c72ac
...
@@ -4,10 +4,13 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -4,10 +4,13 @@ function CrowdsourceHinter(runtime, element, data){
var
executeHinter
=
true
;
var
executeHinter
=
true
;
$
(
".crowdsourcehinter_block"
,
element
).
hide
();
$
(
".crowdsourcehinter_block"
,
element
).
hide
();
if
(
executeHinter
){
if
(
!
executeHinter
){
return
;
}
var
isShowingHintFeedback
=
false
;
var
isShowingHintFeedback
=
false
;
var
voted
=
false
;
var
voted
=
false
;
$
(
".csh_HintsToUse"
,
element
).
text
(
""
)
;
var
correctSubmission
=
false
;
function
stopScript
(){
function
stopScript
(){
//This function is used to prevent a particular instance of the hinter from acting after
//This function is used to prevent a particular instance of the hinter from acting after
...
@@ -18,25 +21,21 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -18,25 +21,21 @@ function CrowdsourceHinter(runtime, element, data){
Logger
.
listen
(
'seq_prev'
,
null
,
stopScript
);
Logger
.
listen
(
'seq_prev'
,
null
,
stopScript
);
Logger
.
listen
(
'seq_goto'
,
null
,
stopScript
);
Logger
.
listen
(
'seq_goto'
,
null
,
stopScript
);
//data about the problem obtained from Logger.listen('problem_graded') is passed on to the onStudentSubmission.
//send student answer data and receive a hint from ajax call.
//directly passing data to onStudentSubmission does not appear to work
//pass data to showHint to actually show hint to student
function
get_event_data
(
event_type
,
data
,
element
){
function
get_hint
(
data
){
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.
//If it was correctly answered it will begin the process for giving feedback on hints.
if
(
problem_graded_event_data
[
1
].
search
(
/class="correct/
)
===
-
1
){
$
(
".crowdsourcehinter_block"
,
element
).
show
();
$
(
".crowdsourcehinter_block"
,
element
).
show
();
$
.
ajax
({
$
.
ajax
({
type
:
"POST"
,
type
:
"POST"
,
url
:
runtime
.
handlerUrl
(
element
,
'get_hint'
),
url
:
runtime
.
handlerUrl
(
element
,
'get_hint'
),
data
:
JSON
.
stringify
({
"submittedanswer"
:
unescape
(
problem_graded_event_
data
[
0
])}),
data
:
JSON
.
stringify
({
"submittedanswer"
:
unescape
(
data
[
0
])}),
success
:
seeh
int
success
:
showH
int
});
});
}
else
{
}
//first step to starting student feedback for hints
//this function will be called after student correctly answers question
function
start_feedback
(){
$
(
'.csh_correct'
,
element
).
show
();
$
(
'.csh_correct'
,
element
).
show
();
$
(
".csh_hint_reveal"
,
element
).
hide
();
$
(
".csh_hint_reveal"
,
element
).
hide
();
//send empty data for ajax call because not having a data field causes error
//send empty data for ajax call because not having a data field causes error
...
@@ -44,18 +43,30 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -44,18 +43,30 @@ function CrowdsourceHinter(runtime, element, data){
type
:
"POST"
,
type
:
"POST"
,
url
:
runtime
.
handlerUrl
(
element
,
'get_feedback'
),
url
:
runtime
.
handlerUrl
(
element
,
'get_feedback'
),
data
:
JSON
.
stringify
({}),
data
:
JSON
.
stringify
({}),
success
:
getFeedback
success
:
showStudentContribution
});
});
}
}
}
function
seehint
(
result
){
//This function will determine whether or not the student correctly answered the question.
//if incorrect, call function to get hint to show to student
//if correct, call function to start student feedback on hints
function
onStudentSubmission
(){
return
function
(
event_type
,
data
,
element
){
//search method of correctness of problem is brittle due to checking for a class within
//the problem block.
if
(
data
[
1
].
search
(
/class="correct/
)
===
-
1
){
get_hint
(
data
);
}
else
{
//if the correct answer is submitted
start_feedback
();
}
}}
Logger
.
listen
(
'problem_graded'
,
data
.
hinting_element
,
onStudentSubmission
());
function
showHint
(
result
){
//Show a hint to the student after an incorrect answer is submitted.
//Show a hint to the student after an incorrect answer is submitted.
$
(
'.csh_HintsToUse'
,
element
).
attr
(
'student_answer'
,
result
.
StudentAnswer
);
$
(
'.csh_Hints'
,
element
).
attr
(
'student_answer'
,
result
.
StudentAnswer
);
$
(
'.csh_HintsToUse'
,
element
).
attr
(
'hint_received'
,
result
.
HintsToUse
);
$
(
'.csh_Hints'
,
element
).
attr
(
'hint_received'
,
result
.
Hints
);
$
(
'.csh_HintsToUse'
,
element
).
text
(
"Hint: "
+
result
.
HintsToUse
);
$
(
'.csh_Hints'
,
element
).
text
(
"Hint: "
+
result
.
Hints
);
Logger
.
log
(
'crowd_hinter.seehint'
,
{
"student_answer"
:
result
.
StudentAnswer
,
"hint_received"
:
result
.
HintsToUse
});
Logger
.
log
(
'crowd_hinter.showHint'
,
{
"student_answer"
:
result
.
StudentAnswer
,
"hint_received"
:
result
.
Hints
});
}
}
function
showHintFeedback
(
hint
,
student_answer
){
function
showHintFeedback
(
hint
,
student_answer
){
...
@@ -93,7 +104,7 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -93,7 +104,7 @@ function CrowdsourceHinter(runtime, element, data){
$
(
".csh_reported_hints"
,
element
).
append
(
html
);
$
(
".csh_reported_hints"
,
element
).
append
(
html
);
}
}
function
s
etStudentAnswers
(
student_answers
){
function
s
howStudentSubmissionHistory
(
student_answers
){
//Append new divisions into html for each answer the student submitted before correctly
//Append new divisions into html for each answer the student submitted before correctly
//answering the question. showHintFeedback appends new hints into these divs.
//answering the question. showHintFeedback appends new hints into these divs.
//When the hinter is set to show best, only one div will be created
//When the hinter is set to show best, only one div will be created
...
@@ -106,7 +117,7 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -106,7 +117,7 @@ function CrowdsourceHinter(runtime, element, data){
$
(
".csh_feedback"
,
element
).
append
(
html
);
$
(
".csh_feedback"
,
element
).
append
(
html
);
}
}
function
getFeedback
(
result
){
function
showStudentContribution
(
result
){
//Set up the student feedback stage. Each student answer and all answer-specific hints for that answer are shown
//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.
//to the student, as well as an option to create a new hint for an answer.
if
(
data
.
isStaff
){
if
(
data
.
isStaff
){
...
@@ -121,7 +132,7 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -121,7 +132,7 @@ function CrowdsourceHinter(runtime, element, data){
if
(
!
isShowingHintFeedback
){
if
(
!
isShowingHintFeedback
){
$
.
each
(
result
,
function
(
index
,
value
)
{
$
.
each
(
result
,
function
(
index
,
value
)
{
if
(
value
!=
"Reported"
){
if
(
value
!=
"Reported"
){
s
etStudentAnswers
(
value
);
s
howStudentSubmissionHistory
(
value
);
student_answer
=
value
;
student_answer
=
value
;
hint
=
index
;
hint
=
index
;
//hints return null if no answer-specific hints exist
//hints return null if no answer-specific hints exist
...
@@ -151,17 +162,17 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -151,17 +162,17 @@ function CrowdsourceHinter(runtime, element, data){
}
}
}
}
$
(
element
).
on
(
'click'
,
'.csh_student_hint_creation'
,
function
(
){
function
create_text_input
(){
return
function
(
clicked
){
//create text input area for contributing a new hint
//create text input area for contributing a new hint
$
(
'.csh_student_hint_creation'
,
element
).
each
(
function
(){
$
(
'.csh_student_hint_creation'
,
element
).
each
(
function
(){
$
(
this
).
show
();
$
(
clicked
.
currentTarget
).
show
();
});
});
$
(
'.csh_student_text_input'
,
element
).
remove
();
$
(
'.csh_student_text_input'
,
element
).
remove
();
$
(
'.csh_submit_new'
,
element
).
remove
();
$
(
'.csh_submit_new'
,
element
).
remove
();
$
(
this
).
hide
();
$
(
clicked
.
currentTarget
).
hide
();
student_answer
=
$
(
this
).
parent
().
parent
().
find
(
'.csh_answer_text'
).
attr
(
'answer'
);
student_answer
=
$
(
clicked
.
currentTarget
).
parent
().
parent
().
find
(
'.csh_answer_text'
).
attr
(
'answer'
);
$
(
".csh_student_answer"
,
element
).
each
(
function
(){
$
(
".csh_student_answer"
,
element
).
each
(
function
(){
if
(
$
(
this
).
find
(
'.csh_answer_text'
).
attr
(
'answer'
)
==
student_answer
){
if
(
$
(
'.csh_answer_text'
,
element
).
attr
(
'answer'
)
==
student_answer
){
var
html
=
""
;
var
html
=
""
;
$
(
function
(){
$
(
function
(){
var
template
=
$
(
'#student_hint_creation'
).
html
();
var
template
=
$
(
'#student_hint_creation'
).
html
();
...
@@ -171,12 +182,13 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -171,12 +182,13 @@ function CrowdsourceHinter(runtime, element, data){
$
(
this
).
append
(
html
);
$
(
this
).
append
(
html
);
}
}
});
});
})
}}
$
(
element
).
on
(
'click'
,
'.csh_student_hint_creation'
,
create_text_input
(
$
(
this
)));
$
(
element
).
on
(
'click'
,
'.csh_submit_new'
,
function
(
){
function
submit_new_hint
(){
return
function
(
clicked
){
//add the newly created hint to the hinter's pool of hints
//add the newly created hint to the hinter's pool of hints
if
(
$
(
this
).
parent
().
parent
().
find
(
'.csh_student_text_input'
).
val
().
length
>
0
){
if
(
$
(
'.csh_student_text_input'
,
element
).
val
().
length
>
0
){
var
answerdata
=
unescape
(
$
(
this
).
attr
(
'answer'
)
);
var
answerdata
=
unescape
(
clicked
.
currentTarget
.
attributes
[
'answer'
].
value
);
var
newhint
=
unescape
(
$
(
'.csh_student_text_input'
).
val
());
var
newhint
=
unescape
(
$
(
'.csh_student_text_input'
).
val
());
$
(
'.csh_submitbutton'
,
element
).
show
();
$
(
'.csh_submitbutton'
,
element
).
show
();
$
.
ajax
({
$
.
ajax
({
...
@@ -185,28 +197,31 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -185,28 +197,31 @@ function CrowdsourceHinter(runtime, element, data){
data
:
JSON
.
stringify
({
"submission"
:
newhint
,
"answer"
:
answerdata
}),
data
:
JSON
.
stringify
({
"submission"
:
newhint
,
"answer"
:
answerdata
}),
success
:
Logger
.
log
(
'crowd_hinter.submit_new.click.event'
,
{
"student_answer"
:
answerdata
,
"new_hint_submission"
:
newhint
})
success
:
Logger
.
log
(
'crowd_hinter.submit_new.click.event'
,
{
"student_answer"
:
answerdata
,
"new_hint_submission"
:
newhint
})
});
});
$
(
this
).
parent
().
parent
().
find
(
'.csh_student_text_input'
).
remove
();
$
(
'.csh_student_text_input'
,
element
).
remove
();
$
(
this
).
remove
();
$
(
clicked
.
currentTarget
).
remove
();
}
}
})
}}
$
(
element
).
on
(
'click'
,
'.csh_submit_new'
,
submit_new_hint
(
$
(
this
)));
$
(
element
).
on
(
'click'
,
'.csh_rate_hint'
,
function
(
){
function
rate_hint
(){
return
function
(
clicked
){
//send info to hinter indicating whether the hint was upvoted, downvoted, or reported
//send info to hinter indicating whether the hint was upvoted, downvoted, or reported
if
(
!
voted
||
$
(
this
).
attr
(
'data-rate'
)
==
"report"
){
rating
=
clicked
.
currentTarget
.
attributes
[
'data-rate'
].
value
;
if
(
$
(
this
).
attr
(
'data-rate'
)
==
"report"
){
if
(
!
voted
||
rating
==
"report"
){
if
(
rating
==
"report"
){
alert
(
"This hint has been reported for review."
);
alert
(
"This hint has been reported for review."
);
}
}
hint
=
$
(
'.csh_HintsToUse
'
,
element
).
attr
(
'hint_received'
);
hint
=
$
(
'.csh_Hints
'
,
element
).
attr
(
'hint_received'
);
student_answer
=
$
(
'.csh_HintsToUse
'
,
element
).
attr
(
'student_answer'
);
student_answer
=
$
(
'.csh_Hints
'
,
element
).
attr
(
'student_answer'
);
$
.
ajax
({
$
.
ajax
({
type
:
"POST"
,
type
:
"POST"
,
url
:
runtime
.
handlerUrl
(
element
,
'rate_hint'
),
url
:
runtime
.
handlerUrl
(
element
,
'rate_hint'
),
data
:
JSON
.
stringify
({
"student_rating"
:
$
(
this
).
attr
(
'data-rate'
)
,
"hint"
:
hint
,
"student_answer"
:
student_answer
}),
data
:
JSON
.
stringify
({
"student_rating"
:
rating
,
"hint"
:
hint
,
"student_answer"
:
student_answer
}),
success
:
Logger
.
log
(
'crowd_hinter.rate_hint.click.event'
,
{
"hint"
:
hint
,
"student_answer"
:
student_answer
,
"rating"
:
$
(
this
).
attr
(
'data-rate'
)
})
success
:
Logger
.
log
(
'crowd_hinter.rate_hint.click.event'
,
{
"hint"
:
hint
,
"student_answer"
:
student_answer
,
"rating"
:
rating
})
});
});
voted
=
true
;
voted
=
true
;
}
}
});
}}
$
(
element
).
on
(
'click'
,
'.csh_rate_hint'
,
rate_hint
(
$
(
this
)));
function
removeFeedback
(){
function
removeFeedback
(){
//remove a hint from the staff feedback area after a staff member has
//remove a hint from the staff feedback area after a staff member has
...
@@ -218,17 +233,19 @@ function CrowdsourceHinter(runtime, element, data){
...
@@ -218,17 +233,19 @@ function CrowdsourceHinter(runtime, element, data){
});
});
}
}
$
(
element
).
on
(
'click'
,
'.csh_staff_rate'
,
function
(
){
function
staff_rate_hint
(){
return
function
(
clicked
){
//Staff "rating" removes or returns a reported hint from/to the hinter's pool of hints
//Staff "rating" removes or returns a reported hint from/to the hinter's pool of hints
hint
=
$
(
this
).
parent
().
find
(
".csh_hint"
).
text
();
hint
=
$
(
clicked
.
currentTarget
).
parent
().
find
(
".csh_hint"
).
text
();
rating
=
clicked
.
currentTarget
.
attributes
[
'data-rate'
].
value
student_answer
=
"Reported"
;
student_answer
=
"Reported"
;
Logger
.
log
(
'crowd_hinter.staff_rate_hint.click.event'
,
{
"hint"
:
hint
,
"student_answer"
:
student_answer
,
"rating"
:
$
(
this
).
attr
(
'data-rate'
)
});
Logger
.
log
(
'crowd_hinter.staff_rate_hint.click.event'
,
{
"hint"
:
hint
,
"student_answer"
:
student_answer
,
"rating"
:
rating
});
$
.
ajax
({
$
.
ajax
({
type
:
"POST"
,
type
:
"POST"
,
url
:
runtime
.
handlerUrl
(
element
,
'rate_hint'
),
url
:
runtime
.
handlerUrl
(
element
,
'rate_hint'
),
data
:
JSON
.
stringify
({
"student_rating"
:
$
(
this
).
attr
(
'data-rate'
)
,
"hint"
:
hint
,
"student_answer"
:
student_answer
}),
data
:
JSON
.
stringify
({
"student_rating"
:
rating
,
"hint"
:
hint
,
"student_answer"
:
student_answer
}),
success
:
removeFeedback
()
success
:
removeFeedback
()
});
});
})
}}
$
(
element
).
on
(
'click'
,
'.csh_staff_rate'
,
staff_rate_hint
(
$
(
this
)));
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment