PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.8
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / TemplateHooks / Admin / AdminEditQuestionTemplate.php

AdminEditQuestionTemplate.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.8, at inc/TemplateHooks/Admin/AdminEditQuestionTemplate.php

958 lines 29.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\TemplateHooks\Admin;
4
5 use Exception;
6 use LearnPress\Helpers\Singleton;
7 use LearnPress\Helpers\Template;
8 use LearnPress\Models\Question\QuestionAnswerModel;
9 use LearnPress\Models\Question\QuestionPostFIBModel;
10 use LearnPress\Models\Question\QuestionPostModel;
11 use LearnPress\TemplateHooks\TemplateAJAX;
12 use stdClass;
13
14 /**
15 * Template Admin Edit Quiz.
16 *
17 * @since 4.2.9
18 * @version 1.0.0
19 */
20 class AdminEditQuestionTemplate {
21 use Singleton;
22
23 public function init() {
24 add_action( 'learn-press/admin/edit-question/layout', [ $this, 'edit_layout' ] );
25 add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
26 add_filter(
27 'wp_default_editor',
28 function ( $r ) {
29 global $post;
30 if ( ! $post ) {
31 return $r;
32 }
33
34 if ( $post->post_type !== LP_QUESTION_CPT ) {
35 return $r;
36 }
37
38 return 'html';
39 },
40 1000
41 );
42 }
43
44 /**
45 * Layout for edit question.
46 *
47 * @use self::render_edit_question
48 *
49 * @since 4.2.9
50 * @version 1.0.0
51 */
52 public function edit_layout( QuestionPostModel $questionPostModel ) {
53 wp_enqueue_style( 'lp-edit-question' );
54 wp_enqueue_script( 'lp-edit-question' );
55
56 $args = [
57 'id_url' => 'edit-question',
58 'question_id' => $questionPostModel->ID,
59 ];
60 $call_back = array(
61 'class' => self::class,
62 'method' => 'render_edit_question',
63 );
64
65 echo TemplateAJAX::load_content_via_ajax( $args, $call_back );
66 }
67
68 /**
69 * Allow callback for AJAX.
70 * @use self::render_edit_quiz
71 * @use self::render_list_items_not_assign
72 *
73 * @param array $callbacks
74 *
75 * @return array
76 */
77 public function allow_callback( array $callbacks ): array {
78 $callbacks[] = self::class . ':render_edit_question';
79
80 return $callbacks;
81 }
82
83 /**
84 * Render edit question html.
85 *
86 * @throws Exception
87 */
88 public static function render_edit_question( array $data ): stdClass {
89 $question_id = $data['question_id'] ?? 0;
90 $questionPostModel = QuestionPostModel::find( $question_id, true );
91 if ( ! $questionPostModel ) {
92 throw new Exception( __( 'Question not found', 'learnpress' ) );
93 }
94
95 // Check permission
96 $questionPostModel->check_capabilities_create_item_course();
97
98 $content = new stdClass();
99 $content->content = self::instance()->html_edit_question( $questionPostModel );
100
101 return $content;
102 }
103
104 public function html_edit_question( QuestionPostModel $questionPostModel ): string {
105 $section_edit_details = [
106 'wrap' => '<div class="question-edit-details lp-section-toggle">',
107 'header' => sprintf(
108 '<div class="lp-question-data-edit-header lp-trigger-toggle">
109 <label>%s</label>
110 <span class="lp-icon-angle-down"></span><span class="lp-icon-angle-up"></span>
111 </div>',
112 __( 'Option Details', 'learnpress' )
113 ),
114 'collapse' => '<div class="lp-section-collapse">',
115 'point' => AdminEditQuestionTemplate::instance()->html_edit_mark( $questionPostModel ),
116 'hint' => AdminEditQuestionTemplate::instance()->html_edit_hint( $questionPostModel ),
117 'explanation' => AdminEditQuestionTemplate::instance()->html_edit_explanation( $questionPostModel ),
118 'collapse_end' => '</div>',
119 'wrap_end' => '</div>',
120 ];
121
122 $section_edit_main = [
123 'wrap' => sprintf(
124 '<div class="lp-edit-question-wrap lp-question-edit-main" data-question-id="%s">',
125 esc_attr( $questionPostModel->ID )
126 ),
127 'left' => '<div class="lp-question-edit-left">',
128 'answers' => AdminEditQuestionTemplate::instance()->html_edit_question_by_type( $questionPostModel ),
129 'left_end' => '</div>',
130 'details' => Template::combine_components( $section_edit_details ),
131 'wrap_end' => '</div>',
132 ];
133
134 return Template::combine_components( $section_edit_main );
135 }
136
137 /**
138 * HTML for field settings.
139 *
140 * @param array $args
141 *
142 * @return string
143 */
144 public function html_field_settings( array $args = [] ): string {
145 $section = [
146 'wrap' => '<div class="lp-question-field-settings">',
147 'label' => sprintf(
148 '<div class="lp-question-field-settings__label"><label>%s</label></div>',
149 $args['label'] ?? ''
150 ),
151 'input' => $args['input'] ?? '',
152 'description' => sprintf(
153 '<div class="lp-question-field-settings___desc">%s</div>',
154 $args['description'] ?? ''
155 ),
156 'wrap_end' => '</div>',
157 ];
158
159 return Template::combine_components( $section );
160 }
161
162 /**
163 * HTML for edit question mark.
164 *
165 * @param QuestionPostModel $questionPostModel
166 *
167 * @return string
168 */
169 public function html_edit_mark( QuestionPostModel $questionPostModel ): string {
170 $point = $questionPostModel->get_mark();
171
172 $args = [
173 'label' => __( 'Points', 'learnpress' ),
174 'input' => sprintf(
175 '<input type="number" name="lp-question-point-input"
176 class="lp-auto-save-question"
177 data-key-auto-save="question_mark"
178 value="%s" min="0" step="0.01">',
179 esc_attr( $point )
180 ),
181 'description' => __( 'Points for choosing the correct answer.', 'learnpress' ),
182 ];
183
184 return $this->html_field_settings( $args );
185 }
186
187 /**
188 * HTML for edit question hint.
189 *
190 * @param QuestionPostModel $questionPostModel
191 *
192 * @return string
193 */
194 public function html_edit_hint( QuestionPostModel $questionPostModel ): string {
195 $question_id = $questionPostModel->ID;
196 $hint = $questionPostModel->get_hint();
197
198 $editor_id = 'lp-question-hint-' . $question_id;
199
200 $args = [
201 'label' => __( 'Hint', 'learnpress' ),
202 'input' => AdminTemplate::editor_tinymce(
203 $hint,
204 $editor_id,
205 [
206 'editor_height' => 50,
207 'editor_class' => 'lp-editor-tinymce lp-auto-save-question',
208 ]
209 ),
210 'description' => __( 'The instructions for the user to select the right answer. The text will be shown when users click the "Hint" button.', 'learnpress' ),
211 ];
212
213 return $this->html_field_settings( $args );
214 }
215
216 /**
217 * HTML for edit question explanation.
218 *
219 * @param QuestionPostModel|null $questionPostModel
220 *
221 * @return string
222 */
223 public function html_edit_explanation( QuestionPostModel $questionPostModel ): string {
224 $question_id = $questionPostModel->ID;
225 $explanation = $questionPostModel->get_explanation();
226 $editor_id = 'lp-question-explanation-' . $question_id;
227
228 $args = [
229 'label' => __( 'Explanation', 'learnpress' ),
230 'input' => AdminTemplate::editor_tinymce(
231 $explanation,
232 $editor_id,
233 [
234 'editor_height' => 50,
235 'editor_class' => 'lp-editor-tinymce lp-auto-save-question',
236 ]
237 ),
238 'description' => __( 'The explanation will be displayed when students click the "Check Answer" button.', 'learnpress' ),
239 ];
240
241 return $this->html_field_settings( $args );
242 }
243
244 /**
245 * HTML for edit question description.
246 *
247 * @param QuestionPostModel|null $questionPostModel
248 *
249 * @return string
250 */
251 public function html_edit_question_description( QuestionPostModel $questionPostModel ): string {
252 $question_id = $questionPostModel->ID;
253 $question_description = $questionPostModel->get_the_content();
254 $editor_id = 'lp-question-description-' . $question_id;
255
256 $section = [
257 'wrap' => '<div class="lp-question-data-edit">',
258 'header' => sprintf(
259 '<div class="lp-question-data-edit-header">
260 <label>%s</label>
261 </div>',
262 __( 'Description', 'learnpress' )
263 ),
264 'tinymce' => AdminTemplate::editor_tinymce(
265 $question_description,
266 $editor_id,
267 [
268 'editor_class' => 'lp-editor-tinymce lp-auto-save-question',
269 'editor_height' => 50,
270 ]
271 ),
272 'wrap_end' => '</div>',
273 ];
274
275 return Template::combine_components( $section );
276 }
277
278 /**
279 * HTML for edit question by type.
280 *
281 * @param QuestionPostModel|null $questionPostModel
282 *
283 * @return string
284 */
285 public function html_edit_question_by_type( QuestionPostModel $questionPostModel ): string {
286 $html_answers_config = AdminEditQuestionTemplate::instance()->html_answer_option( $questionPostModel );
287
288 $section = [
289 'wrap' => '<div class="lp-question-data-edit lp-question-by-type">',
290 'header' => sprintf(
291 '<div class="lp-question-data-edit-header">
292 <label>%s</label>
293 <span class="lp-question-type-label">%s</span>
294 </div>',
295 __( 'Config Your Answer', 'learnpress' ),
296 esc_html( $questionPostModel->get_type_label() )
297 ),
298 /*'button-save' => sprintf(
299 '<button type="button" class="lp-btn-update-question-answer button lp-hidden">%s</button>',
300 __( 'Save Answer', 'learnpress' )
301 ),*/
302 'answers-config' => $html_answers_config,
303 'wrap_end' => '</div>',
304 ];
305
306 return Template::combine_components( $section );
307 }
308
309 /**
310 * HTML input question title.
311 *
312 * @param string $question_title
313 *
314 * @return string
315 */
316 public function html_input_question_title( string $question_title = '' ): string {
317 return sprintf(
318 '<input class="lp-question-title-input"
319 name="lp-question-title-input"
320 type="text"
321 value="%1$s"
322 data-old="%1$s"
323 placeholder="%2$s"
324 data-mess-empty-title="%3$s">',
325 esc_attr( $question_title ),
326 esc_attr__( 'Update question title', 'learnpress' ),
327 esc_attr__( 'Question title is required', 'learnpress' )
328 );
329 }
330
331 /**
332 * Get html edit question type.
333 *
334 * @param QuestionPostModel $questionPostModel
335 *
336 * @return string
337 */
338 public function html_answer_option( QuestionPostModel $questionPostModel ): string {
339 $type = $questionPostModel->get_type();
340
341 // For addon sorting choice old <= v4.0.1
342 if ( class_exists( 'LP_Addon_Sorting_Choice_Preload' ) && $type === 'sorting_choice' ) {
343 if ( version_compare( LP_ADDON_SORTING_CHOICE_VER, '4.0.1', '<=' ) ) {
344 $type = 'sorting_choice_old';
345 }
346 }
347
348 switch ( $type ) {
349 case 'true_or_false':
350 $html = self::html_answer_type_true_or_false( $questionPostModel );
351 break;
352 case 'single_choice':
353 $html = self::html_answer_type_single_choice( $questionPostModel );
354 break;
355 case 'multi_choice':
356 $html = self::html_answer_type_multiple_choice( $questionPostModel );
357 break;
358 case 'fill_in_blanks':
359 $html = self::html_answer_type_fill_in_blanks( $questionPostModel );
360 break;
361 case 'sorting_choice_old':
362 $html = self::html_answer_type_sorting_choice_old( $questionPostModel );
363 break;
364 case $type:
365 $html = apply_filters( 'learn-press/edit-question/type/html', '', $type, $questionPostModel );
366 break;
367 default:
368 $html = '';
369 break;
370 }
371
372 // For create new question, type is empty.
373 if ( empty( $type ) ) {
374 $html_question_types = sprintf(
375 '<option value="">%s</option>',
376 esc_html__( 'Select question type', 'learnpress' )
377 );
378 $question_types = QuestionPostModel::get_types();
379 foreach ( $question_types as $type => $label ) {
380 $html_question_types .= sprintf(
381 '<option value="%s">%s</option>',
382 esc_attr( $type ),
383 esc_html( $label )
384 );
385 }
386 $html = Template::instance()->nest_elements(
387 [
388 sprintf(
389 '<select class="lp-question-type-new"
390 name="lp-question-type-new" data-mess-empty-type="%s">',
391 esc_attr__( 'Question type is required', 'learnpress' )
392 )
393 => '</select>',
394 ],
395 $html_question_types
396 );
397 $html .= sprintf(
398 '<button class="lp-btn-question-create-type button"
399 type="button">%s %s
400 </button>',
401 '<span class="lp-icon-spinner"></span> ',
402 __( 'Create Question Type', 'learnpress' )
403 );
404 $html = Template::instance()->nest_elements(
405 [ '<div class="lp-question-type-new-wrap">' => '</div>' ],
406 $html
407 );
408 }
409
410 $answers = $questionPostModel->get_answer_option();
411 if ( $questionPostModel->get_type() === 'fill_in_blanks' ) {
412 $answers = $answers[0] ?? [];
413 }
414
415 $section = [
416 'wrap' => sprintf(
417 '<div class="lp-answers-config" data-question-type="%s" data-answers="%s">',
418 esc_attr( $type ),
419 Template::convert_data_to_json( $answers )
420 ),
421 'answers' => $html,
422 'wrap_end' => '</div>',
423 ];
424
425 return Template::combine_components( $section );
426 }
427
428 /**
429 * Get html edit question type true or false.
430 *
431 * @param QuestionPostModel $questionPostModel
432 *
433 * @return string
434 */
435 public function html_answer_type_true_or_false( QuestionPostModel $questionPostModel ): string {
436 $name_radio = 'lp-input-answer-set-true-' . $questionPostModel->ID;
437 $answers = $questionPostModel->get_answer_option();
438
439 $html_answers = '';
440 foreach ( $answers as $answer ) {
441 $questionAnswerModel = new QuestionAnswerModel( $answer );
442
443 $html_answers .= sprintf(
444 '<div class="lp-question-answer-item" data-answer-id="%6$s">
445 <span class="drag lp-icon-drag" title="Drag to reorder section"></span>
446 <span class="lp-icon-spinner"></span>
447 <input type="text" class="%1$s" name="%1$s" value="%2$s" />
448 <input type="radio" class="lp-input-answer-set-true lp-auto-save-question-answer" name="%4$s" %3$s value="%5$s" />
449 </div>',
450 'lp-question-answer-title-input lp-auto-save-question-answer',
451 esc_attr( $questionAnswerModel->title ),
452 $questionAnswerModel->is_true === 'yes' ? 'checked' : '',
453 $name_radio,
454 esc_attr( $questionAnswerModel->is_true ),
455 esc_attr( $questionAnswerModel->question_answer_id )
456 );
457 }
458
459 $section = [
460 'header' => sprintf(
461 '<div class="lp-question-choice-header">
462 <span>%s</span><span>%s</span>
463 </div>',
464 __( 'Answers', 'learnpress' ),
465 __( 'Corrects', 'learnpress' )
466 ),
467 'answers' => $html_answers,
468 ];
469
470 return Template::combine_components( $section );
471 }
472
473 /**
474 * Get html edit single choice.
475 *
476 * @param QuestionPostModel $questionPostModel
477 *
478 * @return string
479 */
480 public function html_answer_type_single_choice( QuestionPostModel $questionPostModel ): string {
481 $name_radio = 'lp-input-answer-set-true-' . $questionPostModel->ID;
482 $answers = $questionPostModel->get_answer_option();
483 $answers[] = null;
484
485 $html_answers = '';
486 foreach ( $answers as $answer ) {
487 $is_clone = true;
488 $title = '';
489 $is_true = 'no';
490 $question_answer_id = 0;
491
492 if ( ! is_null( $answer ) ) {
493 $is_clone = false;
494 $questionAnswerModel = new QuestionAnswerModel( $answer );
495 $title = $questionAnswerModel->title;
496 $is_true = $questionAnswerModel->is_true;
497 $question_answer_id = $questionAnswerModel->question_answer_id;
498 }
499
500 $html_answers .= sprintf(
501 '<div class="lp-question-answer-item %7$s" data-answer-id="%6$s">
502 <span class="drag lp-icon-drag" title="Drag to reorder section"></span>
503 %8$s
504 <input type="text" class="%1$s" name="%1$s" value="%2$s" />
505 <span class="lp-icon-trash-o lp-btn-delete-question-answer"></span>
506 <input type="radio" class="lp-input-answer-set-true lp-auto-save-question-answer" name="%4$s" %3$s value="%5$s" />
507 </div>',
508 'lp-question-answer-title-input lp-auto-save-question-answer',
509 esc_attr( $title ),
510 $is_true === 'yes' ? 'checked' : '',
511 $name_radio,
512 esc_attr( $is_true ),
513 esc_attr( $question_answer_id ),
514 $is_clone ? 'clone lp-hidden' : '',
515 '<span class="lp-icon-spinner"></span>'
516 );
517 }
518
519 $html_answers .= sprintf(
520 '<div class="lp-question-answer-item-add-new">
521 <span class="lp-icon-plus" title="Add answer option"></span>
522 <input type="text" class="%1$s" name="%1$s" value="" data-mess-empty-title="%2$s" />
523 <button type="button" class="button lp-btn-add-question-answer lp-btn-edit-primary">%3$s</button>
524 </div>',
525 'lp-question-answer-title-new-input',
526 esc_attr__( 'Answer title is required', 'learnpress' ),
527 __( 'Add Option', 'learnpress' )
528 );
529
530 $section = [
531 'header' => sprintf(
532 '<div class="lp-question-choice-header">
533 <span>%s</span><span>%s</span>
534 </div>',
535 __( 'Answers', 'learnpress' ),
536 __( 'Corrects', 'learnpress' )
537 ),
538 'answers' => $html_answers,
539 ];
540
541 return Template::combine_components( $section );
542 }
543
544 /**
545 * Get html edit question type multiple choice.
546 *
547 * @param QuestionPostModel $questionPostModel
548 *
549 * @return string
550 */
551 public function html_answer_type_multiple_choice( QuestionPostModel $questionPostModel ): string {
552 $name_checkbox = 'lp-input-answer-set-true-' . $questionPostModel->ID;
553 $answers = $questionPostModel->get_answer_option();
554 $answers[] = null;
555
556 $html_answers = '';
557 foreach ( $answers as $answer ) {
558 $is_clone = true;
559 $title = '';
560 $is_true = 'no';
561 $question_answer_id = 0;
562
563 if ( ! is_null( $answer ) ) {
564 $is_clone = false;
565 $questionAnswerModel = new QuestionAnswerModel( $answer );
566 $title = $questionAnswerModel->title;
567 $is_true = $questionAnswerModel->is_true;
568 $question_answer_id = $questionAnswerModel->question_answer_id;
569 }
570
571 $html_answers .= sprintf(
572 '<div class="lp-question-answer-item %7$s" data-answer-id="%6$s">
573 <span class="drag lp-icon-drag" title="Drag to reorder section"></span>
574 %8$s
575 <input type="text" class="%1$s" name="%1$s" value="%2$s" />
576 <span class="lp-icon-trash-o lp-btn-delete-question-answer"></span>
577 <input type="checkbox" class="lp-input-answer-set-true lp-auto-save-question-answer" name="%4$s" %3$s value="%5$s" />
578 </div>',
579 'lp-question-answer-title-input lp-auto-save-question-answer',
580 esc_attr( $title ),
581 $is_true === 'yes' ? 'checked' : '',
582 $name_checkbox,
583 esc_attr( $is_true ),
584 esc_attr( $question_answer_id ),
585 $is_clone ? 'clone lp-hidden' : '',
586 '<span class="lp-icon-spinner"></span>'
587 );
588 }
589
590 $html_answers .= sprintf(
591 '<div class="lp-question-answer-item-add-new">
592 <span class="lp-icon-plus" title="Add answer option"></span>
593 <input type="text" class="%1$s" name="%1$s" value="" data-mess-empty-title="%2$s" />
594 <button type="button" class="button lp-btn-add-question-answer lp-btn-edit-primary">%3$s</button>
595 </div>',
596 'lp-question-answer-title-new-input',
597 esc_attr__( 'Answer title is required', 'learnpress' ),
598 __( 'Add Option', 'learnpress' )
599 );
600
601 $section = [
602 'header' => sprintf(
603 '<div class="lp-question-choice-header">
604 <span>%s</span><span>%s</span>
605 </div>',
606 __( 'Answers', 'learnpress' ),
607 __( 'Corrects', 'learnpress' )
608 ),
609 'answers' => $html_answers,
610 ];
611
612 return Template::combine_components( $section );
613 }
614
615 /**
616 * Get html edit question type multiple choice.
617 *
618 * @param QuestionPostModel $questionPostModel
619 *
620 * @return string
621 */
622 public function html_answer_type_sorting_choice_old( QuestionPostModel $questionPostModel ): string {
623 $answers = $questionPostModel->get_answer_option();
624 $answers[] = null;
625
626 $html_answers = '';
627 foreach ( $answers as $answer ) {
628 $is_clone = true;
629 $title = '';
630 $question_answer_id = 0;
631
632 if ( ! is_null( $answer ) ) {
633 $is_clone = false;
634 $questionAnswerModel = new QuestionAnswerModel( $answer );
635 $title = $questionAnswerModel->title;
636 $question_answer_id = $questionAnswerModel->question_answer_id;
637 }
638
639 $html_answers .= sprintf(
640 '<div class="lp-question-answer-item %s" data-answer-id="%d">
641 <span class="drag lp-icon-drag" title="Drag to reorder section"></span>
642 <span class="lp-icon-spinner"></span>
643 <input type="text" class="%s" name="%s" value="%s" />
644 <span class="lp-icon-trash-o lp-btn-delete-question-answer"></span>
645 </div>',
646 $is_clone ? 'clone lp-hidden' : '',
647 esc_attr( $question_answer_id ),
648 'lp-question-answer-title-input lp-auto-save-question-answer',
649 'lp-question-answer-title-input',
650 esc_attr( $title )
651 );
652 }
653
654 $html_answers .= sprintf(
655 '<div class="lp-question-answer-item-add-new">
656 <span class="lp-icon-plus" title="Add answer option"></span>
657 <input type="text" class="%1$s" name="%1$s" value="" data-mess-empty-title="%2$s" />
658 <button type="button" class="button lp-btn-add-question-answer lp-btn-edit-primary">%3$s</button>
659 </div>',
660 'lp-question-answer-title-new-input',
661 esc_attr__( 'Answer title is required', 'learnpress' ),
662 __( 'Add Option', 'learnpress' )
663 );
664
665 $section = [
666 'header' => sprintf(
667 '<div class="lp-question-choice-header">
668 <span>%s</span><span>%s</span>
669 </div>',
670 __( 'Answers', 'learnpress' ),
671 __( 'Corrects', 'learnpress' )
672 ),
673 'answers' => $html_answers,
674 ];
675
676 return Template::combine_components( $section );
677 }
678
679 /**
680 * Get html edit question type fill in blanks.
681 *
682 * @param QuestionPostModel $questionPostModel
683 *
684 * @return string
685 */
686 public function html_answer_type_fill_in_blanks( QuestionPostModel $questionPostModel ): string {
687 $questionPostFIBModel = new QuestionPostFIBModel( $questionPostModel );
688 $name = 'lp-question-fib-input-' . $questionPostFIBModel->ID;
689 $answers = $questionPostFIBModel->get_answer_option();
690 $options = [
691 'clone' =>
692 [
693 'fill' => '',
694 'match_case' => 0,
695 'comparison' => 'equal',
696 'id' => 'clone',
697 ],
698 ];
699 /**
700 * @var QuestionAnswerModel[] $answers
701 */
702 $questionAnswerModel = $answers[0] ?? null;
703 if ( $questionAnswerModel instanceof QuestionAnswerModel ) {
704 $meta_data = $questionAnswerModel->get_all_metadata();
705
706 if ( is_array( $meta_data ) ) {
707 $options = array_merge(
708 $meta_data,
709 $options
710 );
711 }
712 }
713
714 $content = '';
715
716 if ( $questionAnswerModel instanceof QuestionAnswerModel ) {
717 $content = $this->convert_content_fib_to_span( $questionAnswerModel->title );
718 }
719
720 $section = [
721 'input' => AdminTemplate::editor_tinymce(
722 $content,
723 $name,
724 [
725 'default_editor' => 'html', // Use HTML editor by default tinymce
726 'tinymce' => true,
727 'quicktags' => true, // Set true to show tab "Code" in editor
728 ]
729 ),
730 'desc' => sprintf(
731 '<div class="lp-question-fib-desc">%s</div>',
732 __( 'Select a word in the passage above and click "Insert a new blank" to make that word a blank for filling.', 'learnpress' )
733 ),
734 'buttons' => '<div class="lp-question-fib-buttons">',
735 'btn-insert-new' => sprintf(
736 '<button type="button" class="lp-btn-fib-insert-blank button"
737 data-default-text="%s"
738 data-mess-inserted="%s"
739 data-mess-require-select-text="%s">%s %s</button>',
740 esc_html__( 'Enter answer correct on here', 'learnpress' ),
741 __( 'This text inserted to blank', 'learnpress' ),
742 __( 'You must select a text or position on Editor to insert new blank.', 'learnpress' ),
743 '<span class="lp-icon-spinner"></span>',
744 __( 'Insert new blank', 'learnpress' )
745 ),
746 'btn-delete-all-blanks' => sprintf(
747 '<button type="button"
748 class="lp-btn-fib-delete-all-blanks button"
749 data-title="%s"
750 data-content="%s"
751 title="%s">%s %s
752 </button>',
753 esc_attr__( 'Are you sure?', 'learnpress' ),
754 esc_html__( 'This action will delete all blanks in the editor, only keep text content.', 'learnpress' ),
755 esc_attr__( 'Delete all blanks on this editor.', 'learnpress' ),
756 '<span class="lp-icon-spinner"></span>',
757 __( 'Delete all blanks', 'learnpress' )
758 ),
759 'btn-save' => sprintf(
760 '<button type="button" class="lp-btn-fib-save-content button lp-btn-edit-primary active">%s %s</button>',
761 '<span class="lp-icon-spinner"></span> ',
762 __( 'Save content', 'learnpress' )
763 ),
764 'btn-clear' => sprintf(
765 '<button type="button"
766 class="lp-btn-fib-clear-all-content button"
767 data-title="%s"
768 data-content="%s"
769 title="%s">%s %s
770 </button>',
771 esc_attr__( 'Are you sure?', 'learnpress' ),
772 esc_html__( 'This action will delete all content in the editor.', 'learnpress' ),
773 esc_attr__( 'Clear all content on this editor.', 'learnpress' ),
774 '<span class="lp-icon-spinner"></span>',
775 __( 'Clear content', 'learnpress' )
776 ),
777 'buttons_end' => '</div>',
778 'options' => $this->html_fib_options( $options ),
779 ];
780
781 return Template::combine_components( $section );
782 }
783
784 public function html_fib_options( $options ): string {
785 if ( empty( $options ) || ! is_array( $options ) ) {
786 return '';
787 }
788
789 $html = '';
790 $i = 1;
791 foreach ( $options as $option ) {
792 $match_case = $option['match_case'] ?? 0;
793 $comparison = $option['comparison'] ?? '';
794 $id = $option['id'] ?? '';
795
796 /*if ( $id === 'clone' ) {
797 $i = 0;
798 }*/
799
800 $section_header = [
801 'wrap' => '<div class="lp-question-fib-option-header">',
802 'number' => sprintf(
803 '<span class="lp-question-fib-option-index">%s.</span>',
804 $i++
805 ),
806 'loading' => '<span class="lp-icon-spinner"></span>',
807 'title' => sprintf(
808 '<input type="text"
809 name="lp-question-fib-option-title-input-%s"
810 value="%s"
811 class="lp-question-fib-option-title-input" />',
812 esc_attr( $id ),
813 esc_html( $option['fill'] ?? '' )
814 ),
815 'btn-delete' => sprintf(
816 '<span
817 class="lp-btn-fib-option-delete lp-icon-trash-o"
818 data-title="%s" data-content="%s">
819 </span>',
820 esc_attr__( 'Are you sure?', 'learnpress' ),
821 esc_html__( 'Delete this blank and keep text', 'learnpress' )
822 ),
823 'toggle' => '<div class="lp-trigger-toggle"><span class="lp-icon-angle-down"></span><span class="lp-icon-angle-up"></span></div>',
824 'wrap_end' => '</div>',
825 ];
826
827 $section_detail = [
828 'wrap' => '<div class="lp-question-fib-option-detail lp-section-collapse">',
829 'match-case' => sprintf(
830 '<label>
831 <input type="checkbox" class="lp-question-fib-option-match-case-input" %s name="%s" data-key="%s" value="1" /> %s
832 </label>',
833 $match_case ? 'checked' : '',
834 esc_attr( 'lp-question-fib-option-match-case-input' . $id ),
835 'match_case',
836 __( 'Match case', 'learnpress' )
837 ),
838 'wrap_match_case' => sprintf(
839 '<div class="lp-question-fib-option-match-case-wrap %s">',
840 $match_case ? '' : 'lp-hidden'
841 ),
842 'separator-label' => sprintf(
843 '<div>%s</div>',
844 __( 'Comparison', 'learnpress' )
845 ),
846 'equal' => sprintf(
847 '<div>
848 <label>
849 <input type="radio"
850 data-key ="comparison"
851 name="lp-question-fib-option-comparison-input-%s"
852 class="lp-question-fib-option-comparison-input" value="equal" %s /> %s
853 </label>
854 <p>%s</p>
855 </div>',
856 esc_attr( $id ),
857 $comparison === 'equal' ? 'checked' : '',
858 __( 'Equal', 'learnpress' ),
859 __( 'Match two words are equality.', 'learnpress' )
860 ),
861 'range' => sprintf(
862 '<div>
863 <label>
864 <input type="radio"
865 data-key ="comparison"
866 name="lp-question-fib-option-comparison-input-%s"
867 class="lp-question-fib-option-comparison-input" value="range" %s /> %s
868 </label>
869 <p>%s</p>
870 </div>',
871 esc_attr( $id ),
872 $comparison === 'range' ? 'checked' : '',
873 __( 'Range', 'learnpress' ),
874 __( 'Match any number in a range. Use 100, 200 to match any value from 100 to 200.', 'learnpress' )
875 ),
876 'any' => sprintf(
877 '<div>
878 <label>
879 <input type="radio"
880 data-key ="comparison"
881 name="lp-question-fib-option-comparison-input-%s"
882 class="lp-question-fib-option-comparison-input" value="any" %s /> %s
883 </label>
884 <p>%s</p>
885 </div>',
886 esc_attr( $id ),
887 $comparison === 'any' ? 'checked' : '',
888 __( 'Any', 'learnpress' ),
889 __( 'Match any value in a set of words. Use fill, blank, or question to match any value in the set.', 'learnpress' )
890 ),
891 'wrap_match_case_end' => '</div>', // End match case wrap
892 'wrap_end' => '</div>',
893 ];
894
895 $section = [
896 'wrap' => sprintf(
897 '<div class="lp-question-fib-blank-option-item %s lp-section-toggle lp-collapse" data-id="%s">',
898 $id === 'clone' ? 'clone lp-hidden' : '',
899 esc_attr( $id )
900 ),
901 'header' => Template::combine_components( $section_header ),
902 'detail' => Template::combine_components( $section_detail ),
903 'wrap_end' => '</div>',
904 ];
905
906 $html .= Template::combine_components( $section );
907 }
908
909 $html = Template::instance()->nest_elements(
910 [ '<div class="lp-question-fib-blank-options">' => '</div>' ],
911 $html
912 );
913
914 return $html;
915 }
916
917 /**
918 * Convert content of fill in blanks shortcode to span elements display on Editor.
919 *
920 * @param string $content
921 *
922 * @return string
923 */
924 public function convert_content_fib_to_span( string $content = '' ): string {
925 $regex_str = get_shortcode_regex( array( 'fib' ) );
926 $pattern = "/{$regex_str}/";
927 preg_match_all(
928 $pattern,
929 $content,
930 $all_shortcode,
931 PREG_SET_ORDER
932 );
933
934 if ( ! empty( $all_shortcode ) ) {
935 foreach ( $all_shortcode as $shortcode ) {
936 $atts = shortcode_parse_atts( $shortcode[0] );
937
938 $fill = $atts['fill'] ?? '';
939 $id = $atts['id'] ?? '';
940 if ( empty( $id ) ) {
941 $ida = explode( '=', str_replace( ']', '', $atts[1] ) );
942 $id = isset( $ida[1] ) ? str_replace( '"', '', $ida[1] ) : '';
943 }
944
945 $new_str = sprintf(
946 '<span class="lp-question-fib-input" data-id="%s">%s</span>',
947 esc_attr( $id ),
948 esc_html( $fill )
949 );
950
951 $content = str_replace( $shortcode[0], $new_str, $content );
952 }
953 }
954
955 return $content;
956 }
957 }
958