Exercises: Fix get content from editor, fix exercise creation

pull/3890/head
Julio Montoya 5 years ago
parent f1bee3ab9f
commit 0650e7c67e
  1. 10
      assets/js/app.js
  2. 3
      assets/vue/main.js
  3. 6
      assets/vue/views/documents/List.vue
  4. 2
      assets/vue/views/documents/Update.vue
  5. 20
      public/main/exercise/exercise.class.php
  6. 27
      public/main/exercise/exercise_report.php
  7. 5
      public/main/exercise/exercise_show.php
  8. 115
      public/main/exercise/exercise_submit.php
  9. 4
      public/main/exercise/fill_blanks.class.php
  10. 2
      public/main/exercise/freeanswer.class.php
  11. 2
      public/main/exercise/live_stats.php
  12. 5
      public/main/exercise/question.class.php
  13. 2
      public/main/exercise/stats.php
  14. 3
      public/main/inc/lib/exercise.lib.php
  15. 6
      public/main/inc/lib/formvalidator/FormValidator.class.php

@ -20,6 +20,16 @@ window.luxon = global.luxon = DateTime;
import 'select2/dist/js/select2.full.min';
import 'select2/dist/css/select2.min.css';
// Gets HTML content from tinymce
window.getContentFromEditor = function (id) {
let content = '';
if (tinymce.get(id)) {
content = tinymce.get(id).getContent();
}
return content;
};
//require('flatpickr');
//import('bootstrap-vue');
import('bootstrap');

@ -123,11 +123,8 @@ const app = createApp(App);
import { Quasar } from 'quasar'
import quasarUserOptions from './quasar-user-options'
// Tinymce
import Editor from './components/Editor';
//window.tinymce = Editor;
// Prime
import PrimeVue from 'primevue/config'

@ -190,9 +190,9 @@
<Column :exportable="false">
<template #body="slotProps">
<div class="flex flex-row gap-2">
<Button label="Show" class="btn btn-primary p-mr-2" @click="showHandler(slotProps.data)" />
<Button v-if="isAuthenticated && isCurrentTeacher" label="Edit" icon="pi pi-pencil" class="btn btn-primary p-mr-2" @click="editHandler(slotProps.data)" />
<Button v-if="isAuthenticated && isCurrentTeacher" label="Delete" icon="pi pi-trash" class="btn btn-danger" @click="confirmDeleteItem(slotProps.data)" />
<Button icon="fa fa-info-circle" class="btn btn-primary " @click="showHandler(slotProps.data)" />
<Button v-if="isAuthenticated && isCurrentTeacher" icon="pi pi-pencil" class="btn btn-primary p-mr-2" @click="editHandler(slotProps.data)" />
<Button v-if="isAuthenticated && isCurrentTeacher" icon="pi pi-trash" class="btn btn-danger" @click="confirmDeleteItem(slotProps.data)" />
</div>
</template>
</Column>

@ -1,4 +1,4 @@
<template>2222
<template>
<div v-if="!isLoading && item && isCurrentTeacher">
<!-- :handle-delete="del"-->
<Toolbar

