def create_fill_in_the_blanks_widget(question, sections): question_widget = create_question_widget(question) num_sections = len(sections) paragraph = HBox([], layout=Layout(display='flex', flex_flow='row wrap', align_items='stretch', width='auto')) for i in range(num_sections): section = sections[i] # Because row-wrap still not working. See https://stackoverflow.com/questions/58405678/text-wrapping-in-ipywidgets prefix = widgets.HTML( value='<style>p{word-wrap: break-word}</style> <p>' + section['prefix'] + ' </p>') #prefix = Label(value = section['prefix'], layout=Layout(width='auto')) blank = Text(value='', placeholder='', description='', disabled=False, layout=(Layout(width='auto'))) suffix = widgets.HTML( value='<style>p{word-wrap: break-word}</style> <p>' + section['suffix'] + ' </p>') #suffix = Label(value=section['suffix'], layout=Layout(width='auto')) new_hbox = widgets.HBox([prefix, blank, suffix], layout=Layout(display='flex', flex_flow='row wrap', align_items='stretch', width='auto')) # new_hbox.box_style = 'info' paragraph.children += (new_hbox, ) # please G-d of programmers forgive me for I don't yet know how to get that colour from css. score_widget = create_score_widget('#4DD0E1') # fill_in = AppLayout(header=question_widget, # left_sidebar=paragraph, # center=None, # right_sidebar=None, # footer=score_widget, layout=Layout(display='flex', flex_flow='column', #align_items='stretch', width='100%')) fill_in = VBox([question_widget, paragraph, score_widget], layout=Layout(display='flex', flex_flow='column', align_items='stretch', width='100%')) fill_in.box_style = 'info' # compare checkbox value with original def check_answers(b): # run through each option, compare expected answer (checked/unchecked) with actual student answer num_sections = len(sections) incorrect = 0 missing = 0 paragraph_widget = fill_in.children[1] feedback_widget = fill_in.children[2] submit_button = feedback_widget.children[0] for i in range(num_sections): blank = paragraph_widget.children[i].children[1] actual_answer = blank.value expected_answer = sections[i]['answer'] # clear feedback before giving new feedback blank.layout = Layout(border='None', width='auto', height='32px') # red border + 'incorrect' for incorrectly checked # green border + 'correct!' for correctly checked if (actual_answer == ''): missing += 1 elif (expected_answer == actual_answer): blank.layout = Layout(border='1px solid #81C784', width='auto', height='31px') else: blank.layout = Layout(border='1px solid #e57373', width='auto', height='31px') incorrect += 1 # update the score label if incorrect + missing == 0: # Success! So disable checkboxes for i in range(num_sections): blank = paragraph_widget.children[i].children[1] blank.disabled = True if submit_button.description == 'Submit': text = '' else: text = 'Now you got it!' generate_feedback(fill_in, score_widget, style='success', feedback_text=text, show_show_answer_btn=False) submit_button.layout.disable = True else: # Some incorrect answers, write feedback so they can try again if missing > 0: text = 'Fill in all the blanks!' else: text = '' generate_feedback(fill_in, score_widget, style='danger', feedback_text=text, show_show_answer_btn=True) def show_answers(b): num_sections = len(sections) paragraph_widget = fill_in.children[1] feedback_widget = fill_in.children[2] submit_button = feedback_widget.children[0] for i in range(num_sections): blank = paragraph_widget.children[i].children[1] # clear feedback before giving the answers blank.value = '' blank.layout = Layout(border='None', width='auto', height='32px') blank.placeholder = sections[i]['answer'] generate_feedback(fill_in, score_widget, style='warning') submit_button = score_widget.children[0] submit_button.on_click(check_answers) show_answer_button = score_widget.children[2] show_answer_button.on_click(show_answers) return (fill_in)
def create_multi_answer_widget(question, options): question_widget = create_question_widget(question) # Need to make my own checkbox out of checkbox + label because LaTeX not displaying nicely in checkbox built in description label labels = [ widgets.HTML(value='<style>p{word-wrap: break-word}</style> <p>' + option['answer'] + ' </p>') for option in options ] checkboxes = [ HBox([ Checkbox(value=False, style={'description_width': 'initial'}, layout=Layout(width='30px')), lbl ], layout=Layout(display='flex', flex_flow='row wrap', align_items='stretch', width='auto')) for lbl in labels ] # for each option, create a feedback box on the left and a checkbox on the right vertical = [] for cb in checkboxes: new_hbox = widgets.HBox([Label(value=''), cb], layout=Layout(display='flex', flex_flow='row wrap', align_items='stretch', width='auto')) #new_hbox.box_style = 'info' vertical.append(new_hbox) # vertically laid out options with feedback on the left option_widget = widgets.VBox(vertical, layout=Layout(display='flex', flex_flow='column', align_items='stretch', width='100%')) score_widget = create_score_widget('#4DD0E1') multi_answer = VBox([question_widget, option_widget, score_widget], layout=Layout(display='flex', flex_flow='column', align_items='stretch', width='100%')) multi_answer.box_style = 'info' # compare checkbox value with original def check_answers(b): #run through each option, compare expected answer (checked/unchecked) with actual student answer num_options = len(options) incorrect = 0 missing = 0 option_widget = multi_answer.children[1] score_widget = multi_answer.children[2] submit_button = score_widget.children[0] for i in range(num_options): opt = option_widget.children[i] lbl = opt.children[0] cb = opt.children[1].children[0] actual_answer = cb.value expected_answer = options[i]['correct'] # clear feedback before giving new feedback opt.layout = Layout(border=None) lbl.value = '' lbl.layout = Layout(width='100px') # red border + 'incorrect' for incorrectly checked # green border + 'correct!' for correctly checked if (expected_answer and actual_answer): opt.layout = Layout(border='1px solid #81C784') lbl.value = 'Correct!' if (expected_answer and not actual_answer): missing += 1 if (not expected_answer and actual_answer): lbl.value = 'Incorrect' opt.layout = Layout(border='1px solid #e57373') incorrect += 1 # update the score label if incorrect + missing == 0: # Success! So disable checkboxes for i in range(num_options): opt = option_widget.children[i] cb = opt.children[1].children[0] cb.disabled = True if submit_button.description == 'Submit': text = '' else: text = 'Now you got it!' generate_feedback(multi_answer, score_widget, style='success', feedback_text=text, show_show_answer_btn=False) submit_button.layout.disable = True else: #Some incorrect answers, write feedback so they can try again if missing > 0: text = 'You missed some correct options, try again!' else: text = '' generate_feedback(multi_answer, score_widget, style='danger', feedback_text=text, show_show_answer_btn=False) submit_button = score_widget.children[0] submit_button.on_click(check_answers) return (multi_answer)