Commit b19291c6 by solashirai Committed by Piotr Mitros

removed unused funcitonality, fixed naming

parent b0d54190
...@@ -28,10 +28,10 @@ class CrowdsourceHinter(XBlock): ...@@ -28,10 +28,10 @@ class CrowdsourceHinter(XBlock):
# {"incorrect_answer": {"hint": rating}} # {"incorrect_answer": {"hint": rating}}
initial_hints = Dict(default={}, scope=Scope.content) initial_hints = Dict(default={}, scope=Scope.content)
# This is a list of incorrect answer submissions made by the student. this list is mostly used for # This is a list of incorrect answer submissions made by the student. this list is mostly used for
# feedback, to find which incorrect answer's hint a student voted on. # when the student starts rating hints, to find which incorrect answer's hint a student voted on.
# #
# Example: ["personal computer", "PC", "computerr"] # Example: ["personal computer", "PC", "computerr"]
WrongAnswers = List([], scope=Scope.user_state) incorrect_answers = List([], scope=Scope.user_state)
# A dictionary of generic_hints. default hints will be shown to students when there are no matches with the # A dictionary of generic_hints. default hints will be shown to students when there are no matches with the
# student's incorrect answer within the hint_database dictionary (i.e. no students have made hints for the # student's incorrect answer within the hint_database dictionary (i.e. no students have made hints for the
# particular incorrect answer) # particular incorrect answer)
...@@ -43,21 +43,13 @@ class CrowdsourceHinter(XBlock): ...@@ -43,21 +43,13 @@ class CrowdsourceHinter(XBlock):
# multiple times) # multiple times)
# #
# Example: ["You misspelled computer, remove the last r."] # Example: ["You misspelled computer, remove the last r."]
Used = List([], scope=Scope.user_state) used = List([], scope=Scope.user_state)
# This list is used to prevent students from voting multiple times on the same hint during the feedback stage.
# i believe this will also prevent students from voting again on a particular hint if they were to return to
# a particular problem later
Voted = List(default=[], scope=Scope.user_state)
# This is a dictionary of hints that have been reported. the values represent the incorrect answer submission, and the # This is a dictionary of hints that have been reported. the values represent the incorrect answer submission, and the
# keys are the hints the corresponding hints. hints with identical text for differing answers will all not show up for the # keys are the hints the corresponding hints. hints with identical text for differing answers will all not show up for the
# student. # student.
# #
# Example: {"desk": "You're completely wrong, the answer is supposed to be computer."} # Example: {"desk": "You're completely wrong, the answer is supposed to be computer."}
Reported = Dict(default={}, scope=Scope.user_state_summary) reported_hints = Dict(default={}, scope=Scope.user_state_summary)
# This string determines whether or not to show only the best (highest rated) hint to a student
# When set to 'True' only the best hint will be shown to the student.
# Details on operation when set to 'False' are to be finalized.
show_best = Boolean(default=True, scope=Scope.user_state_summary)
# This String represents the xblock element for which the hinter is running. It is necessary to manually # This String represents the xblock element for which the hinter is running. It is necessary to manually
# set this value in the XML file under the format "hinting_element": "i4x://edX/DemoX/problem/Text_Input" . # set this value in the XML file under the format "hinting_element": "i4x://edX/DemoX/problem/Text_Input" .
# Setting the element in the XML file is critical for the hinter to work. # Setting the element in the XML file is critical for the hinter to work.
...@@ -139,42 +131,29 @@ class CrowdsourceHinter(XBlock): ...@@ -139,42 +131,29 @@ class CrowdsourceHinter(XBlock):
answer = answer[eqplace:] answer = answer[eqplace:]
remaining_hints = str(self.find_hints(answer)) remaining_hints = str(self.find_hints(answer))
if remaining_hints != str(0): if remaining_hints != str(0):
best_hint = max(self.hint_database[str(answer)].iteritems(), key=operator.itemgetter(1))[0] for hint in self.hint_database[str(answer)]:
if self.show_best: print hint, self.reported_hints.keys()
# if set to show best, only the best hint will be shown. Different hints will not be shown print str(self.reported_hints)
# for multiple submissions/hint requests if hint not in self.reported_hints.keys():
# currently set by default to True #if best_hint hasn't been set yet or the rating of hints is greater than the rating of best_hint
if best_hint not in self.Reported.keys(): if (best_hint == "" or self.hint_database[str(answer)][hint] > self.hint_database[str(answer)][str(best_hint)]):
self.Used.append(best_hint) best_hint = hint
self.used.append(best_hint)
return {'BestHint': best_hint, "StudentAnswer": answer} return {'BestHint': best_hint, "StudentAnswer": answer}
if best_hint not in self.Used:
# choose highest rated hint for the incorrect answer
if best_hint not in self.Reported.keys():
self.Used.append(best_hint)
return {'BestHint': best_hint, "StudentAnswer": answer}
# choose another random hint for the answer.
temporary_hints_list = []
for hint_keys in self.hint_database[str(answer)]:
if hint_keys not in self.Used:
if hint_keys not in self.Reported:
temporary_hints_list.append(str(hint_keys))
not_used = random.choice(temporary_hints_list)
self.Used.append(not_used)
return {'BestHint': 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) generic_hint = random.choice(self.generic_hints)
self.Used.append(not_used) self.used.append(generic_hint)
return {'BestHint': not_used, "StudentAnswer": answer} return {'BestHint': generic_hint, "StudentAnswer": answer}
else: else:
# if there are no more hints left in either the database or defaults # if there are no hints in either the database or generic hints
self.Used.append(str("There are no hints for" + " " + answer)) self.used.append(str("There are no hints for" + " " + answer))
return {'Hints': "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):
""" """
This function is used to find all appropriate hints that would be provided for This function is used to check that an incorrect answer has available hints to show.
an incorrect answer. It will also add the incorrect answer test to self.incorrect_answers.
Args: Args:
answer: This is equal to answer from get_hint, the answer the student submitted answer: This is equal to answer from get_hint, the answer the student submitted
...@@ -182,90 +161,60 @@ class CrowdsourceHinter(XBlock): ...@@ -182,90 +161,60 @@ class CrowdsourceHinter(XBlock):
Returns 0 if no hints to show exist Returns 0 if no hints to show exist
""" """
isreported = [] isreported = []
isused = 0 self.incorrect_answers.append(str(answer)) # add the student's input to the temporary list
self.WrongAnswers.append(str(answer)) # add the student's input to the temporary list
if str(answer) not in self.hint_database: if str(answer) not in self.hint_database:
# add incorrect answer to hint_database if no precedent exists # add incorrect answer to hint_database if no precedent exists
self.hint_database[str(answer)] = {} self.hint_database[str(answer)] = {}
return str(0) return str(0)
for hint_keys in self.hint_database[str(answer)]: for hint_keys in self.hint_database[str(answer)]:
for reported_keys in self.Reported: for reported_keys in self.reported_hints:
if hint_keys == reported_keys: if hint_keys == reported_keys:
isreported.append(hint_keys) isreported.append(hint_keys)
if str(hint_keys) in self.Used: if (len(self.hint_database[str(answer)]) - len(isreported)) > 0:
if self.show_best is False:
isused += 1
if (len(self.hint_database[str(answer)]) - len(isreported) - isused) > 0:
return str(1) return str(1)
else: else:
return str(0) return str(0)
@XBlock.json_handler @XBlock.json_handler
def get_feedback(self, data, suffix=''): def get_used_hint_answer_data(self, data, suffix=''):
""" """
This function is used to facilitate student feedback to hints. Specifically this function This function helps to facilitate student rating of hints and contribution of new hints.
is used to send necessary data to JS about incorrect answer submissions and hints. Specifically this function is used to send necessary data to JS about incorrect answer
submissions and hints. It also will return hints that have been reported, although this
is only for Staff.
Returns: Returns:
feedback_data: This dicitonary contains all incorrect answers that a student submitted used_hint_answer_text: This dicitonary contains reported hints/answers (if the user is staff) and the
for the question, all the hints the student recieved, as well as two first hint/answer pair that the student submitted for a problem.
more random hints that exist for an incorrect answer in the hint_database
""" """
# feedback_data is a dictionary of hints (or lack thereof) used for a # used_hint_answer_text is a dictionary of hints (or lack thereof) used for a
# specific answer, as well as 2 other random hints that exist for each answer # specific answer, as well as 2 other random hints that exist for each answer
# that were not used. The keys are the used hints, the values are the # that were not used. The keys are the used hints, the values are the
# corresponding incorrect answer # corresponding incorrect answer
feedback_data = {} used_hint_answer_text = {}
if self.get_user_is_staff(): if self.get_user_is_staff():
if len(self.Reported) != 0: for index in range(0, len(self.reported_hints)):
for answer_keys in self.hint_database: used_hint_answer_text[str(self.reported_hints[i])] = str("reported")
if str(len(self.hint_database[str(answer_keys)])) != str(0): if len(self.incorrect_answers) == 0:
for hints in self.hint_database[str(answer_keys)]: return used_hint_answer_text
for reported_hints in self.Reported:
if str(hints) == reported_hints:
feedback_data[str(hints)] = str("Reported")
if len(self.WrongAnswers) == 0:
return feedback_data
else: else:
for index in range(0, len(self.Used)): for index in range(0, len(self.used)):
# each index is a hint that was used, in order of usage # each index is a hint that was used, in order of usage
if str(self.Used[index]) in self.hint_database[self.WrongAnswers[index]]: if str(self.used[index]) in self.hint_database[self.incorrect_answers[index]]:
# add new key (hint) to feedback_data with a value (incorrect answer) # add new key (hint) to used_hint_answer_text with a value (incorrect answer)
feedback_data[str(self.Used[index])] = str(self.WrongAnswers[index]) used_hint_answer_text[str(self.used[index])] = str(self.incorrect_answers[index])
self.WrongAnswers = [] self.incorrect_answers = []
self.Used = [] self.used = []
return feedback_data return used_hint_answer_text
else: else:
# if the student's answer had no hints (or all the hints were reported and unavailable) return None # if the student's answer had no hints (or all the hints were reported and unavailable) return None
feedback_data[None] = str(self.WrongAnswers[index]) used_hint_answer_text[None] = str(self.incorrect_answers[index])
self.WrongAnswers = [] self.incorrect_answers = []
self.Used = [] self.used = []
return feedback_data return used_hint_answer_text
self.WrongAnswers=[] self.incorrect_answers=[]
self.Used=[] self.used=[]
return feedback_data return used_hint_answer_text
@XBlock.json_handler
def get_ratings(self, data, suffix=''):
"""
This function is used to return the ratings of hints during hint feedback.
data['student_answer'] is the answer for the hint being displayed
data['hint'] is the hint being shown to the student
returns:
hint_rating: the rating of the hint as well as data on what the hint in question is
"""
hint_rating = {}
if data['student_answer'] == 'Reported':
hint_rating['rating'] = 0
hint_rating['student_ansxwer'] = 'Reported'
hint_rating['hint'] = data['hint']
return hint_rating
hint_rating['rating'] = self.hint_database[data['student_answer']][data['hint']]
hint_rating['student_answer'] = data['student_answer']
hint_rating['hint'] = data['hint']
return hint_rating
@XBlock.json_handler @XBlock.json_handler
def rate_hint(self, data, suffix=''): def rate_hint(self, data, suffix=''):
...@@ -275,40 +224,31 @@ class CrowdsourceHinter(XBlock): ...@@ -275,40 +224,31 @@ class CrowdsourceHinter(XBlock):
Hint ratings in hint_database are updated and the resulting hint rating (or reported status) is returned to JS. Hint ratings in hint_database are updated and the resulting hint rating (or reported status) is returned to JS.
Args: Args:
data['student_answer']: The incorrect answer that corresponds to the hint that is being voted on data['student_answer']: The incorrect answer that corresponds to the hint that is being rated
data['hint']: The hint that is being voted on data['hint']: The hint that is being rated
data['student_rating']: The rating chosen by the student. data['student_rating']: The rating chosen by the student.
Returns:
"rating": The rating of the hint.
""" """
answer_data = data['student_answer'] answer_data = data['student_answer']
data_rating = data['student_rating'] data_rating = data['student_rating']
data_hint = data['hint'] data_hint = data['hint']
print data_rating, answer_data
if data['student_rating'] == 'unreport': if data['student_rating'] == 'unreport':
for reported_hints in self.Reported: for reported_hints in self.reported_hints:
if reported_hints == data_hint: if reported_hints == data_hint:
self.Reported.pop(data_hint, None) self.reported_hints.pop(data_hint, None)
return {'rating': 'unreported'} return {'rating': 'unreported'}
if data['student_rating'] == 'remove': if data['student_rating'] == 'remove':
for reported_hints in self.Reported: for reported_hints in self.reported_hints:
if data_hint == reported_hints: if data_hint == reported_hints:
self.hint_database[self.Reported[data_hint]].pop(data_hint, None) self.hint_database[self.reported_hints[data_hint]].pop(data_hint, None)
self.Reported.pop(data_hint, None) self.reported_hints.pop(data_hint, None)
return {'rating': 'removed'} return {'rating': 'removed'}
if data['student_rating'] == 'report': if data['student_rating'] == 'report':
# add hint to Reported dictionary # add hint to Reported dictionary
self.Reported[str(data_hint)] = answer_data self.reported_hints[str(data_hint)] = answer_data
return {"rating": 'reported', 'hint': data_hint} return {"rating": 'reported', 'hint': data_hint}
if str(data_hint) not in self.Voted:
self.Voted.append(str(data_hint)) # add data to Voted to prevent multiple votes
rating = self.change_rating(data_hint, data_rating, answer_data) # change hint rating rating = self.change_rating(data_hint, data_rating, answer_data) # change hint rating
if str(rating) == str(0):
return {"rating": str(0), 'hint': data_hint}
else:
return {"rating": str(rating), 'hint': data_hint} return {"rating": str(rating), 'hint': data_hint}
else:
return {"rating": str('voted'), 'hint': data_hint}
def change_rating(self, data_hint, data_rating, answer_data): def change_rating(self, data_hint, data_rating, answer_data):
""" """
...@@ -358,7 +298,7 @@ class CrowdsourceHinter(XBlock): ...@@ -358,7 +298,7 @@ class CrowdsourceHinter(XBlock):
This function serves to return the dictionary of reported hints to JS. This is intended for use in This function serves to return the dictionary of reported hints to JS. This is intended for use in
the studio_view, which is under construction at the moment the studio_view, which is under construction at the moment
""" """
return self.Reported return self.reported_hints
@staticmethod @staticmethod
def workbench_scenarios(): def workbench_scenarios():
......
<script type='x-tmpl/mustache' id='show_hint_contribution'> <script type='x-tmpl/mustache' id='show_hint_rating_ux'>
<div class='csh_hint_value' value="{{hintText}}"> <div class='csh_hint_value' value="{{hintText}}">
<div class='csh_hint_data'> <div class='csh_hint_data'>
<div class="csh_hint"><b>{{hintText}}</b></div> <div class="csh_hint"><b>{{hintText}}</b></div>
......
...@@ -37,21 +37,21 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -37,21 +37,21 @@ function CrowdsourceHinter(runtime, element, data){
} }
/** /**
* Start student hint contribution. This will allow students to contribute new hints * Start student hint rating/contribution. This will allow students to contribute new hints
* to the hinter as well as vote on the helpfulness of the first hint they received * to the hinter as well as vote on the helpfulness of the first hint they received
* for the current problem. This function is called after the student answers * for the current problem. This function is called after the student answers
* the question correctly. * the question correctly.
*/ */
function startHintContribution(){ function startHintRating(){
$('.csh_correct', element).show(); $('.csh_correct', element).show();
$(".csh_hint_reveal", element).hide(); $(".csh_hint_reveal", element).hide();
if($('.csh_hint_creation', element)){ if($('.csh_hint_creation', element)){
//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
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: runtime.handlerUrl(element, 'get_feedback'), url: runtime.handlerUrl(element, 'get_used_hint_answer_data'),
data: JSON.stringify({}), data: JSON.stringify({}),
success: setHintContributionDivs success: setHintRatingUX
}); });
} }
} }
...@@ -60,6 +60,7 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -60,6 +60,7 @@ function CrowdsourceHinter(runtime, element, data){
* Check whether or not the question was correctly answered by the student. * Check whether or not the question was correctly answered by the student.
* The current method of checking the correctness of the answer is very brittle * The current method of checking the correctness of the answer is very brittle
* since we simply look for a string within the problemGradedEventData. * since we simply look for a string within the problemGradedEventData.
* HACK
* @param problemGradedEventData is the data from problem_graded event. * @param problemGradedEventData is the data from problem_graded event.
*/ */
function checkIsAnswerCorrect(problemGradedEventData){ function checkIsAnswerCorrect(problemGradedEventData){
...@@ -80,7 +81,7 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -80,7 +81,7 @@ function CrowdsourceHinter(runtime, element, data){
//search method of correctness of problem is brittle due to checking for a class within //search method of correctness of problem is brittle due to checking for a class within
//the problem block. //the problem block.
if (checkIsAnswerCorrect(data)){ if (checkIsAnswerCorrect(data)){
startHintContribution(); startHintRating();
} else { //if the submitted answer is incorrect } else { //if the submitted answer is incorrect
getHint(data); getHint(data);
} }
...@@ -98,15 +99,15 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -98,15 +99,15 @@ function CrowdsourceHinter(runtime, element, data){
} }
/** /**
* Called by setHintContributionDivs to append hints into divs created by * Called by setHintRatingUX to append hints into divs created by
* showStudentSubmissoinHistory, after the student answered the question correctly. * showStudentSubmissoinHistory, after the student answered the question correctly.
* Feedback on hints at this stage consists of upvote/downvote/report buttons. * Feedback on hints at this stage consists of upvote/downvote/report buttons.
* @param hint is the first hint that was shown to the student * @param hint is the first hint that was shown to the student
* @param student_answer is the first incorrect answer submitted by the student * @param student_answer is the first incorrect answer submitted by the student
*/ */
function showStudentHintContribution(hint, student_answer){ function showStudentHintRatingUX(hint, student_answer){
var hintContributionTemplate = $(Mustache.render($('#show_hint_contribution').html(), {hintText: hint})); var hintRatingUXTemplate = $(Mustache.render($('#show_hint_rating_ux').html(), {hintText: hint}));
$('.csh_answer_text', element).append(hintContributionTemplate); $('.csh_answer_text', element).append(hintRatingUXTemplate);
var hintCreationTemplate = $(Mustache.render($('#add_hint_creation').html(), {})); var hintCreationTemplate = $(Mustache.render($('#add_hint_creation').html(), {}));
$('.csh_answer_text', element).append(hintCreationTemplate); $('.csh_answer_text', element).append(hintCreationTemplate);
} }
...@@ -125,8 +126,8 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -125,8 +126,8 @@ function CrowdsourceHinter(runtime, element, data){
/** /**
* 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. showStudentHintContribution appends new hints into these divs. * answering the question. showStudentHintRatingUX appends new hints into these divs.
* When the hinter is set to show best, only one div will be created. *
* @param student_answers is the text of the student's incorrect answer * @param student_answers is the text of the student's incorrect answer
*/ */
function showStudentSubmissionHistory(student_answer){ function showStudentSubmissionHistory(student_answer){
...@@ -138,11 +139,11 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -138,11 +139,11 @@ function CrowdsourceHinter(runtime, element, data){
* Set up student/staff voting on hints and contribution of new hints. The original incorrect answer and the * Set up student/staff voting on hints and contribution of new hints. The original incorrect answer and the
* the corresponding hint shown to the student is displayed. Students can upvote/downvote/report * the corresponding hint shown to the student is displayed. Students can upvote/downvote/report
* the hint or contribute a new hint for their incorrect answer. * the hint or contribute a new hint for their incorrect answer.
* Only one incorrect answer and hint will be shown when the hinter is set to show best. *
* @param result is a dictionary of incorrect answers and hints, with the index being the hint and the value * @param result is a dictionary of incorrect answers and hints, with the index being the hint and the value
* being the incorrect answer * being the incorrect answer
*/ */
function setHintContributionDivs(result){ function setHintRatingUX(result){
if(data.isStaff){ //allow staff to see and remove/return reported hints to/from the hint pool for a problem if(data.isStaff){ //allow staff to see and remove/return reported hints to/from the hint pool for a problem
$('.crowdsourcehinter_block', element).attr('class', 'crowdsourcehinter_block_is_staff'); $('.crowdsourcehinter_block', element).attr('class', 'crowdsourcehinter_block_is_staff');
$.each(result, function(index, value) { $.each(result, function(index, value) {
...@@ -164,7 +165,7 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -164,7 +165,7 @@ function CrowdsourceHinter(runtime, element, data){
var hintCreationTemplate = $(Mustache.render($('#add_hint_creation').html(), {})); var hintCreationTemplate = $(Mustache.render($('#add_hint_creation').html(), {}));
$('.csh_student_answer', element).append(hintCreationTemplate); $('.csh_student_answer', element).append(hintCreationTemplate);
} else { } else {
showStudentHintContribution(hint, student_answer); showStudentHintRatingUX(hint, student_answer);
} }
} }
}); });
...@@ -175,7 +176,7 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -175,7 +176,7 @@ function CrowdsourceHinter(runtime, element, data){
* is triggered by clicking the "contribute a new hint" button. * is triggered by clicking the "contribute a new hint" button.
* @param createTextInputButtonHTML is the "contribute a new hint" button that was clicked * @param createTextInputButtonHTML is the "contribute a new hint" button that was clicked
*/ */
function create_text_input(){ return function(createTextInputButtonHTML){ function createHintContributionTextInput(){ return function(createTextInputButtonHTML){
$('.csh_student_hint_creation', element).each(function(){ $('.csh_student_hint_creation', element).each(function(){
$(createTextInputButtonHTML.currentTarget).show(); $(createTextInputButtonHTML.currentTarget).show();
}); });
...@@ -187,11 +188,11 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -187,11 +188,11 @@ function CrowdsourceHinter(runtime, element, data){
var hintTextInputTemplate = $(Mustache.render($('#hint_text_input').html(), {student_answer: student_answer})); var hintTextInputTemplate = $(Mustache.render($('#hint_text_input').html(), {student_answer: student_answer}));
$('.csh_answer_text', element).append(hintTextInputTemplate); $('.csh_answer_text', element).append(hintTextInputTemplate);
}} }}
$(element).on('click', '.csh_student_hint_creation', create_text_input($(this))); $(element).on('click', '.csh_student_hint_creation', createHintContributionTextInput($(this)));
/** /**
* Submit a new hint created by the student to the hint pool. Hint text is in * Submit a new hint created by the student to the hint pool. Hint text is in
* the text input area created by create_text_input. Contributed hints are specific to * the text input area created by createHintContributionTextInput. Contributed hints are specific to
* incorrect answers. Triggered by clicking the "submit hint" button. * incorrect answers. Triggered by clicking the "submit hint" button.
* @param submitHintButtonHTML is the "submit hint" button clicked * @param submitHintButtonHTML is the "submit hint" button clicked
*/ */
...@@ -258,7 +259,6 @@ function CrowdsourceHinter(runtime, element, data){ ...@@ -258,7 +259,6 @@ function CrowdsourceHinter(runtime, element, data){
*/ */
function removeReportedHint(){ function removeReportedHint(){
Logger.log('crowd_hinter.staff_rate_hint.click.event', {"hint": hint, "student_answer": student_answer, "rating": rating}); Logger.log('crowd_hinter.staff_rate_hint.click.event', {"hint": hint, "student_answer": student_answer, "rating": rating});
//TODO: change if statement, just find .csh_hint_value with attribute of hint
$(".csh_hint_value[value='" + hint + "']", element).remove(); $(".csh_hint_value[value='" + hint + "']", element).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