@ -3404,7 +3404,7 @@ class Exercise
*
* @return string
*/
public function showTimeControlJS($timeLeft)
public function showTimeControlJS($timeLeft, $redirectToUrl = '')
{
$timeLeft = (int) $timeLeft;
$script = 'redirectExerciseToResult();';
@ -10707,14 +10707,14 @@ class Exercise
if (!empty($question) && !empty($answer) && FREE_ANSWER == $answer_type) {
$open_question_list .=
'<tr>'
.'<td width="220" valign="top" bgcolor="#E5EDF8">&nbsp;&nbsp;'.get_lang('Question').'</td>'
.'<td width="473" valign="top" bgcolor="#F3F3F3">'.$question.'</td>'
.'</tr>'
.'<tr>'
.'<td width="220" valign="top" bgcolor="#E5EDF8">&nbsp;&nbsp;'.get_lang('Answer').'</td>'
.'<td valign="top" bgcolor="#F3F3F3">'.$answer.'</td>'
.'</tr>';
'<tr>
<td width="220" valign="top" bgcolor="#E5EDF8">&nbsp;&nbsp;'.get_lang('Question').'</td>
<td width="473" valign="top" bgcolor="#F3F3F3">'.$question.'</td>
</tr>
<tr>
<td width="220" valign="top" bgcolor="#E5EDF8">&nbsp;&nbsp;'.get_lang('Answer').'</td>
<td valign="top" bgcolor="#F3F3F3">'.$answer.'</td>
</tr>';
}
}
@ -10734,7 +10734,7 @@ class Exercise
$msg
);
if ('learnpath' != $origin) {
if ('learnpath' !== $origin) {
$msg .= '<br /><a href="#url#">'.get_lang(
'Click this link to check the answer and/or give feedback'
).'</a>';

@ -546,7 +546,7 @@ if (($is_allowedToEdit || $is_tutor || api_is_coach()) &&
// Security token to protect deletion
$token = Security::get_token();
$actions = Display::div($actions, ['class' => 'actions']);
$actions = Display::toolbarAction('exercise_report', [$actions]);
$extra = '<script>
$(function() {
@ -589,41 +589,30 @@ $form = new FormValidator(
null,
['class' => 'form-vertical']
);
$form->addElement(
'radio',
$form->addRadio(
'export_format',
null,
get_lang('CSV export'),
'csv',
['csv'],
['id' => 'export_format_csv_label']
);
$form->addElement(
'radio',
$form->addRadio(
'export_format',
null,
get_lang('Excel export'),
'xls',
['xls'],
['id' => 'export_format_xls_label']
);
$form->addElement(
'checkbox',
$form->addCheckBox(
'load_extra_data',
null,
get_lang('Load extra user fields data (have to be marked as \'Filter\' to appear).'),
'0',
['id' => 'export_format_xls_label']
);
$form->addElement(
'checkbox',
$form->addCheckBox(
'include_all_users',
null,
get_lang('Include all users'),
'0'
);
$form->addElement(
'checkbox',
$form->addCheckBox(
'only_best_attempts',
null,
get_lang('Only best attempts'),
'0'
);

@ -227,8 +227,9 @@ if ('export' != $action) {
var oHidden = document.createElement("input");
oHidden.type = "hidden";
oHidden.name = "comments_" + ids[k];
if (CKEDITOR.instances[oHidden.name]) {
oHidden.value = CKEDITOR.instances[oHidden.name].getData();
const content = getContentFromEditor(oHidden.name);
if (content) {
oHidden.value = content;
} else {
oHidden.value = $("textarea[name='" + oHidden.name + "']").val();
}

@ -51,7 +51,7 @@ if ('learnpath' === $origin) {
$showGlossary = in_array($glossaryExtraTools, ['true', 'lp', 'exercise_and_lp']);
}
if ($showGlossary) {
$htmlHeadXtra[] = '<script type="text/javascript" src="'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?add_ready=1&'.api_get_cidreq().'"></script>';
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?add_ready=1&'.api_get_cidreq().'"></script>';
$htmlHeadXtra[] = api_get_js('jquery.highlight.js');
}
@ -1241,7 +1241,9 @@ if ($objExercise->review_answers) {
echo '<a
href="../document/download.php?doc_url=%2Faudio%2F'.Security::remove_XSS($exercise_sound).'"
target="_blank">';
echo '<img src="../img/sound.gif" border="0" align="absmiddle" alt=', get_lang('Audio or video file').'" /></a>';
echo '<img
src="../img/sound.gif" border="0"
align="absmiddle" alt=', get_lang('Audio or video file').'" /></a>';
}
// Get number of hotspot questions for javascript validation
$number_of_hotspot_questions = 0;
@ -1353,14 +1355,11 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
}
});
$(".main_question").mouseout(function() {
$(this).removeClass("question_highlight");
});
$(".no_remind_highlight").hide();
$("form#exercise_form").prepend($("#exercise-description"));
$(\'button[name="previous_question_and_save"]\').on("touchstart click", function (e) {
@ -1387,44 +1386,11 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
e.preventDefault();
e.stopPropagation();
var $this = $(this);
var urlExtra = $this.data(\'url\') || null;
var questionId = parseInt($this.data(\'question\')) || 0;
save_now(questionId, "check_answers");
var checkUrl = "'.$checkAnswersUrl.'";
$("#global-modal").attr("data-keyboard", "false");
$("#global-modal").attr("data-backdrop", "static");
$("#global-modal").find(".close").hide();
$("#global-modal .modal-body").load(checkUrl, function() {
$("#global-modal .modal-body").append("<div class=\"btn-group\"></div>");
var continueTest = $("<a>",{
text: "'.addslashes(get_lang('ContinueTest')).'",
title: "'.addslashes(get_lang('ContinueTest')).'",
href: "javascript:void(0);",
click: function(){
$(this).attr("disabled", "disabled");
$("#global-modal").modal("hide");
$("#global-modal .modal-body").html("");
}
}).addClass("btn btn-default").appendTo("#global-modal .modal-body .btn-group");
$("<a>",{
text: "'.addslashes(get_lang('EndTest')).'",
title: "'.addslashes(get_lang('EndTest')).'",
href: "javascript:void(0);",
click: function() {
$(this).attr("disabled", "disabled");
continueTest.attr("disabled", "disabled");
save_now(questionId, urlExtra);
$("#global-modal .modal-body").html("<span style=\"text-align:center\">'.addslashes($loading).addslashes(get_lang('Loading')).'</span>");
}
}).addClass("btn btn-primary").appendTo("#global-modal .modal-body .btn-group");
});
$("#global-modal").modal("show");
});
$(\'button[name="save_now"]\').on(\'touchstart click\', function (e) {
e.preventDefault();
e.stopPropagation();
@ -1494,12 +1460,12 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
// 4. choice for degree of certainty
var my_choiceDc = $(\'*[name*="choiceDegreeCertainty[\'+question_id+\']"]\').serialize();
// Checking CkEditor
// Checking Editor
if (question_id) {
if (CKEDITOR.instances["choice["+question_id+"]"]) {
var ckContent = CKEDITOR.instances["choice["+question_id+"]"].getData();
const content = getContentFromEditor("choice"+question_id);
if (content) {
my_choice = {};
my_choice["choice["+question_id+"]"] = ckContent;
my_choice["choice["+question_id+"]"] = content;
my_choice = $.param(my_choice);
}
}
@ -1523,13 +1489,13 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&a=save_exercise_by_now",
data: dataparam,
success: function(return_value) {
if (return_value == "ok") {
if (return_value.ok) {
$("#save_for_now_"+question_id).html(\''.
Display::return_icon('save.png', get_lang('Saved'), [], ICON_SIZE_SMALL).'\');
} else if (return_value == "error") {
} else if (return_value.error) {
$("#save_for_now_"+question_id).html(\''.
Display::return_icon('error.png', get_lang('Error'), [], ICON_SIZE_SMALL).'\');
} else if (return_value == "one_per_page") {
} else if (return_value.type == "one_per_page") {
var url = "";
if ('.$reminder.' == 1 ) {
url = "exercise_reminder.php?'.$params.'&num='.$current_question.'";
@ -1551,9 +1517,45 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
}
$("#save_for_now_"+question_id).html(\''.
Display::return_icon('save.png', get_lang('Saved'), [], ICON_SIZE_SMALL).'\');
Display::return_icon('save.png', get_lang('Saved'), [], ICON_SIZE_SMALL).'\' + return_value.savedAnswerMessage);
// Show popup
if ("check_answers" === url_extra) {
var button = $(\'button[name="check_answers"]\');
var questionId = parseInt(button.data(\'question\')) || 0;
var urlExtra = button.data(\'url\') || null;
var checkUrl = "'.$checkAnswersUrl.'";
$("#global-modal").attr("data-keyboard", "false");
$("#global-modal").attr("data-backdrop", "static");
$("#global-modal").find(".close").hide();
$("#global-modal .modal-body").load(checkUrl, function() {
$("#global-modal .modal-body").append("<div class=\"btn-group\"></div>");
var continueTest = $("<a>",{
text: "'.addslashes(get_lang('ContinueTest')).'",
title: "'.addslashes(get_lang('ContinueTest')).'",
href: "javascript:void(0);",
click: function(){
$(this).attr("disabled", "disabled");
$("#global-modal").modal("hide");
$("#global-modal .modal-body").html("");
}
}).addClass("btn btn-default").appendTo("#global-modal .modal-body .btn-group");
$("<a>",{
text: "'.addslashes(get_lang('EndTest')).'",
title: "'.addslashes(get_lang('EndTest')).'",
href: "javascript:void(0);",
click: function() {
$(this).attr("disabled", "disabled");
continueTest.attr("disabled", "disabled");
save_now(questionId, urlExtra);
$("#global-modal .modal-body").html("<span style=\"text-align:center\">'.addslashes($loading).addslashes(get_lang('Loading')).'</span>");
}
}).addClass("btn btn-primary").appendTo("#global-modal .modal-body .btn-group");
});
$("#global-modal").modal("show");
return true;
}
// window.quizTimeEnding will be reset in exercise.class.php
@ -1585,11 +1587,11 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
var question_list = ['.implode(',', $questionList).'];
var free_answers = {};
$.each(question_list, function(index, my_question_id) {
// Checking Ckeditor
// Checking editor
if (my_question_id) {
if (CKEDITOR.instances["choice["+my_question_id+"]"]) {
var ckContent = CKEDITOR.instances["choice["+my_question_id+"]"].getData();
free_answers["free_choice["+my_question_id+"]"] = ckContent;
const content = getContentFromEditor("choice"+my_question_id);
if (content) {
free_answers["free_choice["+my_question_id+"]"] = content;
}
}
});
@ -1608,8 +1610,9 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&a=save_exercise_by_now",
data: requestData,
success: function(return_value) {
if (return_value == "ok") {
if (return_value.ok) {
if (validate == "validate") {
$("#save_all_response").html(return_value.savedAnswerMessage);
window.location = "'.$script_php.'?'.$params.'";
} else {
$("#save_all_response").html(\''.Display::return_icon('accept.png').'\');
@ -1803,7 +1806,11 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
Display::button(
'save_now',
get_lang('Save and continue'),
['type' => 'button', 'class' => 'btn btn-info', 'data-question' => $questionId]
[
'type' => 'button',
'class' => 'btn btn-info',
'data-question' => $questionId,
]
),
'<span id="save_for_now_'.$questionId.'"></span>&nbsp;',
];
@ -1846,7 +1853,7 @@ $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
break;
}
}
// end foreach()
if (ALL_ON_ONE_PAGE == $objExercise->type) {
$exerciseActions = $objExercise->show_button(
$questionId,

@ -85,7 +85,7 @@ class FillBlanks extends Question
var field = document.getElementById("answer");
answer = field.value;
} else {
answer = CKEDITOR.instances["answer"].getData();
answer = getContentFromEditor("answer");
}
// disable the save button, if not blanks have been created
@ -220,7 +220,7 @@ class FillBlanks extends Question
var field = document.getElementById("answer");
answer = field.value;
} else {
answer = CKEDITOR.instances["answer"].getData();
answer = getContentFromEditor("answer");
}
var blanks = answer.match(eval(blanksRegexp));

@ -23,7 +23,7 @@ class FreeAnswer extends Question
public function createAnswersForm($form)
{
$form->addElement('text', 'weighting', get_lang('Score'));
$form->addText('weighting', get_lang('Score'));
global $text;
// setting the save button here and not in the question class.php
$form->addButtonSave($text, 'submitQuestion');

@ -110,7 +110,7 @@ $(function() {
$actions = '<a href="exercise_report.php?exerciseId='.(int) ($_GET['exerciseId']).'&'.api_get_cidreq().'">'.
Display::return_icon('back.png', get_lang('Go back to the questions list'), '', ICON_SIZE_MEDIUM).'</a>';
echo $actions = Display::div($actions, ['class' => 'actions']);
$actions = Display::toolbarAction('exercise_report', [$actions]);
echo Display::grid_html('live_stats');

@ -1192,12 +1192,11 @@ abstract class Question
$file = api_get_path(SYS_PATH).$filePart;
$includeFile = '';
if (file_exists($file)) {
$includeFile = '<script type="text/javascript" src="'.api_get_path(WEB_PATH).$filePart.'"></script>';
$includeFile = '<script src="'.api_get_path(WEB_PATH).$filePart.'"></script>';
$language = $iso;
}
echo $includeFile;
echo '<script type="text/javascript" charset="utf-8">
echo '<script>
$(function() {
$(".create_img_link").click(function(e){
e.preventDefault();

@ -343,7 +343,7 @@ $actions .= Display::url(
Display::return_icon('pdf.png', get_lang('ExportToPDF'), [], ICON_SIZE_MEDIUM),
'stats.php?exerciseId='.$exerciseId.'&export_pdf=1&'.api_get_cidreq()
);
$actions = Display::div($actions, ['class' => 'actions']);
$actions = Display::toolbarAction('exercise_report', [$actions]);
$content = $actions.$content;
$tpl->assign('content', $content);
$tpl->display_one_col_template();

@ -194,7 +194,6 @@ class ExerciseLib
$form = new FormValidator('free_choice_'.$questionId);
$config = [
'ToolbarSet' => 'TestFreeAnswer',
'id' => 'choice['.$questionId.']',
];
$form->addHtmlEditor(
'choice['.$questionId.']',
@ -361,7 +360,7 @@ class ExerciseLib
if ('Answers' === $item) {
$properties['colspan'] = 2;
$properties['style'] = 'background-color: #F56B2A; color: #ffffff;';
} elseif ('DegreeOfCertaintyThatMyAnswerIsCorrect' == $item) {
} elseif ('DegreeOfCertaintyThatMyAnswerIsCorrect' === $item) {
$properties['colspan'] = 6;
$properties['style'] = 'background-color: #330066; color: #ffffff;';
}

@ -1075,18 +1075,18 @@ EOT;
$config = [],
$attributes = []
) {
$attributes = [];
$attributes['rows'] = $config['rows'] ?? 15;
$attributes['cols'] = $config['cols'] ?? 80;
$attributes['cols-size'] = $config['cols-size'] ?? [];
$attributes['class'] = $config['class'] ?? [];
$cleanName = str_replace(['[', ']', '#'], '', $name);
$attributes['id'] = $config['id'] ?? uniqid('answer_'.$cleanName, false);
if (empty($attributes['id'])) {
$attributes['id'] = $name;
$attributes['id'] = $cleanName;
}
//$attributes['id'] = $config['id'] ?? 'editor_'.$cleanName;
$this->addElement('html_editor', $name, $label, $attributes, $config);
$this->applyFilter($name, 'trim');
if ($required) {

Loading…
Cancel
Save