Merge branch 'master_MDL-71679-mod_quiz-52' of https://github.com/catalyst/moodle-MDL-70329
This commit is contained in:
@@ -137,7 +137,7 @@ abstract class base extends area_base {
|
||||
}
|
||||
// Default to SITEID if courseid is null, i.e. system or category level questions.
|
||||
$thiscourseid = ($componentinfo->courseid !== null) ? $componentinfo->courseid : SITEID;
|
||||
return new \moodle_url('/question/question.php', ['courseid' => $thiscourseid, 'id' => $questionid]);
|
||||
return new \moodle_url('/question/bank/editquestion/question.php', ['courseid' => $thiscourseid, 'id' => $questionid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -692,23 +692,6 @@ $CFG->admin = 'admin';
|
||||
// $CFG->uninstallclionly = true;
|
||||
//
|
||||
//
|
||||
// Customise question bank display
|
||||
//
|
||||
// The display of Moodle's question bank is made up of a number of columns.
|
||||
// You can customise this display by giving a comma-separated list of column class
|
||||
// names here. Each class must be a subclass of \core_question\bank\column_base.
|
||||
// For example you might define a class like
|
||||
// class \local_qbank_extensions\my_column extends \core_question\bank\column_base
|
||||
// in a local plugin, then add it to the list here. At the time of writing,
|
||||
// the default question bank display is equivalent to the following, but you might like
|
||||
// to check the latest default in question/classes/bank/view.php before setting this.
|
||||
//
|
||||
// $CFG->questionbankcolumns = 'checkbox_column,question_type_column,'
|
||||
// . 'question_name_idnumber_tags_column,edit_menu_column,'
|
||||
// . 'tags_action_column,edit_action_column,copy_action_column,'
|
||||
// . 'preview_action_column,delete_action_column,export_xml_action_column,'
|
||||
// . 'creator_name_column,modifier_name_column';
|
||||
//
|
||||
// Forum summary report
|
||||
//
|
||||
// In order for the forum summary report to calculate word count and character count data, those details are now stored
|
||||
|
||||
@@ -77,11 +77,11 @@ class question_created extends question_base {
|
||||
public function get_url() {
|
||||
if ($this->courseid) {
|
||||
if ($this->contextlevel == CONTEXT_MODULE) {
|
||||
return new \moodle_url('/question/preview.php', ['cmid' => $this->contextinstanceid, 'id' => $this->objectid]);
|
||||
return new \moodle_url('/question/bank/previewquestion/preview.php', ['cmid' => $this->contextinstanceid, 'id' => $this->objectid]);
|
||||
}
|
||||
return new \moodle_url('/question/preview.php', ['courseid' => $this->courseid, 'id' => $this->objectid]);
|
||||
return new \moodle_url('/question/bank/previewquestion/preview.php', ['courseid' => $this->courseid, 'id' => $this->objectid]);
|
||||
}
|
||||
// Lets try editing from the frontpage for contexts above course.
|
||||
return new \moodle_url('/question/preview.php', ['courseid' => SITEID, 'id' => $this->objectid]);
|
||||
return new \moodle_url('/question/bank/previewquestion/preview.php', ['courseid' => SITEID, 'id' => $this->objectid]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
namespace core\plugininfo;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Base class for qbank plugins.
|
||||
*
|
||||
@@ -38,6 +36,9 @@ defined('MOODLE_INTERNAL') || die();
|
||||
class qbank extends base {
|
||||
|
||||
public function is_uninstall_allowed(): bool {
|
||||
if (in_array($this->name, \core_plugin_manager::standard_plugins_list('qbank'))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,17 +35,51 @@ defined('MOODLE_INTERNAL') || die();
|
||||
// Like other files in the db directory this file uses an array.
|
||||
// The old class name is the key, the new class name is the value.
|
||||
// The array must be called $renamedclasses.
|
||||
$renamedclasses = array(
|
||||
$renamedclasses = [
|
||||
// Since Moodle 3.7.
|
||||
'core\\analytics\\target\\course_dropout' => 'core_course\\analytics\\target\\course_dropout',
|
||||
'core\\analytics\\target\\course_competencies' => 'core_course\\analytics\\target\\course_competencies',
|
||||
'core\\analytics\\target\\course_completion' => 'core_course\\analytics\\target\\course_completion',
|
||||
'core\\analytics\\target\\course_gradetopass' => 'core_course\\analytics\\target\\course_gradetopass',
|
||||
'core\\analytics\\target\\no_teaching' => 'core_course\\analytics\\target\\no_teaching',
|
||||
// Since Moodle 4.0.
|
||||
'format_base' => 'core_courseformat\\base',
|
||||
'format_topics_renderer' => 'format_topics\\output\\renderer',
|
||||
'format_section_renderer_base' => 'core_courseformat\\output\\section_renderer',
|
||||
'format_singleactivity_renderer' => 'format_singleactivity\\output\\renderer',
|
||||
'format_site_renderer' => 'core_courseformat\\output\\site_renderer',
|
||||
'format_weeks_renderer' => 'format_weeks\\output\\renderer',
|
||||
);
|
||||
'core_question\\bank\\action_column_base' => 'core_question\\local\\bank\\action_column_base',
|
||||
'core_question\\bank\\checkbox_column' => 'core_question\\local\\bank\\checkbox_column',
|
||||
'core_question\\bank\\column_base' => 'core_question\\local\\bank\\column_base',
|
||||
'core_question\\bank\\edit_menu_column' => 'core_question\\local\\bank\\edit_menu_column',
|
||||
'core_question\\bank\\menu_action_column_base' => 'core_question\\local\\bank\\menu_action_column_base',
|
||||
'core_question\\bank\\menuable_action' => 'core_question\\local\\bank\\menuable_action',
|
||||
'core_question\\bank\\random_question_loader' => 'core_question\\local\\bank\\random_question_loader',
|
||||
'core_question\\bank\\row_base' => 'core_question\\local\\bank\\row_base',
|
||||
'core_question\\bank\\view' => 'core_question\\local\\bank\\view',
|
||||
'core_question\\bank\\copy_action_column' => 'qbank_editquestion\\copy_action_column',
|
||||
'core_question\\bank\\edit_action_column' => 'qbank_editquestion\\edit_action_column',
|
||||
'core_question\\bank\\creator_name_column' => 'qbank_viewcreator\\creator_name_column',
|
||||
'core_question\\bank\\modifier_name_column' => 'qbank_viewcreator\\modifier_name_column',
|
||||
'core_question\\bank\\question_name_column' => 'qbank_viewquestionname\\viewquestionname_column_helper',
|
||||
'core_question\\bank\\question_name_idnumber_tags_column' => 'qbank_viewquestionname\\question_name_idnumber_tags_column',
|
||||
'core_question\\bank\\delete_action_column' => 'qbank_deletequestion\\delete_action_column',
|
||||
'core_question\\bank\\export_xml_action_column' => 'qbank_exporttoxml\\export_xml_action_column',
|
||||
'core_question\\bank\\preview_action_column' => 'qbank_previewquestion\\preview_action_column',
|
||||
'core_question\\bank\\question_text_row' => 'qbank_viewquestiontext\\question_text_row',
|
||||
'core_question\\bank\\question_type_column' => 'qbank_viewquestiontype\\question_type_column',
|
||||
'core_question\\bank\\tags_action_column' => 'qbank_tagquestion\\tags_action_column',
|
||||
'core_question\\output\\qbank_chooser' => 'qbank_editquestion\\qbank_chooser',
|
||||
'core_question\\output\\qbank_chooser_item' => 'qbank_editquestion\\qbank_chooser_item',
|
||||
'question_move_form' => 'qbank_managecategories\\form\\question_move_form',
|
||||
'question_import_form' => 'qbank_importquestions\\form\\question_import_form',
|
||||
'question_category_list' => 'qbank_managecategories\\question_category_list',
|
||||
'question_category_list_item' => 'qbank_managecategories\\question_category_list_item',
|
||||
'question_category_object' => 'qbank_managecategories\\question_category_object',
|
||||
'category_form' => 'qbank_managecategories\\form\\category_form',
|
||||
'export_form' => 'qbank_exportquestions\\form\\export_form',
|
||||
'preview_options_form' => 'qbank_previewquestion\\form\\preview_options_form',
|
||||
'question_preview_options' => 'qbank_previewquestion\\output\\question_preview_options',
|
||||
'core_question\\form\\tags' => '\qbank_tagquestion\\form\\tags_form'
|
||||
];
|
||||
|
||||
+18
-24
@@ -759,14 +759,12 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
|
||||
* @return moodle_url the URL.
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see qbank_previewquestion\helper::question_preview_url()
|
||||
* @todo MDL-71679 uncomment the debug messages after implementing the changes in mod_quiz.
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
function question_preview_url($questionid, $preferredbehaviour = null,
|
||||
$maxmark = null, $displayoptions = null, $variant = null, $context = null) {
|
||||
// Debugging message will be re-added after implementing the changes in mod_quiz.
|
||||
// ...debugging('Function question_preview_url() has been deprecated and moved to qbank_previewquestion plugin,
|
||||
// Please use qbank_previewquestion\helper::question_preview_url() instead.', DEBUG_DEVELOPER);.
|
||||
debugging('Function question_preview_url() has been deprecated and moved to qbank_previewquestion plugin,
|
||||
Please use qbank_previewquestion\helper::question_preview_url() instead.', DEBUG_DEVELOPER);
|
||||
|
||||
return \qbank_previewquestion\helper::question_preview_url($questionid, $preferredbehaviour = null,
|
||||
$maxmark = null, $displayoptions = null, $variant = null, $context = null);
|
||||
@@ -776,13 +774,11 @@ function question_preview_url($questionid, $preferredbehaviour = null,
|
||||
* @return array that can be passed as $params to the {@link popup_action} constructor.
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see qbank_previewquestion\helper::question_preview_popup_params()
|
||||
* @todo MDL-71679 uncomment the debug messages after implementing the changes to mod_quiz.
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
function question_preview_popup_params() {
|
||||
// Debugging message will be re-added after implementing the changes in mod_quiz.
|
||||
// ...debugging('Function question_preview_popup_params() has been deprecated and moved to qbank_previewquestion plugin,
|
||||
// Please use qbank_previewquestion\helper::question_preview_popup_params() instead.', DEBUG_DEVELOPER);.
|
||||
debugging('Function question_preview_popup_params() has been deprecated and moved to qbank_previewquestion plugin,
|
||||
Please use qbank_previewquestion\helper::question_preview_popup_params() instead.', DEBUG_DEVELOPER);
|
||||
|
||||
return \qbank_previewquestion\helper::question_preview_popup_params();
|
||||
}
|
||||
@@ -1656,18 +1652,9 @@ function question_extend_settings_navigation(navigation_node $navigationnode, $c
|
||||
'title' => get_string('questions', 'question'),
|
||||
'url' => new moodle_url($baseurl)
|
||||
],
|
||||
'categories' => [
|
||||
'title' => get_string('categories', 'question'),
|
||||
'url' => new moodle_url('/question/category.php')
|
||||
],
|
||||
'import' => [
|
||||
'title' => get_string('import', 'question'),
|
||||
'url' => new moodle_url('/question/import.php')
|
||||
],
|
||||
'export' => [
|
||||
'title' => get_string('export', 'question'),
|
||||
'url' => new moodle_url('/question/export.php')
|
||||
]
|
||||
'categories' => [],
|
||||
'import' => [],
|
||||
'export' => []
|
||||
];
|
||||
|
||||
$plugins = \core_component::get_plugin_list_with_class('qbank', 'plugin_feature', 'plugin_feature.php');
|
||||
@@ -1692,16 +1679,23 @@ function question_extend_settings_navigation(navigation_node $navigationnode, $c
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mitigate the risk of regression.
|
||||
foreach ($corenavigations as $node => $corenavigation) {
|
||||
if (empty($corenavigation)) {
|
||||
unset($corenavigations[$node]);
|
||||
}
|
||||
}
|
||||
|
||||
// Community/additional plugins have navigation node.
|
||||
$pluginnavigations = [];
|
||||
foreach ($plugins as $componentname => $plugin) {
|
||||
$pluginentrypoin = new $plugin();
|
||||
$pluginentrypointobject = $pluginentrypoin->get_navigation_node();
|
||||
if (!\core\plugininfo\qbank::is_plugin_enabled($componentname)) {
|
||||
unset($corenavigations[$key]);
|
||||
$pluginentrypoint = new $plugin();
|
||||
$pluginentrypointobject = $pluginentrypoint->get_navigation_node();
|
||||
// Don't need the plugins without navigation node.
|
||||
if ($pluginentrypointobject === null || !\core\plugininfo\qbank::is_plugin_enabled($componentname)) {
|
||||
unset($plugins[$componentname]);
|
||||
continue;
|
||||
}
|
||||
$pluginnavigations[$pluginentrypointobject->get_navigation_key()] = [
|
||||
|
||||
@@ -71,6 +71,11 @@ information provided here is intended especially for developers.
|
||||
that wants to listen for the events. Backwards compatibility with existing code using jQuery is preserved.
|
||||
* The function message_send() in messagelib.php now returns false if there is an error sending the message to the
|
||||
message processor (MDL-70046).
|
||||
* Following methods are now deprecated in questionlib and moved to the new qbank_previewquestion plugin:
|
||||
- question_preview_url() is moved to qbank_previewquestion\helper::question_preview_url()
|
||||
- question_preview_popup_params() is moved to \qbank_previewquestion\helper::question_preview_popup_params()
|
||||
Calling these functions in the question will point to the plugin.
|
||||
The deprecated codes are removed from the questionlib for those two methods.
|
||||
* The following functions are deprecated in questionlib.php and moved to the new location.
|
||||
These are marked for final deprecation on 4.4:
|
||||
- question_remove_stale_questions_from_category() =>
|
||||
|
||||
@@ -2107,7 +2107,7 @@ class quiz_attempt {
|
||||
} else {
|
||||
$tagids = quiz_retrieve_slot_tag_ids($this->slots[$slot]->id);
|
||||
|
||||
$randomloader = new \core_question\bank\random_question_loader($qubaids, array());
|
||||
$randomloader = new \core_question\local\bank\random_question_loader($qubaids, array());
|
||||
$newqusetionid = $randomloader->get_next_question_id($questiondata->category,
|
||||
(bool) $questiondata->questiontext, $tagids);
|
||||
if ($newqusetionid === null) {
|
||||
|
||||
@@ -651,7 +651,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
'addonpage' => $page, 'appendqnumstring' => 'addquestion');
|
||||
|
||||
$actions['addaquestion'] = new \action_menu_link_secondary(
|
||||
new \moodle_url('/question/addquestion.php', $params),
|
||||
new \moodle_url('/question/bank/editquestion/addquestion.php', $params),
|
||||
new \pix_icon('t/add', $str->addaquestion, 'moodle', array('class' => 'iconsmall', 'title' => '')),
|
||||
$str->addaquestion, array('class' => 'cm-edit-action addquestion', 'data-action' => 'addquestion')
|
||||
);
|
||||
@@ -722,7 +722,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
|
||||
return html_writer::tag('form', html_writer::div($output),
|
||||
array('class' => 'addnewquestion', 'method' => 'post',
|
||||
'action' => new \moodle_url('/question/addquestion.php')));
|
||||
'action' => new \moodle_url('/question/bank/editquestion/addquestion.php')));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -836,7 +836,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
$image = $this->pix_icon('t/preview', $strpreviewquestion);
|
||||
|
||||
$action = new \popup_action('click', $url, 'questionpreview',
|
||||
question_preview_popup_params());
|
||||
\qbank_previewquestion\helper::question_preview_popup_params());
|
||||
|
||||
return $this->action_link($url, $image . $strpreviewlabel, $action,
|
||||
array('title' => $strpreviewquestion, 'class' => 'preview'));
|
||||
@@ -946,7 +946,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
$output = '';
|
||||
|
||||
$question = $structure->get_question_in_slot($slot);
|
||||
$editurl = new \moodle_url('/question/question.php', array(
|
||||
$editurl = new \moodle_url('/question/bank/editquestion/question.php', array(
|
||||
'returnurl' => $pageurl->out_as_local_url(),
|
||||
'cmid' => $structure->get_cmid(), 'id' => $question->id));
|
||||
|
||||
@@ -1252,9 +1252,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
*/
|
||||
public function question_bank_contents(\mod_quiz\question\bank\custom_view $questionbank, array $pagevars) {
|
||||
|
||||
$qbank = $questionbank->render('editq', $pagevars['qpage'], $pagevars['qperpage'],
|
||||
$pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['qbshowtext'],
|
||||
$pagevars['qtagids']);
|
||||
$qbank = $questionbank->render($pagevars, 'editq');
|
||||
return html_writer::div(html_writer::div($qbank, 'bd'), 'questionbankformforpopup');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2016 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_chooser extends \core_question\output\qbank_chooser {
|
||||
class question_chooser extends \qbank_editquestion\qbank_chooser {
|
||||
}
|
||||
|
||||
@@ -14,30 +14,23 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the add this question to the quiz action.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_quiz\question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the add this question to the quiz action.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @author 2021 Safat Shahin <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class add_action_column extends \core_question\bank\action_column_base {
|
||||
class add_action_column extends \core_question\local\bank\action_column_base {
|
||||
|
||||
/** @var string caches a lang string used repeatedly. */
|
||||
protected $stradd;
|
||||
|
||||
public function init() {
|
||||
public function init(): void {
|
||||
parent::init();
|
||||
$this->stradd = get_string('addtoquiz', 'quiz');
|
||||
}
|
||||
|
||||
@@ -31,18 +31,22 @@ use coding_exception;
|
||||
* Subclass to customise the view of the question bank for the quiz editing screen.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @author 2021 Safat Shahin <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class custom_view extends \core_question\bank\view {
|
||||
/** @var bool whether the quiz this is used by has been attemptd. */
|
||||
class custom_view extends \core_question\local\bank\view {
|
||||
|
||||
/** @var bool $quizhasattempts whether the quiz this is used by has been attemptd. */
|
||||
protected $quizhasattempts = false;
|
||||
/** @var \stdClass the quiz settings. */
|
||||
|
||||
/** @var \stdClass $quiz the quiz settings. */
|
||||
protected $quiz = false;
|
||||
|
||||
/** @var int The maximum displayed length of the category info. */
|
||||
const MAX_TEXT_LENGTH = 200;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Constructor for custom_view.
|
||||
* @param \question_edit_contexts $contexts
|
||||
* @param \moodle_url $pageurl
|
||||
* @param \stdClass $course course settings
|
||||
@@ -54,76 +58,66 @@ class custom_view extends \core_question\bank\view {
|
||||
$this->quiz = $quiz;
|
||||
}
|
||||
|
||||
protected function wanted_columns() {
|
||||
global $CFG;
|
||||
|
||||
if (empty($CFG->quizquestionbankcolumns)) {
|
||||
$quizquestionbankcolumns = array(
|
||||
'add_action_column',
|
||||
'checkbox_column',
|
||||
'question_type_column',
|
||||
'question_name_text_column',
|
||||
'preview_action_column',
|
||||
);
|
||||
} else {
|
||||
$quizquestionbankcolumns = explode(',', $CFG->quizquestionbankcolumns);
|
||||
}
|
||||
protected function wanted_columns(): array {
|
||||
$quizquestionbankcolumns = [
|
||||
'mod_quiz\\question\\bank\\add_action_column',
|
||||
'core_question\\local\\bank\\checkbox_column',
|
||||
'qbank_viewquestiontype\\question_type_column',
|
||||
'mod_quiz\\question\\bank\\question_name_text_column',
|
||||
'qbank_previewquestion\\preview_action_column',
|
||||
];
|
||||
|
||||
foreach ($quizquestionbankcolumns as $fullname) {
|
||||
if (!class_exists($fullname)) {
|
||||
if (class_exists('mod_quiz\\question\\bank\\' . $fullname)) {
|
||||
$fullname = 'mod_quiz\\question\\bank\\' . $fullname;
|
||||
} else if (class_exists('core_question\\bank\\' . $fullname)) {
|
||||
$fullname = 'core_question\\bank\\' . $fullname;
|
||||
} else if (class_exists('question_bank_' . $fullname)) {
|
||||
debugging('Legacy question bank column class question_bank_' .
|
||||
$fullname . ' should be renamed to mod_quiz\\question\\bank\\' .
|
||||
$fullname, DEBUG_DEVELOPER);
|
||||
$fullname = 'question_bank_' . $fullname;
|
||||
} else {
|
||||
throw new coding_exception('Invalid quiz question bank column', $fullname);
|
||||
}
|
||||
throw new coding_exception('Invalid quiz question bank column', $fullname);
|
||||
}
|
||||
$this->requiredcolumns[$fullname] = new $fullname($this);
|
||||
}
|
||||
return $this->requiredcolumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the column heading
|
||||
*
|
||||
* @return string Column name for the heading
|
||||
*/
|
||||
protected function heading_column() {
|
||||
protected function heading_column(): string {
|
||||
return 'mod_quiz\\question\\bank\\question_name_text_column';
|
||||
}
|
||||
|
||||
protected function default_sort() {
|
||||
return array(
|
||||
'core_question\\bank\\question_type_column' => 1,
|
||||
protected function default_sort(): array {
|
||||
return [
|
||||
'qbank_viewquestiontype\\question_type_column' => 1,
|
||||
'mod_quiz\\question\\bank\\question_name_text_column' => 1,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the question bank display know whether the quiz has been attempted,
|
||||
* hence whether some bits of UI, like the add this question to the quiz icon,
|
||||
* should be displayed.
|
||||
*
|
||||
* @param bool $quizhasattempts whether the quiz has attempts.
|
||||
*/
|
||||
public function set_quiz_has_attempts($quizhasattempts) {
|
||||
public function set_quiz_has_attempts($quizhasattempts): void {
|
||||
$this->quizhasattempts = $quizhasattempts;
|
||||
if ($quizhasattempts && isset($this->visiblecolumns['addtoquizaction'])) {
|
||||
unset($this->visiblecolumns['addtoquizaction']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Question preview url.
|
||||
*
|
||||
* @param \stdClass $question
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function preview_question_url($question) {
|
||||
return quiz_question_preview_url($this->quiz, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of add to quiz.
|
||||
*
|
||||
* @param $questionid
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function add_to_quiz_url($questionid) {
|
||||
global $CFG;
|
||||
$params = $this->baseurl->params();
|
||||
$params['addquestion'] = $questionid;
|
||||
$params['sesskey'] = sesskey();
|
||||
@@ -136,34 +130,26 @@ class custom_view extends \core_question\bank\view {
|
||||
* Note that you can only output this rendered result once per page, as
|
||||
* it contains IDs which must be unique.
|
||||
*
|
||||
* @param array $pagevars
|
||||
* @param string $tabname
|
||||
* @return string HTML code for the form
|
||||
*/
|
||||
public function render($tabname, $page, $perpage, $cat, $recurse, $showhidden,
|
||||
$showquestiontext, $tagids = []) {
|
||||
public function render($pagevars, $tabname): string {
|
||||
ob_start();
|
||||
$this->display($tabname, $page, $perpage, $cat, $recurse, $showhidden, $showquestiontext, $tagids);
|
||||
$this->display($pagevars, $tabname);
|
||||
$out = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the controls at the bottom of the list of questions.
|
||||
* @param int $totalnumber Total number of questions that might be shown (if it was not for paging).
|
||||
* @param bool $recurse Whether to include subcategories.
|
||||
* @param \stdClass $category The question_category row from the database.
|
||||
* @param \context $catcontext The context of the category being displayed.
|
||||
* @param array $addcontexts contexts where the user is allowed to add new questions.
|
||||
*/
|
||||
protected function display_bottom_controls($totalnumber, $recurse, $category, \context $catcontext, array $addcontexts) {
|
||||
protected function display_bottom_controls($totalnumber, $recurse, $category, \context $catcontext, array $addcontexts): void {
|
||||
$cmoptions = new \stdClass();
|
||||
$cmoptions->hasattempts = !empty($this->quizhasattempts);
|
||||
|
||||
$canuseall = has_capability('moodle/question:useall', $catcontext);
|
||||
|
||||
echo '<div class="modulespecificbuttonscontainer">';
|
||||
echo \html_writer::start_tag('div', ['class' => 'modulespecificbuttonscontainer']);
|
||||
if ($canuseall) {
|
||||
|
||||
// Add selected questions to the quiz.
|
||||
$params = array(
|
||||
'type' => 'submit',
|
||||
@@ -177,75 +163,19 @@ class custom_view extends \core_question\bank\view {
|
||||
);
|
||||
echo \html_writer::empty_tag('input', $params);
|
||||
}
|
||||
echo "</div>\n";
|
||||
echo \html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a form to choose categories.
|
||||
* @param string $categoryandcontext 'categoryID,contextID'.
|
||||
* @deprecated since Moodle 2.6 MDL-40313.
|
||||
* @see \core_question\bank\search\category_condition
|
||||
* @todo MDL-41978 This will be deleted in Moodle 2.8
|
||||
*/
|
||||
protected function print_choose_category_message($categoryandcontext) {
|
||||
global $OUTPUT;
|
||||
debugging('print_choose_category_message() is deprecated, ' .
|
||||
'please use \core_question\bank\search\category_condition instead.', DEBUG_DEVELOPER);
|
||||
echo $OUTPUT->box_start('generalbox questionbank');
|
||||
$this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'),
|
||||
$this->baseurl, $categoryandcontext);
|
||||
echo "<p style=\"text-align:center;\"><b>";
|
||||
print_string('selectcategoryabove', 'question');
|
||||
echo "</b></p>";
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
protected function display_options_form($showquestiontext, $scriptpath = '/mod/quiz/edit.php',
|
||||
$showtextoption = false) {
|
||||
// Overridden just to change the default values of the arguments.
|
||||
parent::display_options_form($showquestiontext, $scriptpath, $showtextoption);
|
||||
}
|
||||
|
||||
protected function print_category_info($category) {
|
||||
$formatoptions = new \stdClass();
|
||||
$formatoptions->noclean = true;
|
||||
$strcategory = get_string('category', 'quiz');
|
||||
echo '<div class="categoryinfo"><div class="categorynamefieldcontainer">' .
|
||||
$strcategory;
|
||||
echo ': <span class="categorynamefield">';
|
||||
echo shorten_text(strip_tags(format_string($category->name)), 60);
|
||||
echo '</span></div><div class="categoryinfofieldcontainer">' .
|
||||
'<span class="categoryinfofield">';
|
||||
echo shorten_text(strip_tags(format_text($category->info, $category->infoformat,
|
||||
$formatoptions, $this->course->id)), 200);
|
||||
echo '</span></div></div>';
|
||||
}
|
||||
|
||||
protected function display_options($recurse, $showhidden, $showquestiontext) {
|
||||
debugging('display_options() is deprecated, see display_options_form() instead.', DEBUG_DEVELOPER);
|
||||
echo '<form method="get" action="edit.php" id="displayoptions">';
|
||||
echo "<fieldset class='invisiblefieldset'>";
|
||||
echo \html_writer::input_hidden_params($this->baseurl,
|
||||
array('recurse', 'showhidden', 'qbshowtext'));
|
||||
$this->display_category_form_checkbox('recurse', $recurse,
|
||||
get_string('includesubcategories', 'question'));
|
||||
$this->display_category_form_checkbox('showhidden', $showhidden,
|
||||
get_string('showhidden', 'question'));
|
||||
echo '<noscript><div class="centerpara"><input type="submit" value="' .
|
||||
get_string('go') . '" />';
|
||||
echo '</div></noscript></fieldset></form>';
|
||||
}
|
||||
|
||||
protected function create_new_question_form($category, $canadd) {
|
||||
protected function create_new_question_form($category, $canadd): void {
|
||||
// Don't display this.
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the base implementation in \core_question\bank\view
|
||||
* Override the base implementation in \core_question\local\bank\view
|
||||
* because we don't want to print the headers in the fragment
|
||||
* for the modal.
|
||||
*/
|
||||
protected function display_question_bank_header() {
|
||||
protected function display_question_bank_header(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,7 +186,7 @@ class custom_view extends \core_question\bank\view {
|
||||
* Unfortunately the best we can do is to look at the URL for
|
||||
* those parameters (only marginally better really).
|
||||
*/
|
||||
protected function init_sort_from_params() {
|
||||
protected function init_sort_from_params(): void {
|
||||
$this->sort = [];
|
||||
for ($i = 1; $i <= self::MAX_SORTS; $i++) {
|
||||
if (!$sort = $this->baseurl->param('qbs' . $i)) {
|
||||
@@ -272,8 +202,8 @@ class custom_view extends \core_question\bank\view {
|
||||
}
|
||||
}
|
||||
// Deal with subsorts.
|
||||
list($colname, $subsort) = $this->parse_subsort($sort);
|
||||
$this->requiredcolumns[$colname] = $this->get_column_type($colname);
|
||||
list($colname) = $this->parse_subsort($sort);
|
||||
$this->get_column_type($colname);
|
||||
$this->sort[$sort] = $order;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,39 +14,35 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_quiz\question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @author 2021 Safat Shahin <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class question_name_column extends \core_question\bank\column_base {
|
||||
class question_name_column extends \core_question\local\bank\column_base {
|
||||
|
||||
/**
|
||||
* @var null $checkboxespresent
|
||||
*/
|
||||
protected $checkboxespresent = null;
|
||||
|
||||
public function get_name() {
|
||||
public function get_name(): string {
|
||||
return 'questionname';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
protected function get_title(): string {
|
||||
return get_string('question');
|
||||
}
|
||||
|
||||
protected function label_for($question) {
|
||||
protected function label_for($question): string {
|
||||
if (is_null($this->checkboxespresent)) {
|
||||
$this->checkboxespresent = $this->qbank->has_column('core_question\bank\checkbox_column');
|
||||
$this->checkboxespresent = $this->qbank->has_column('core_question\local\bank\checkbox_column');
|
||||
}
|
||||
if ($this->checkboxespresent) {
|
||||
return 'checkq' . $question->id;
|
||||
@@ -55,19 +51,19 @@ class question_name_column extends \core_question\bank\column_base {
|
||||
}
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
protected function display_content($question, $rowclasses): void {
|
||||
$labelfor = $this->label_for($question);
|
||||
if ($labelfor) {
|
||||
echo '<label for="' . $labelfor . '">';
|
||||
echo \html_writer::start_tag('label', ['for' => $labelfor]);
|
||||
}
|
||||
echo format_string($question->name);
|
||||
if ($labelfor) {
|
||||
echo '</label>';
|
||||
echo \html_writer::end_tag('label');
|
||||
}
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
return array('q.id', 'q.name');
|
||||
public function get_required_fields(): array {
|
||||
return ['q.id', 'q.name'];
|
||||
}
|
||||
|
||||
public function is_sortable() {
|
||||
|
||||
@@ -14,44 +14,37 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name followed by the start of the question text.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category question
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_quiz\question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name followed by the start of the question text.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @author 2021 Safat Shahin <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_name_text_column extends question_name_column {
|
||||
public function get_name() {
|
||||
|
||||
public function get_name(): string {
|
||||
return 'questionnametext';
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
echo '<div>';
|
||||
protected function display_content($question, $rowclasses): void {
|
||||
echo \html_writer::start_tag('div');
|
||||
$labelfor = $this->label_for($question);
|
||||
if ($labelfor) {
|
||||
echo '<label for="' . $labelfor . '">';
|
||||
echo \html_writer::start_tag('label', ['for' => $labelfor]);
|
||||
}
|
||||
echo quiz_question_tostring($question, false, true, true, $question->tags);
|
||||
if ($labelfor) {
|
||||
echo '</label>';
|
||||
echo \html_writer::end_tag('label');
|
||||
}
|
||||
echo '</div>';
|
||||
echo \html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
public function get_required_fields(): array {
|
||||
$fields = parent::get_required_fields();
|
||||
$fields[] = 'q.questiontext';
|
||||
$fields[] = 'q.questiontextformat';
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
// Get the question bank view.
|
||||
$questionbank = new mod_quiz\question\bank\custom_view($contexts, $thispageurl, $course, $cm, $quiz);
|
||||
$questionbank->set_quiz_has_attempts($quizhasattempts);
|
||||
$questionbank->process_actions($thispageurl, $cm);
|
||||
$questionbank->process_actions();
|
||||
|
||||
// End of process commands =====================================================.
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $time
|
||||
$usedquestionids[$question->id] = 1;
|
||||
}
|
||||
}
|
||||
$randomloader = new \core_question\bank\random_question_loader($qubaids, $usedquestionids);
|
||||
$randomloader = new \core_question\local\bank\random_question_loader($qubaids, $usedquestionids);
|
||||
|
||||
foreach ($quizobj->get_questions() as $questiondata) {
|
||||
$slot += 1;
|
||||
@@ -1401,7 +1401,7 @@ function quiz_question_edit_button($cmid, $question, $returnurl, $contentafteric
|
||||
$returnurl = $returnurl->out_as_local_url(false);
|
||||
}
|
||||
$questionparams = array('returnurl' => $returnurl, 'cmid' => $cmid, 'id' => $question->id);
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php", $questionparams);
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/bank/editquestion/question.php", $questionparams);
|
||||
return '<a title="' . $action . '" href="' . $questionurl->out() . '" class="questioneditbutton">' .
|
||||
$OUTPUT->pix_icon($icon, $action) . $contentaftericon .
|
||||
'</a>';
|
||||
@@ -1429,7 +1429,7 @@ function quiz_question_preview_url($quiz, $question, $variant = null) {
|
||||
}
|
||||
|
||||
// Work out the correcte preview URL.
|
||||
return question_preview_url($question->id, $quiz->preferredbehaviour,
|
||||
return \qbank_previewquestion\helper::question_preview_url($question->id, $quiz->preferredbehaviour,
|
||||
$maxmark, $displayoptions, $variant);
|
||||
}
|
||||
|
||||
|
||||
@@ -429,8 +429,7 @@ class behat_mod_quiz extends behat_question_base {
|
||||
*/
|
||||
public function i_should_see_on_quiz_page($questionname, $pagenumber) {
|
||||
$xpath = "//li[contains(., '" . $this->escape($questionname) .
|
||||
"')][./preceding-sibling::li[contains(@class, 'pagenumber')][1][contains(., 'Page " .
|
||||
$pagenumber . "')]]";
|
||||
"')][./preceding-sibling::li[contains(., 'Page " . $pagenumber . "')]]";
|
||||
|
||||
$this->execute('behat_general::should_exist', array($xpath, 'xpath_element'));
|
||||
}
|
||||
@@ -457,8 +456,8 @@ class behat_mod_quiz extends behat_question_base {
|
||||
* @param string $secondquestionname the name of the question that should come immediately after it in order.
|
||||
*/
|
||||
public function i_should_see_before_on_the_edit_quiz_page($firstquestionname, $secondquestionname) {
|
||||
$xpath = "//li[contains(@class, ' slot ') and contains(., '" . $this->escape($firstquestionname) .
|
||||
"')]/following-sibling::li[contains(@class, ' slot ')][1]" .
|
||||
$xpath = "//li[contains(., '" . $this->escape($firstquestionname) .
|
||||
"')]/following-sibling::li" .
|
||||
"[contains(., '" . $this->escape($secondquestionname) . "')]";
|
||||
|
||||
$this->execute('behat_general::should_exist', array($xpath, 'xpath_element'));
|
||||
|
||||
@@ -79,7 +79,7 @@ Feature: Adding questions to a quiz from the question bank
|
||||
Then I should see "question 21 name" in the "categoryquestions" "table"
|
||||
And I should see "question 22 name" in the "categoryquestions" "table"
|
||||
And I should not see "question 01 name" in the "categoryquestions" "table"
|
||||
And I click on "Show all 22" "link" in the ".pagingbottom" "css_element"
|
||||
And I click on "Show all 22" "link" in the ".question-showall-text" "css_element"
|
||||
And I should see "question 01 name" in the "categoryquestions" "table"
|
||||
And I should see "question 22 name" in the "categoryquestions" "table"
|
||||
|
||||
|
||||
@@ -63,7 +63,15 @@ class quiz_question_bank_view_testcase extends advanced_testcase {
|
||||
// Generate the view.
|
||||
$view = new mod_quiz\question\bank\custom_view($contexts, new moodle_url('/'), $course, $cm, $quiz);
|
||||
ob_start();
|
||||
$view->display('editq', 0, 20, $cat->id . ',' . $cat->contextid, false, false, false);
|
||||
$pagevars = [
|
||||
'qpage' => 0,
|
||||
'qperpage' => 20,
|
||||
'cat' => $cat->id . ',' . $context->id,
|
||||
'recurse' => false,
|
||||
'showhidden' => false,
|
||||
'qbshowtext' => false
|
||||
];
|
||||
$view->display($pagevars, 'editq');
|
||||
$html = ob_get_clean();
|
||||
|
||||
// Verify the output includes the expected question.
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Shows a screen where the user can choose a question type, before being
|
||||
* redirected to question.php
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once(__DIR__ . '/editlib.php');
|
||||
|
||||
// Read URL parameters.
|
||||
$categoryid = required_param('category', PARAM_INT);
|
||||
$cmid = optional_param('cmid', 0, PARAM_INT);
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT);
|
||||
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
|
||||
$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
|
||||
$validationerror = optional_param('validationerror', false, PARAM_BOOL);
|
||||
|
||||
// Place to accumulate hidden params for the form we will print.
|
||||
$hiddenparams = array('category' => $categoryid);
|
||||
|
||||
// Validate params.
|
||||
if (!$category = $DB->get_record('question_categories', array('id' => $categoryid))) {
|
||||
print_error('categorydoesnotexist', 'question', $returnurl);
|
||||
}
|
||||
|
||||
if ($cmid) {
|
||||
list($module, $cm) = get_module_from_cmid($cmid);
|
||||
require_login($cm->course, false, $cm);
|
||||
$thiscontext = context_module::instance($cmid);
|
||||
$hiddenparams['cmid'] = $cmid;
|
||||
} else if ($courseid) {
|
||||
require_login($courseid, false);
|
||||
$thiscontext = context_course::instance($courseid);
|
||||
$module = null;
|
||||
$cm = null;
|
||||
$hiddenparams['courseid'] = $courseid;
|
||||
} else {
|
||||
print_error('missingcourseorcmid', 'question');
|
||||
}
|
||||
|
||||
// Check permissions.
|
||||
$categorycontext = context::instance_by_id($category->contextid);
|
||||
require_capability('moodle/question:add', $categorycontext);
|
||||
|
||||
// Ensure other optional params get passed on to question.php.
|
||||
if (!empty($returnurl)) {
|
||||
$hiddenparams['returnurl'] = $returnurl;
|
||||
}
|
||||
if (!empty($appendqnumstring)) {
|
||||
$hiddenparams['appendqnumstring'] = $appendqnumstring;
|
||||
}
|
||||
|
||||
$PAGE->set_url('/question/addquestion.php', $hiddenparams);
|
||||
if ($cmid) {
|
||||
$questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
|
||||
} else {
|
||||
$questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
|
||||
}
|
||||
navigation_node::override_active_url($questionbankurl);
|
||||
|
||||
$chooseqtype = get_string('chooseqtypetoadd', 'question');
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
$PAGE->navbar->add($chooseqtype);
|
||||
$PAGE->set_title($chooseqtype);
|
||||
|
||||
// Display a form to choose the question type.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->notification(get_string('youmustselectaqtype', 'question'));
|
||||
echo $OUTPUT->box_start('generalbox boxwidthnormal boxaligncenter', 'chooseqtypebox');
|
||||
echo print_choose_qtype_to_add_form($hiddenparams, null, false);
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
+2
-601
@@ -21,608 +21,9 @@
|
||||
* @subpackage questionbank
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// number of categories to display on page
|
||||
define('QUESTION_PAGE_LENGTH', 25);
|
||||
|
||||
require_once($CFG->libdir . '/listlib.php');
|
||||
require_once($CFG->dirroot . '/question/category_form.php');
|
||||
require_once($CFG->dirroot . '/question/move_form.php');
|
||||
|
||||
|
||||
/**
|
||||
* Class representing a list of question categories
|
||||
*
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71585
|
||||
* @see \qbank_managecategories\question_category_list
|
||||
* @todo deprecation on MDL-71679
|
||||
*/
|
||||
class question_category_list extends moodle_list {
|
||||
public $table = "question_categories";
|
||||
public $listitemclassname = 'question_category_list_item';
|
||||
/**
|
||||
* @var reference to list displayed below this one.
|
||||
*/
|
||||
public $nextlist = null;
|
||||
/**
|
||||
* @var reference to list displayed above this one.
|
||||
*/
|
||||
public $lastlist = null;
|
||||
|
||||
public $context = null;
|
||||
public $sortby = 'parent, sortorder, name';
|
||||
|
||||
public function __construct($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $context = null){
|
||||
debugging('Class question_category_list in \core_question\category_class is deprecated,
|
||||
please use qbank_managecategories\question_category_list instead.', DEBUG_DEVELOPER);
|
||||
|
||||
parent::__construct('ul', '', $editable, $pageurl, $page, 'cpage', $itemsperpage);
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function get_records() {
|
||||
$this->records = get_categories_for_contexts($this->context->id, $this->sortby);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest category id that the $item can have as its parent.
|
||||
* Note: question categories cannot go higher than the TOP category.
|
||||
*
|
||||
* @param list_item $item The item which its top level parent is going to be returned.
|
||||
* @return int
|
||||
*/
|
||||
public function get_top_level_parent_id($item) {
|
||||
// Put the item at the highest level it can go.
|
||||
$topcategory = question_get_top_category($item->item->contextid, true);
|
||||
return $topcategory->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* process any actions.
|
||||
*
|
||||
* @param integer $left id of item to move left
|
||||
* @param integer $right id of item to move right
|
||||
* @param integer $moveup id of item to move up
|
||||
* @param integer $movedown id of item to move down
|
||||
* @return void
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function process_actions($left, $right, $moveup, $movedown) {
|
||||
$category = new stdClass();
|
||||
if (!empty($left)) {
|
||||
// Moved Left (In to another category).
|
||||
$category->id = $left;
|
||||
$category->contextid = $this->context->id;
|
||||
$event = \core\event\question_category_moved::create_from_question_category_instance($category);
|
||||
$event->trigger();
|
||||
} else if (!empty($right)) {
|
||||
// Moved Right (Out of the current category).
|
||||
$category->id = $right;
|
||||
$category->contextid = $this->context->id;
|
||||
$event = \core\event\question_category_moved::create_from_question_category_instance($category);
|
||||
$event->trigger();
|
||||
}
|
||||
parent::process_actions($left, $right, $moveup, $movedown);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An item in a list of question categories.
|
||||
*
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71585
|
||||
* @see \qbank_managecategories\question_category_list_item
|
||||
* @todo deprecation on MDL-71679
|
||||
*/
|
||||
class question_category_list_item extends list_item {
|
||||
public function set_icon_html($first, $last, $lastitem){
|
||||
debugging('Function set_icon_html() in \core_question\category_class is deprecated,
|
||||
please use qbank_managecategories\question_category_list_item::set_icon_html() instead.', DEBUG_DEVELOPER);
|
||||
global $CFG;
|
||||
$category = $this->item;
|
||||
$url = new moodle_url('/question/category.php', ($this->parentlist->pageurl->params() + array('edit'=>$category->id)));
|
||||
$this->icons['edit']= $this->image_icon(get_string('editthiscategory', 'question'), $url, 'edit');
|
||||
parent::set_icon_html($first, $last, $lastitem);
|
||||
$toplevel = ($this->parentlist->parentitem === null);//this is a top level item
|
||||
if (($this->parentlist->nextlist !== null) && $last && $toplevel && (count($this->parentlist->items)>1)){
|
||||
$url = new moodle_url($this->parentlist->pageurl, array('movedowncontext'=>$this->id, 'tocontext'=>$this->parentlist->nextlist->context->id, 'sesskey'=>sesskey()));
|
||||
$this->icons['down'] = $this->image_icon(
|
||||
get_string('shareincontext', 'question', $this->parentlist->nextlist->context->get_context_name()), $url, 'down');
|
||||
}
|
||||
if (($this->parentlist->lastlist !== null) && $first && $toplevel && (count($this->parentlist->items)>1)){
|
||||
$url = new moodle_url($this->parentlist->pageurl, array('moveupcontext'=>$this->id, 'tocontext'=>$this->parentlist->lastlist->context->id, 'sesskey'=>sesskey()));
|
||||
$this->icons['up'] = $this->image_icon(
|
||||
get_string('shareincontext', 'question', $this->parentlist->lastlist->context->get_context_name()), $url, 'up');
|
||||
}
|
||||
}
|
||||
|
||||
public function item_html($extraargs = array()){
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
debugging('Function item_html() in \core_question\category_class is deprecated,
|
||||
please use qbank_managecategories\question_category_list_item::item_html() instead.', DEBUG_DEVELOPER);
|
||||
$str = $extraargs['str'];
|
||||
$category = $this->item;
|
||||
|
||||
$editqestions = get_string('editquestions', 'question');
|
||||
|
||||
// Each section adds html to be displayed as part of this list item.
|
||||
$nodeparent = $PAGE->settingsnav->find('questionbank', \navigation_node::TYPE_CONTAINER);
|
||||
$questionbankurl = new moodle_url($nodeparent->action, $this->parentlist->pageurl->params());
|
||||
$questionbankurl->param('cat', $category->id . ',' . $category->contextid);
|
||||
$item = '';
|
||||
$text = format_string($category->name, true, ['context' => $this->parentlist->context]);
|
||||
if ($category->idnumber !== null && $category->idnumber !== '') {
|
||||
$text .= ' ' . html_writer::span(
|
||||
html_writer::span(get_string('idnumber', 'question'), 'accesshide') .
|
||||
' ' . $category->idnumber, 'badge badge-primary');
|
||||
}
|
||||
$text .= ' (' . $category->questioncount . ')';
|
||||
$item .= html_writer::tag('b', html_writer::link($questionbankurl, $text,
|
||||
['title' => $editqestions]) . ' ');
|
||||
$item .= format_text($category->info, $category->infoformat,
|
||||
array('context' => $this->parentlist->context, 'noclean' => true));
|
||||
|
||||
// Don't allow delete if this is the top category, or the last editable category in this context.
|
||||
if ($category->parent && !question_is_only_child_of_top_category_in_context($category->id)) {
|
||||
$deleteurl = new moodle_url($this->parentlist->pageurl, array('delete' => $this->id, 'sesskey' => sesskey()));
|
||||
$item .= html_writer::link($deleteurl,
|
||||
$OUTPUT->pix_icon('t/delete', $str->delete),
|
||||
array('title' => $str->delete));
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class for performing operations on question categories.
|
||||
*
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71585
|
||||
* @see \qbank_managecategories\question_category_object
|
||||
* @todo deprecation on MDL-71679
|
||||
*/
|
||||
class question_category_object {
|
||||
|
||||
/**
|
||||
* @var array common language strings.
|
||||
*/
|
||||
public $str;
|
||||
|
||||
/**
|
||||
* @var array nested lists to display categories.
|
||||
*/
|
||||
public $editlists = array();
|
||||
public $tab;
|
||||
public $tabsize = 3;
|
||||
|
||||
/**
|
||||
* @var moodle_url Object representing url for this page
|
||||
*/
|
||||
public $pageurl;
|
||||
|
||||
/**
|
||||
* @var question_category_edit_form Object representing form for adding / editing categories.
|
||||
*/
|
||||
public $catform;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $page page number
|
||||
* @param moodle_url $pageurl base URL of the display categories page. Used for redirects.
|
||||
* @param context[] $contexts contexts where the current user can edit categories.
|
||||
* @param int $currentcat id of the category to be edited. 0 if none.
|
||||
* @param int|null $defaultcategory id of the current category. null if none.
|
||||
* @param int $todelete id of the category to delete. 0 if none.
|
||||
* @param context[] $addcontexts contexts where the current user can add questions.
|
||||
*/
|
||||
public function __construct($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
|
||||
debugging('Class question_category_list in \core_question\category_class is deprecated,
|
||||
please use qbank_managecategories\question_category_object instead.', DEBUG_DEVELOPER);
|
||||
|
||||
$this->tab = str_repeat(' ', $this->tabsize);
|
||||
|
||||
$this->str = new stdClass();
|
||||
$this->str->course = get_string('course');
|
||||
$this->str->category = get_string('category', 'question');
|
||||
$this->str->categoryinfo = get_string('categoryinfo', 'question');
|
||||
$this->str->questions = get_string('questions', 'question');
|
||||
$this->str->add = get_string('add');
|
||||
$this->str->delete = get_string('delete');
|
||||
$this->str->moveup = get_string('moveup');
|
||||
$this->str->movedown = get_string('movedown');
|
||||
$this->str->edit = get_string('editthiscategory', 'question');
|
||||
$this->str->hide = get_string('hide');
|
||||
$this->str->order = get_string('order');
|
||||
$this->str->parent = get_string('parent', 'question');
|
||||
$this->str->add = get_string('add');
|
||||
$this->str->action = get_string('action');
|
||||
$this->str->top = get_string('top');
|
||||
$this->str->addcategory = get_string('addcategory', 'question');
|
||||
$this->str->editcategory = get_string('editcategory', 'question');
|
||||
$this->str->cancel = get_string('cancel');
|
||||
$this->str->editcategories = get_string('editcategories', 'question');
|
||||
$this->str->page = get_string('page');
|
||||
|
||||
$this->pageurl = $pageurl;
|
||||
|
||||
$this->initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Old syntax of class constructor. Deprecated in PHP7.
|
||||
*
|
||||
* @deprecated since Moodle 3.1
|
||||
*/
|
||||
public function question_category_object($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
|
||||
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
|
||||
self::__construct($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this classes general category-related variables
|
||||
*/
|
||||
public function initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
|
||||
$lastlist = null;
|
||||
foreach ($contexts as $context){
|
||||
$this->editlists[$context->id] = new question_category_list('ul', '', true, $this->pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH, $context);
|
||||
$this->editlists[$context->id]->lastlist =& $lastlist;
|
||||
if ($lastlist!== null){
|
||||
$lastlist->nextlist =& $this->editlists[$context->id];
|
||||
}
|
||||
$lastlist =& $this->editlists[$context->id];
|
||||
}
|
||||
|
||||
$count = 1;
|
||||
$paged = false;
|
||||
foreach ($this->editlists as $key => $list){
|
||||
list($paged, $count) = $this->editlists[$key]->list_from_records($paged, $count);
|
||||
}
|
||||
$this->catform = new question_category_edit_form($this->pageurl, compact('contexts', 'currentcat'));
|
||||
if (!$currentcat){
|
||||
$this->catform->set_data(array('parent'=>$defaultcategory));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the user interface
|
||||
*
|
||||
*/
|
||||
public function display_user_interface() {
|
||||
|
||||
/// Interface for editing existing categories
|
||||
$this->output_edit_lists();
|
||||
|
||||
|
||||
echo '<br />';
|
||||
/// Interface for adding a new category:
|
||||
$this->output_new_table();
|
||||
echo '<br />';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a table to allow entry of a new category
|
||||
*/
|
||||
public function output_new_table() {
|
||||
$this->catform->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a list to allow editing/rearranging of existing categories
|
||||
*
|
||||
* $this->initialize() must have already been called
|
||||
*
|
||||
*/
|
||||
public function output_edit_lists() {
|
||||
global $OUTPUT;
|
||||
|
||||
echo $OUTPUT->heading_with_help(get_string('editcategories', 'question'), 'editcategories', 'question');
|
||||
|
||||
foreach ($this->editlists as $context => $list){
|
||||
$listhtml = $list->to_html(0, array('str'=>$this->str));
|
||||
if ($listhtml){
|
||||
echo $OUTPUT->box_start('boxwidthwide boxaligncenter generalbox questioncategories contextlevel' . $list->context->contextlevel);
|
||||
$fullcontext = context::instance_by_id($context);
|
||||
echo $OUTPUT->heading(get_string('questioncatsfor', 'question', $fullcontext->get_context_name()), 3);
|
||||
echo $listhtml;
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
}
|
||||
echo $list->display_page_numbers();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets all the courseids for the given categories
|
||||
*
|
||||
* @param array categories contains category objects in a tree representation
|
||||
* @return array courseids flat array in form categoryid=>courseid
|
||||
*/
|
||||
public function get_course_ids($categories) {
|
||||
$courseids = array();
|
||||
foreach ($categories as $key=>$cat) {
|
||||
$courseids[$key] = $cat->course;
|
||||
if (!empty($cat->children)) {
|
||||
$courseids = array_merge($courseids, $this->get_course_ids($cat->children));
|
||||
}
|
||||
}
|
||||
return $courseids;
|
||||
}
|
||||
|
||||
public function edit_single_category($categoryid) {
|
||||
/// Interface for adding a new category
|
||||
global $DB;
|
||||
/// Interface for editing existing categories
|
||||
$category = $DB->get_record("question_categories", array("id" => $categoryid));
|
||||
if (empty($category)) {
|
||||
print_error('invalidcategory', '', '', $categoryid);
|
||||
} else if ($category->parent == 0) {
|
||||
print_error('cannotedittopcat', 'question', '', $categoryid);
|
||||
} else {
|
||||
$category->parent = "{$category->parent},{$category->contextid}";
|
||||
$category->submitbutton = get_string('savechanges');
|
||||
$category->categoryheader = $this->str->edit;
|
||||
$this->catform->set_data($category);
|
||||
$this->catform->display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the viable parents
|
||||
*
|
||||
* Viable parents are any except for the category itself, or any of it's descendants
|
||||
* The parentstrings parameter is passed by reference and changed by this function.
|
||||
*
|
||||
* @param array parentstrings a list of parentstrings
|
||||
* @param object category
|
||||
*/
|
||||
public function set_viable_parents(&$parentstrings, $category) {
|
||||
|
||||
unset($parentstrings[$category->id]);
|
||||
if (isset($category->children)) {
|
||||
foreach ($category->children as $child) {
|
||||
$this->set_viable_parents($parentstrings, $child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets question categories
|
||||
*
|
||||
* @param int parent - if given, restrict records to those with this parent id.
|
||||
* @param string sort - [[sortfield [,sortfield]] {ASC|DESC}]
|
||||
* @return array categories
|
||||
*/
|
||||
public function get_question_categories($parent=null, $sort="sortorder ASC") {
|
||||
global $COURSE, $DB;
|
||||
if (is_null($parent)) {
|
||||
$categories = $DB->get_records('question_categories', array('course' => $COURSE->id), $sort);
|
||||
} else {
|
||||
$select = "parent = ? AND course = ?";
|
||||
$categories = $DB->get_records_select('question_categories', $select, array($parent, $COURSE->id), $sort);
|
||||
}
|
||||
return $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing question category
|
||||
*
|
||||
* @param int deletecat id of category to delete
|
||||
*/
|
||||
public function delete_category($categoryid) {
|
||||
global $CFG, $DB;
|
||||
question_can_delete_cat($categoryid);
|
||||
if (!$category = $DB->get_record("question_categories", array("id" => $categoryid))) { // security
|
||||
print_error('unknowcategory');
|
||||
}
|
||||
/// Send the children categories to live with their grandparent
|
||||
$DB->set_field("question_categories", "parent", $category->parent, array("parent" => $category->id));
|
||||
|
||||
/// Finally delete the category itself
|
||||
$DB->delete_records("question_categories", array("id" => $category->id));
|
||||
|
||||
// Log the deletion of this category.
|
||||
$event = \core\event\question_category_deleted::create_from_question_category_instance($category);
|
||||
$event->add_record_snapshot('question_categories', $category);
|
||||
$event->trigger();
|
||||
|
||||
}
|
||||
|
||||
public function move_questions_and_delete_category($oldcat, $newcat){
|
||||
question_can_delete_cat($oldcat);
|
||||
$this->move_questions($oldcat, $newcat);
|
||||
$this->delete_category($oldcat);
|
||||
}
|
||||
|
||||
public function display_move_form($questionsincategory, $category){
|
||||
global $OUTPUT;
|
||||
$vars = new stdClass();
|
||||
$vars->name = $category->name;
|
||||
$vars->count = $questionsincategory;
|
||||
echo $OUTPUT->box(get_string('categorymove', 'question', $vars), 'generalbox boxaligncenter');
|
||||
$this->moveform->display();
|
||||
}
|
||||
|
||||
public function move_questions($oldcat, $newcat){
|
||||
global $DB;
|
||||
$questionids = $DB->get_records_select_menu('question',
|
||||
'category = ? AND (parent = 0 OR parent = id)', array($oldcat), '', 'id,1');
|
||||
question_move_questions_to_category(array_keys($questionids), $newcat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new category.
|
||||
*
|
||||
* Data is expected to come from question_category_edit_form.
|
||||
*
|
||||
* By default redirects on success, unless $return is true.
|
||||
*
|
||||
* @param string $newparent 'categoryid,contextid' of the parent category.
|
||||
* @param string $newcategory the name.
|
||||
* @param string $newinfo the description.
|
||||
* @param bool $return if true, return rather than redirecting.
|
||||
* @param int|string $newinfoformat description format. One of the FORMAT_ constants.
|
||||
* @param null $idnumber the idnumber. '' is converted to null.
|
||||
* @return bool|int New category id if successful, else false.
|
||||
*/
|
||||
public function add_category($newparent, $newcategory, $newinfo, $return = false, $newinfoformat = FORMAT_HTML,
|
||||
$idnumber = null) {
|
||||
global $DB;
|
||||
if (empty($newcategory)) {
|
||||
print_error('categorynamecantbeblank', 'question');
|
||||
}
|
||||
list($parentid, $contextid) = explode(',', $newparent);
|
||||
//moodle_form makes sure select element output is legal no need for further cleaning
|
||||
require_capability('moodle/question:managecategory', context::instance_by_id($contextid));
|
||||
|
||||
if ($parentid) {
|
||||
if(!($DB->get_field('question_categories', 'contextid', array('id' => $parentid)) == $contextid)) {
|
||||
print_error('cannotinsertquestioncatecontext', 'question', '', array('cat'=>$newcategory, 'ctx'=>$contextid));
|
||||
}
|
||||
}
|
||||
|
||||
if ((string) $idnumber === '') {
|
||||
$idnumber = null;
|
||||
} else if (!empty($contextid)) {
|
||||
// While this check already exists in the form validation, this is a backstop preventing unnecessary errors.
|
||||
if ($DB->record_exists('question_categories',
|
||||
['idnumber' => $idnumber, 'contextid' => $contextid])) {
|
||||
$idnumber = null;
|
||||
}
|
||||
}
|
||||
|
||||
$cat = new stdClass();
|
||||
$cat->parent = $parentid;
|
||||
$cat->contextid = $contextid;
|
||||
$cat->name = $newcategory;
|
||||
$cat->info = $newinfo;
|
||||
$cat->infoformat = $newinfoformat;
|
||||
$cat->sortorder = 999;
|
||||
$cat->stamp = make_unique_id_code();
|
||||
$cat->idnumber = $idnumber;
|
||||
$categoryid = $DB->insert_record("question_categories", $cat);
|
||||
|
||||
// Log the creation of this category.
|
||||
$category = new stdClass();
|
||||
$category->id = $categoryid;
|
||||
$category->contextid = $contextid;
|
||||
$event = \core\event\question_category_created::create_from_question_category_instance($category);
|
||||
$event->trigger();
|
||||
|
||||
if ($return) {
|
||||
return $categoryid;
|
||||
} else {
|
||||
redirect($this->pageurl);//always redirect after successful action
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing category with given params.
|
||||
*
|
||||
* Warning! parameter order and meaning confusingly different from add_category in some ways!
|
||||
*
|
||||
* @param int $updateid id of the category to update.
|
||||
* @param int $newparent 'categoryid,contextid' of the parent category to set.
|
||||
* @param string $newname category name.
|
||||
* @param string $newinfo category description.
|
||||
* @param int|string $newinfoformat description format. One of the FORMAT_ constants.
|
||||
* @param int $idnumber the idnumber. '' is converted to null.
|
||||
* @param bool $redirect if true, will redirect once the DB is updated (default).
|
||||
*/
|
||||
public function update_category($updateid, $newparent, $newname, $newinfo, $newinfoformat = FORMAT_HTML,
|
||||
$idnumber = null, $redirect = true) {
|
||||
global $CFG, $DB;
|
||||
if (empty($newname)) {
|
||||
print_error('categorynamecantbeblank', 'question');
|
||||
}
|
||||
|
||||
// Get the record we are updating.
|
||||
$oldcat = $DB->get_record('question_categories', array('id' => $updateid));
|
||||
$lastcategoryinthiscontext = question_is_only_child_of_top_category_in_context($updateid);
|
||||
|
||||
if (!empty($newparent) && !$lastcategoryinthiscontext) {
|
||||
list($parentid, $tocontextid) = explode(',', $newparent);
|
||||
} else {
|
||||
$parentid = $oldcat->parent;
|
||||
$tocontextid = $oldcat->contextid;
|
||||
}
|
||||
|
||||
// Check permissions.
|
||||
$fromcontext = context::instance_by_id($oldcat->contextid);
|
||||
require_capability('moodle/question:managecategory', $fromcontext);
|
||||
|
||||
// If moving to another context, check permissions some more, and confirm contextid,stamp uniqueness.
|
||||
$newstamprequired = false;
|
||||
if ($oldcat->contextid != $tocontextid) {
|
||||
$tocontext = context::instance_by_id($tocontextid);
|
||||
require_capability('moodle/question:managecategory', $tocontext);
|
||||
|
||||
// Confirm stamp uniqueness in the new context. If the stamp already exists, generate a new one.
|
||||
if ($DB->record_exists('question_categories', array('contextid' => $tocontextid, 'stamp' => $oldcat->stamp))) {
|
||||
$newstamprequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((string) $idnumber === '') {
|
||||
$idnumber = null;
|
||||
} else if (!empty($tocontextid)) {
|
||||
// While this check already exists in the form validation, this is a backstop preventing unnecessary errors.
|
||||
if ($DB->record_exists_select('question_categories',
|
||||
'idnumber = ? AND contextid = ? AND id <> ?',
|
||||
[$idnumber, $tocontextid, $updateid])) {
|
||||
$idnumber = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the category record.
|
||||
$cat = new stdClass();
|
||||
$cat->id = $updateid;
|
||||
$cat->name = $newname;
|
||||
$cat->info = $newinfo;
|
||||
$cat->infoformat = $newinfoformat;
|
||||
$cat->parent = $parentid;
|
||||
$cat->contextid = $tocontextid;
|
||||
$cat->idnumber = $idnumber;
|
||||
if ($newstamprequired) {
|
||||
$cat->stamp = make_unique_id_code();
|
||||
}
|
||||
$DB->update_record('question_categories', $cat);
|
||||
|
||||
// Log the update of this category.
|
||||
$event = \core\event\question_category_updated::create_from_question_category_instance($cat);
|
||||
$event->trigger();
|
||||
|
||||
// If the category name has changed, rename any random questions in that category.
|
||||
if ($oldcat->name != $cat->name) {
|
||||
$where = "qtype = 'random' AND category = ? AND " . $DB->sql_compare_text('questiontext') . " = ?";
|
||||
|
||||
$randomqtype = question_bank::get_qtype('random');
|
||||
$randomqname = $randomqtype->question_name($cat, false);
|
||||
$DB->set_field_select('question', 'name', $randomqname, $where, array($cat->id, '0'));
|
||||
|
||||
$randomqname = $randomqtype->question_name($cat, true);
|
||||
$DB->set_field_select('question', 'name', $randomqname, $where, array($cat->id, '1'));
|
||||
}
|
||||
|
||||
if ($oldcat->contextid != $tocontextid) {
|
||||
// Moving to a new context. Must move files belonging to questions.
|
||||
question_move_category_to_context($cat->id, $oldcat->contextid, $tocontextid);
|
||||
}
|
||||
|
||||
// Cat param depends on the context id, so update it.
|
||||
$this->pageurl->param('cat', $updateid . ',' . $tocontextid);
|
||||
if ($redirect) {
|
||||
redirect($this->pageurl); // Always redirect after successful action.
|
||||
}
|
||||
}
|
||||
}
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
@@ -21,102 +21,7 @@
|
||||
* @subpackage questionbank
|
||||
* @copyright 2007 Jamie Pratt [email protected]
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Form for editing qusetions categories (name, description, etc.)
|
||||
*
|
||||
* @copyright 2007 Jamie Pratt [email protected]
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71585
|
||||
* @see qbank_managecategories\form\category_form
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
class question_category_edit_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
debugging('Class question_export_form in \core_question\category_form is deprecated,
|
||||
please use core_question\bank\managecategories\form\category_form instead.', DEBUG_DEVELOPER);
|
||||
|
||||
$mform = $this->_form;
|
||||
|
||||
$contexts = $this->_customdata['contexts'];
|
||||
$currentcat = $this->_customdata['currentcat'];
|
||||
|
||||
$mform->addElement('header', 'categoryheader', get_string('addcategory', 'question'));
|
||||
|
||||
$mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'question'),
|
||||
array('contexts' => $contexts, 'top' => true, 'currentcat' => $currentcat, 'nochildrenof' => $currentcat));
|
||||
$mform->setType('parent', PARAM_SEQUENCE);
|
||||
if (question_is_only_child_of_top_category_in_context($currentcat)) {
|
||||
$mform->hardFreeze('parent');
|
||||
}
|
||||
$mform->addHelpButton('parent', 'parentcategory', 'question');
|
||||
|
||||
$mform->addElement('text', 'name', get_string('name'),'maxlength="254" size="50"');
|
||||
$mform->setDefault('name', '');
|
||||
$mform->addRule('name', get_string('categorynamecantbeblank', 'question'), 'required', null, 'client');
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
$mform->addElement('editor', 'info', get_string('categoryinfo', 'question'),
|
||||
array('rows' => 10), array('noclean' => 1));
|
||||
$mform->setDefault('info', '');
|
||||
$mform->setType('info', PARAM_RAW);
|
||||
|
||||
$mform->addElement('text', 'idnumber', get_string('idnumber', 'question'), 'maxlength="100" size="10"');
|
||||
$mform->addHelpButton('idnumber', 'idnumber', 'question');
|
||||
$mform->setType('idnumber', PARAM_RAW);
|
||||
|
||||
$this->add_action_buttons(false, get_string('addcategory', 'question'));
|
||||
|
||||
$mform->addElement('hidden', 'id', 0);
|
||||
$mform->setType('id', PARAM_INT);
|
||||
}
|
||||
|
||||
public function set_data($current) {
|
||||
if (is_object($current)) {
|
||||
$current = (array) $current;
|
||||
}
|
||||
if (!empty($current['info'])) {
|
||||
$current['info'] = array('text' => $current['info'],
|
||||
'infoformat' => $current['infoformat']);
|
||||
} else {
|
||||
$current['info'] = array('text' => '', 'infoformat' => FORMAT_HTML);
|
||||
}
|
||||
parent::set_data($current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation.
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $files
|
||||
* @return array the errors that were found
|
||||
*/
|
||||
public function validation($data, $files) {
|
||||
global $DB;
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
// Add field validation check for duplicate idnumber.
|
||||
list($parentid, $contextid) = explode(',', $data['parent']);
|
||||
if (((string) $data['idnumber'] !== '') && !empty($contextid)) {
|
||||
$conditions = 'contextid = ? AND idnumber = ?';
|
||||
$params = [$contextid, $data['idnumber']];
|
||||
if (!empty($data['id'])) {
|
||||
$conditions .= ' AND id <> ?';
|
||||
$params[] = $data['id'];
|
||||
}
|
||||
if ($DB->record_exists_select('question_categories', $conditions, $params)) {
|
||||
$errors['idnumber'] = get_string('idnumbertaken', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A base class for actions that are an icon that lets you manipulate the question in some way.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A base class for actions that are an icon that lets you manipulate the question in some way.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
abstract class action_column_base extends column_base {
|
||||
|
||||
protected function get_title() {
|
||||
return ' ';
|
||||
}
|
||||
|
||||
public function get_extra_classes() {
|
||||
return array('iconcol');
|
||||
}
|
||||
|
||||
protected function print_icon($icon, $title, $url) {
|
||||
global $OUTPUT;
|
||||
echo '<a title="' . $title . '" href="' . $url . '">' . $OUTPUT->pix_icon($icon, $title) . '</a>';
|
||||
}
|
||||
|
||||
public function get_extra_joins() {
|
||||
return array('qc' => 'JOIN {question_categories} qc ON qc.id = q.category');
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
// Createdby is required for permission checks.
|
||||
// Qtype so we can easily avoid applying actions to question types that
|
||||
// are no longer installed.
|
||||
return ['q.id', 'q.qtype', 'q.createdby', 'qc.contextid'];
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column with a checkbox for each question with name q{questionid}.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\output\checkbox_toggleall;
|
||||
|
||||
|
||||
/**
|
||||
* A column with a checkbox for each question with name q{questionid}.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
class checkbox_column extends column_base {
|
||||
|
||||
public function get_name() {
|
||||
return 'checkbox';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
global $OUTPUT;
|
||||
|
||||
$mastercheckbox = new checkbox_toggleall('qbank', true, [
|
||||
'id' => 'qbheadercheckbox',
|
||||
'name' => 'qbheadercheckbox',
|
||||
'value' => '1',
|
||||
'label' => get_string('selectall'),
|
||||
'labelclasses' => 'accesshide',
|
||||
]);
|
||||
|
||||
return $OUTPUT->render($mastercheckbox);
|
||||
}
|
||||
|
||||
protected function get_title_tip() {
|
||||
return get_string('selectquestionsforbulk', 'question');
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
global $OUTPUT;
|
||||
|
||||
$checkbox = new checkbox_toggleall('qbank', false, [
|
||||
'id' => "checkq{$question->id}",
|
||||
'name' => "q{$question->id}",
|
||||
'value' => '1',
|
||||
'label' => get_string('select'),
|
||||
'labelclasses' => 'accesshide',
|
||||
]);
|
||||
|
||||
echo $OUTPUT->render($checkbox);
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
return array('q.id');
|
||||
}
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Base class for representing a column in a {@see question_bank_view}.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Base class for representing a column in a {@see question_bank_view}.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
abstract class column_base {
|
||||
|
||||
/**
|
||||
* @var view $qbank the question bank view we are helping to render.
|
||||
*/
|
||||
protected $qbank;
|
||||
|
||||
/** @var bool determine whether the column is td or th. */
|
||||
protected $isheading = false;
|
||||
|
||||
/**
|
||||
* Constructor for the question bank view we are helping to render.
|
||||
* @param view $qbank
|
||||
*/
|
||||
public function __construct($qbank) {
|
||||
$this->qbank = $qbank;
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* A chance for subclasses to initialise themselves, for example to load lang strings,
|
||||
* without having to override the constructor.
|
||||
*/
|
||||
protected function init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column as heading
|
||||
*/
|
||||
public function set_as_heading() {
|
||||
$this->isheading = true;
|
||||
}
|
||||
|
||||
public function is_extra_row() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the row has an extra preference to view/hide.
|
||||
*/
|
||||
public function has_preference(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the preference key of the row.
|
||||
*/
|
||||
public function get_preference_key(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the preference of the row.
|
||||
*/
|
||||
public function get_preference(): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the column header cell.
|
||||
*/
|
||||
public function display_header() {
|
||||
echo '<th class="header ' . $this->get_classes() . '" scope="col">';
|
||||
$sortable = $this->is_sortable();
|
||||
$name = get_class($this);
|
||||
$title = $this->get_title();
|
||||
$tip = $this->get_title_tip();
|
||||
if (is_array($sortable)) {
|
||||
if ($title) {
|
||||
echo '<div class="title">' . $title . '</div>';
|
||||
}
|
||||
$links = array();
|
||||
foreach ($sortable as $subsort => $details) {
|
||||
$links[] = $this->make_sort_link($name . '-' . $subsort,
|
||||
$details['title'], isset($details['tip']) ? $details['tip'] : '', !empty($details['reverse']));
|
||||
}
|
||||
echo '<div class="sorters">' . implode(' / ', $links) . '</div>';
|
||||
} else if ($sortable) {
|
||||
echo $this->make_sort_link($name, $title, $tip);
|
||||
} else {
|
||||
if ($tip) {
|
||||
echo '<span title="' . $tip . '">';
|
||||
}
|
||||
echo $title;
|
||||
if ($tip) {
|
||||
echo '</span>';
|
||||
}
|
||||
}
|
||||
echo "</th>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Title for this column. Not used if is_sortable returns an array.
|
||||
*/
|
||||
protected abstract function get_title();
|
||||
|
||||
/**
|
||||
* @return string a fuller version of the name. Use this when get_title() returns
|
||||
* something very short, and you want a longer version as a tool tip.
|
||||
*/
|
||||
protected function get_title_tip() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a link that changes the sort order, and indicates the current sort state.
|
||||
* @param string $sort the column to sort on.
|
||||
* @param string $title the link text.
|
||||
* @param string $tip the link tool-tip text. If empty, defaults to title.
|
||||
* @param bool $defaultreverse whether the default sort order for this column is descending, rather than ascending.
|
||||
* @return string HTML fragment.
|
||||
*/
|
||||
protected function make_sort_link($sort, $title, $tip, $defaultreverse = false) {
|
||||
$currentsort = $this->qbank->get_primary_sort_order($sort);
|
||||
$newsortreverse = $defaultreverse;
|
||||
if ($currentsort) {
|
||||
$newsortreverse = $currentsort > 0;
|
||||
}
|
||||
if (!$tip) {
|
||||
$tip = $title;
|
||||
}
|
||||
if ($newsortreverse) {
|
||||
$tip = get_string('sortbyxreverse', '', $tip);
|
||||
} else {
|
||||
$tip = get_string('sortbyx', '', $tip);
|
||||
}
|
||||
$link = '<a href="' . $this->qbank->new_sort_url($sort, $newsortreverse) . '" title="' . $tip . '">';
|
||||
$link .= $title;
|
||||
if ($currentsort) {
|
||||
$link .= $this->get_sort_icon($currentsort < 0);
|
||||
}
|
||||
$link .= '</a>';
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an icon representing the corrent sort state.
|
||||
* @param bool $reverse sort is descending, not ascending.
|
||||
* @return string HTML image tag.
|
||||
*/
|
||||
protected function get_sort_icon($reverse) {
|
||||
global $OUTPUT;
|
||||
if ($reverse) {
|
||||
return $OUTPUT->pix_icon('t/sort_desc', get_string('desc'), '', array('class' => 'iconsort'));
|
||||
} else {
|
||||
return $OUTPUT->pix_icon('t/sort_asc', get_string('asc'), '', array('class' => 'iconsort'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output this column.
|
||||
* @param object $question the row from the $question table, augmented with extra information.
|
||||
* @param string $rowclasses CSS class names that should be applied to this row of output.
|
||||
*/
|
||||
public function display($question, $rowclasses) {
|
||||
$this->display_start($question, $rowclasses);
|
||||
$this->display_content($question, $rowclasses);
|
||||
$this->display_end($question, $rowclasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the opening column tag. If it is set as heading, it will use <th> tag instead of <td>
|
||||
*
|
||||
* @param \stdClass $question
|
||||
* @param string $rowclasses
|
||||
*/
|
||||
protected function display_start($question, $rowclasses) {
|
||||
$tag = 'td';
|
||||
$attr = array('class' => $this->get_classes());
|
||||
if ($this->isheading) {
|
||||
$tag = 'th';
|
||||
$attr['scope'] = 'row';
|
||||
}
|
||||
echo \html_writer::start_tag($tag, $attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the CSS classes to apply to every cell in this column.
|
||||
*/
|
||||
protected function get_classes() {
|
||||
$classes = $this->get_extra_classes();
|
||||
$classes[] = $this->get_name();
|
||||
return implode(' ', $classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal name for this column. Used as a CSS class name,
|
||||
* and to store information about the current sort. Must match PARAM_ALPHA.
|
||||
*
|
||||
* @return string column name.
|
||||
*/
|
||||
public abstract function get_name();
|
||||
|
||||
/**
|
||||
* @return array any extra class names you would like applied to every cell in this column.
|
||||
*/
|
||||
public function get_extra_classes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the contents of this column.
|
||||
* @param object $question the row from the $question table, augmented with extra information.
|
||||
* @param string $rowclasses CSS class names that should be applied to this row of output.
|
||||
*/
|
||||
protected abstract function display_content($question, $rowclasses);
|
||||
|
||||
/**
|
||||
* Output the closing column tag
|
||||
*
|
||||
* @param object $question
|
||||
* @param string $rowclasses
|
||||
*/
|
||||
protected function display_end($question, $rowclasses) {
|
||||
$tag = 'td';
|
||||
if ($this->isheading) {
|
||||
$tag = 'th';
|
||||
}
|
||||
echo \html_writer::end_tag($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array 'table_alias' => 'JOIN clause' to bring in any data that
|
||||
* this column required.
|
||||
*
|
||||
* The return values for all the columns will be checked. It is OK if two
|
||||
* columns join in the same table with the same alias and identical JOIN clauses.
|
||||
* If to columns try to use the same alias with different joins, you get an error.
|
||||
* The only table included by default is the question table, which is aliased to 'q'.
|
||||
*
|
||||
* It is importnat that your join simply adds additional data (or NULLs) to the
|
||||
* existing rows of the query. It must not cause additional rows.
|
||||
*
|
||||
* @return array 'table_alias' => 'JOIN clause'
|
||||
*/
|
||||
public function get_extra_joins() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array fields required. use table alias 'q' for the question table, or one of the
|
||||
* ones from get_extra_joins. Every field requested must specify a table prefix.
|
||||
*/
|
||||
public function get_required_fields() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this column needs extra data (e.g. tags) then load that here.
|
||||
*
|
||||
* The extra data should be added to the question object in the array.
|
||||
* Probably a good idea to check that another column has not already
|
||||
* loaded the data you want.
|
||||
*
|
||||
* @param \stdClass[] $questions the questions that will be displayed.
|
||||
*/
|
||||
public function load_additional_data(array $questions) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the tags for each question.
|
||||
*
|
||||
* Helper that can be used from {@see load_additional_data()};
|
||||
*
|
||||
* @param array $questions
|
||||
*/
|
||||
public function load_question_tags(array $questions) {
|
||||
$firstquestion = reset($questions);
|
||||
if (isset($firstquestion->tags)) {
|
||||
// Looks like tags are already loaded, so don't do it again.
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the tags.
|
||||
$tagdata = \core_tag_tag::get_items_tags('core_question', 'question',
|
||||
array_keys($questions));
|
||||
|
||||
// Add them to the question objects.
|
||||
foreach ($tagdata as $questionid => $tags) {
|
||||
$questions[$questionid]->tags = $tags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this column be sorted on? You can return either:
|
||||
* + false for no (the default),
|
||||
* + a field name, if sorting this column corresponds to sorting on that datbase field.
|
||||
* + an array of subnames to sort on as follows
|
||||
* return array(
|
||||
* 'firstname' => array('field' => 'uc.firstname', 'title' => get_string('firstname')),
|
||||
* 'lastname' => array('field' => 'uc.lastname', 'title' => get_string('lastname')),
|
||||
* );
|
||||
* As well as field, and field, you can also add 'revers' => 1 if you want the default sort
|
||||
* order to be DESC.
|
||||
* @return mixed as above.
|
||||
*/
|
||||
public function is_sortable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for building sort clauses.
|
||||
* @param bool $reverse whether the normal direction should be reversed.
|
||||
* @return string 'ASC' or 'DESC'
|
||||
*/
|
||||
protected function sortorder($reverse) {
|
||||
if ($reverse) {
|
||||
return ' DESC';
|
||||
} else {
|
||||
return ' ASC';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $reverse Whether to sort in the reverse of the default sort order.
|
||||
* @param string $subsort if is_sortable returns an array of subnames, then this will be
|
||||
* one of those. Otherwise will be empty.
|
||||
* @return string some SQL to go in the order by clause.
|
||||
*/
|
||||
public function sort_expression($reverse, $subsort) {
|
||||
$sortable = $this->is_sortable();
|
||||
if (is_array($sortable)) {
|
||||
if (array_key_exists($subsort, $sortable)) {
|
||||
return $sortable[$subsort]['field'] . $this->sortorder($reverse);
|
||||
} else {
|
||||
throw new \coding_exception('Unexpected $subsort type: ' . $subsort);
|
||||
}
|
||||
} else if ($sortable) {
|
||||
return $sortable . $this->sortorder($reverse);
|
||||
} else {
|
||||
throw new \coding_exception('sort_expression called on a non-sortable column.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Question bank column for the duplicate action icon.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Question bank column for the duplicate action icon.
|
||||
*
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class copy_action_column extends menu_action_column_base {
|
||||
/** @var string avoids repeated calls to get_string('duplicate'). */
|
||||
protected $strcopy;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
$this->strcopy = get_string('duplicate');
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'copyaction';
|
||||
}
|
||||
|
||||
protected function get_url_icon_and_label(\stdClass $question): array {
|
||||
if (!\question_bank::is_qtype_installed($question->qtype)) {
|
||||
// It sometimes happens that people end up with junk questions
|
||||
// in their question bank of a type that is no longer installed.
|
||||
// We cannot do most actions on them, because that leads to errors.
|
||||
return [null, null, null];
|
||||
}
|
||||
|
||||
// To copy a question, you need permission to add a question in the same
|
||||
// category as the existing question, and ability to access the details of
|
||||
// the question being copied.
|
||||
if (question_has_capability_on($question, 'add') &&
|
||||
(question_has_capability_on($question, 'edit') || question_has_capability_on($question, 'view'))) {
|
||||
return [$this->qbank->copy_question_moodle_url($question->id), 't/copy', $this->strcopy];
|
||||
}
|
||||
return [null, null, null];
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name of the question creator.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question creator.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class creator_name_column extends column_base {
|
||||
public function get_name() {
|
||||
return 'creatorname';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
return get_string('createdby', 'question');
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
if (!empty($question->creatorfirstname) && !empty($question->creatorlastname)) {
|
||||
$u = new \stdClass();
|
||||
$u = username_load_fields_from_object($u, $question, 'creator');
|
||||
$date = userdate($question->timecreated, get_string('strftimedatetime', 'langconfig'));
|
||||
echo fullname($u) . '<br>' . \html_writer::tag('span', $date, array('class' => 'date'));
|
||||
}
|
||||
}
|
||||
|
||||
public function get_extra_joins() {
|
||||
return array('uc' => 'LEFT JOIN {user} uc ON uc.id = q.createdby');
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
$allnames = \core_user\fields::get_name_fields();
|
||||
$requiredfields = array();
|
||||
foreach ($allnames as $allname) {
|
||||
$requiredfields[] = 'uc.' . $allname . ' AS creator' . $allname;
|
||||
}
|
||||
$requiredfields[] = 'q.timecreated';
|
||||
return $requiredfields;
|
||||
}
|
||||
|
||||
public function is_sortable() {
|
||||
return array(
|
||||
'firstname' => array('field' => 'uc.firstname', 'title' => get_string('firstname')),
|
||||
'lastname' => array('field' => 'uc.lastname', 'title' => get_string('lastname')),
|
||||
'timecreated' => array('field' => 'q.timecreated', 'title' => get_string('date'))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* action to delete (or hide) a question, or restore a previously hidden question.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* action to delete (or hide) a question, or restore a previously hidden question.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class delete_action_column extends menu_action_column_base {
|
||||
protected $strdelete;
|
||||
protected $strrestore;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
$this->strdelete = get_string('delete');
|
||||
$this->strrestore = get_string('restore');
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'deleteaction';
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out the info required to display this action, if appropriate.
|
||||
*
|
||||
* If the action is not appropriate to this question, return [null, null, null].
|
||||
*
|
||||
* Otherwise return an array with three elements:
|
||||
* moodel_url $url the URL to perform the action.
|
||||
* string $icon the icon name. E.g. 't/delete'.
|
||||
* string $label the label to display.
|
||||
*
|
||||
* @param object $question the row from the $question table, augmented with extra information.
|
||||
* @return array [$url, $label, $icon] as above.
|
||||
*/
|
||||
protected function get_url_icon_and_label(\stdClass $question): array {
|
||||
if (!question_has_capability_on($question, 'edit')) {
|
||||
return [null, null, null];
|
||||
}
|
||||
if ($question->hidden) {
|
||||
$url = new \moodle_url($this->qbank->base_url(), array('unhide' => $question->id, 'sesskey' => sesskey()));
|
||||
return [$url, 't/restore', $this->strrestore];
|
||||
} else {
|
||||
$url = new \moodle_url($this->qbank->base_url(), array('deleteselected' => $question->id, 'q' . $question->id => 1,
|
||||
'sesskey' => sesskey()));
|
||||
return [$url, 't/delete', $this->strdelete];
|
||||
}
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
$required = parent::get_required_fields();
|
||||
$required[] = 'q.hidden';
|
||||
return $required;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Base class for question bank columns that just contain an action icon.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Base class for question bank columns that just contain an action icon.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class edit_action_column extends menu_action_column_base {
|
||||
protected $stredit;
|
||||
protected $strview;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
$this->stredit = get_string('editquestion', 'question');
|
||||
$this->strview = get_string('view');
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'editaction';
|
||||
}
|
||||
|
||||
protected function get_url_icon_and_label(\stdClass $question): array {
|
||||
if (!\question_bank::is_qtype_installed($question->qtype)) {
|
||||
// It sometimes happens that people end up with junk questions
|
||||
// in their question bank of a type that is no longer installed.
|
||||
// We cannot do most actions on them, because that leads to errors.
|
||||
return [null, null, null];
|
||||
}
|
||||
|
||||
if (question_has_capability_on($question, 'edit')) {
|
||||
return [$this->qbank->edit_question_moodle_url($question->id), 't/edit', $this->stredit];
|
||||
} else if (question_has_capability_on($question, 'view')) {
|
||||
return [$this->qbank->edit_question_moodle_url($question->id), 'i/info', $this->strview];
|
||||
} else {
|
||||
return [null, null, null];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A question bank column which gathers together all the actions into a menu.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A question bank column which gathers together all the actions into a menu.
|
||||
*
|
||||
* This question bank column, if added to the question bank, will
|
||||
* replace all of the other columns which implement the
|
||||
* {@link menuable_action} interface and replace them with a single
|
||||
* column containing an Edit menu.
|
||||
*
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
class edit_menu_column extends column_base {
|
||||
/**
|
||||
* @var menuable_action[]
|
||||
*/
|
||||
protected $actions;
|
||||
|
||||
/**
|
||||
* Set up the list of actions that should be shown in the menu.
|
||||
*
|
||||
* This takes a list of column object (the list from a question
|
||||
* bank view). It extracts all the ones that should go in the menu
|
||||
* and stores them for later use. Then it returns the remaining columns.
|
||||
*
|
||||
* @param column_base[] $allcolumns a set of columns.
|
||||
* @return column_base[] the non-action columns from the set.
|
||||
*/
|
||||
public function claim_menuable_columns($allcolumns) {
|
||||
$remainingcolumns = [];
|
||||
foreach ($allcolumns as $key => $column) {
|
||||
if ($column instanceof menuable_action) {
|
||||
$this->actions[$key] = $column;
|
||||
} else {
|
||||
$remainingcolumns[$key] = $column;
|
||||
}
|
||||
}
|
||||
return $remainingcolumns;
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
return get_string('actions');
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'editmenu';
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
global $OUTPUT;
|
||||
|
||||
$menu = new \action_menu();
|
||||
$menu->set_menu_trigger(get_string('edit'));
|
||||
$menu->set_alignment(\action_menu::TL, \action_menu::BL);
|
||||
foreach ($this->actions as $actioncolumn) {
|
||||
$action = $actioncolumn->get_action_menu_link($question);
|
||||
if ($action) {
|
||||
$menu->add($action);
|
||||
}
|
||||
}
|
||||
|
||||
$qtypeactions = \question_bank::get_qtype($question->qtype, false)
|
||||
->get_extra_question_bank_actions($question);
|
||||
foreach ($qtypeactions as $action) {
|
||||
$menu->add($action);
|
||||
}
|
||||
|
||||
echo $OUTPUT->render($menu);
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
return ['q.qtype'];
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Question bank column export the question in Moodle XML format.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Question bank column export the question in Moodle XML format.
|
||||
*
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class export_xml_action_column extends menu_action_column_base {
|
||||
/** @var string avoids repeated calls to get_string('duplicate'). */
|
||||
protected $strexportasxml;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
$this->strexportasxml = get_string('exportasxml', 'question');
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'exportasxmlaction';
|
||||
}
|
||||
|
||||
protected function get_url_icon_and_label(\stdClass $question): array {
|
||||
if (!\question_bank::is_qtype_installed($question->qtype)) {
|
||||
// It sometimes happens that people end up with junk questions
|
||||
// in their question bank of a type that is no longer installed.
|
||||
// We cannot do most actions on them, because that leads to errors.
|
||||
return [null, null, null];
|
||||
}
|
||||
|
||||
if (!question_has_capability_on($question, 'view')) {
|
||||
return [null, null, null];
|
||||
}
|
||||
|
||||
return [\qbank_exporttoxml\helper::question_get_export_single_question_url($question),
|
||||
't/download', $this->strexportasxml];
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Base class to make it easier to implement actions that are menuable_actions.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2019 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Base class to make it easier to implement actions that are menuable_actions.
|
||||
*
|
||||
* Use this class if your action is simple (defined by just a URL, label and icon).
|
||||
* If your action is not simple enough to fit into the pattern that this
|
||||
* class implements, then you will have to implement the menuable_action
|
||||
* interface yourself.
|
||||
*
|
||||
* @copyright 2019 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
abstract class menu_action_column_base extends action_column_base implements menuable_action {
|
||||
|
||||
/**
|
||||
* Get the information required to display this action either as a menu item or a separate action column.
|
||||
*
|
||||
* If this action cannot apply to this question (e.g. because the user does not have
|
||||
* permission, then return [null, null, null].
|
||||
*
|
||||
* @param \stdClass $question the row from the $question table, augmented with extra information.
|
||||
* @return array with three elements.
|
||||
* $url - the URL to perform the action.
|
||||
* $icon - the icon for this action. E.g. 't/delete'.
|
||||
* $label - text label to display in the UI (either in the menu, or as a tool-tip on the icon)
|
||||
*/
|
||||
abstract protected function get_url_icon_and_label(\stdClass $question): array;
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
[$url, $icon, $label] = $this->get_url_icon_and_label($question);
|
||||
if ($url) {
|
||||
$this->print_icon($icon, $label, $url);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_action_menu_link(\stdClass $question): ?\action_menu_link {
|
||||
[$url, $icon, $label] = $this->get_url_icon_and_label($question);
|
||||
if (!$url) {
|
||||
return null;
|
||||
}
|
||||
return new \action_menu_link_secondary($url, new \pix_icon($icon, ''), $label);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Interface to indicate that a question bank column can go in the action menu.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2019 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Interface to indicate that a question bank column can go in the action menu.
|
||||
*
|
||||
* If a question bank column implements this interface, and if the {@link edit_menu_column}
|
||||
* is present in the question bank view, then the 'column' will be shown as an entry in the
|
||||
* edit menu instead of as a separate column.
|
||||
*
|
||||
* Probably most columns that want to implement this will be subclasses of
|
||||
* {@link action_column_base}, and most such columns should probably implement
|
||||
* this interface.
|
||||
*
|
||||
* If your column is a simple action, you can probably save duplicated code by
|
||||
* using the base class action_column_menuable as an easy way to implement both
|
||||
* action_column_base and this interface.
|
||||
*
|
||||
* @copyright 2019 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
interface menuable_action {
|
||||
|
||||
/**
|
||||
* Return the appropriate action menu link, or null if it does not apply to this question.
|
||||
*
|
||||
* @param \stdClass $question data about the question being displayed in this row.
|
||||
* @return \action_menu_link|null the action, if applicable to this question.
|
||||
*/
|
||||
public function get_action_menu_link(\stdClass $question): ?\action_menu_link;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name of the question last modifier.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question last modifier.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class modifier_name_column extends column_base {
|
||||
public function get_name() {
|
||||
return 'modifiername';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
return get_string('lastmodifiedby', 'question');
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
if (!empty($question->modifierfirstname) && !empty($question->modifierlastname)) {
|
||||
$u = new \stdClass();
|
||||
$u = username_load_fields_from_object($u, $question, 'modifier');
|
||||
$date = userdate($question->timemodified, get_string('strftimedatetime', 'langconfig'));
|
||||
echo fullname($u) . '<br>' . \html_writer::tag('span', $date, array('class' => 'date'));
|
||||
}
|
||||
}
|
||||
|
||||
public function get_extra_joins() {
|
||||
return array('um' => 'LEFT JOIN {user} um ON um.id = q.modifiedby');
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
$allnames = \core_user\fields::get_name_fields();
|
||||
$requiredfields = array();
|
||||
foreach ($allnames as $allname) {
|
||||
$requiredfields[] = 'um.' . $allname . ' AS modifier' . $allname;
|
||||
}
|
||||
$requiredfields[] = 'q.timemodified';
|
||||
return $requiredfields;
|
||||
}
|
||||
|
||||
public function is_sortable() {
|
||||
return array(
|
||||
'firstname' => array('field' => 'um.firstname', 'title' => get_string('firstname')),
|
||||
'lastname' => array('field' => 'um.lastname', 'title' => get_string('lastname')),
|
||||
'timemodified' => array('field' => 'q.timemodified', 'title' => get_string('date'))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Question bank columns for the preview action icon.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Question bank columns for the preview action icon.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class preview_action_column extends action_column_base implements menuable_action {
|
||||
/**
|
||||
* @var string store this lang string for performance.
|
||||
*/
|
||||
protected $strpreview;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
$this->strpreview = get_string('preview');
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'previewaction';
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
global $PAGE;
|
||||
|
||||
if (!\question_bank::is_qtype_installed($question->qtype)) {
|
||||
// It sometimes happens that people end up with junk questions
|
||||
// in their question bank of a type that is no longer installed.
|
||||
// We cannot do most actions on them, because that leads to errors.
|
||||
return;
|
||||
}
|
||||
|
||||
if (question_has_capability_on($question, 'use')) {
|
||||
echo $PAGE->get_renderer('core_question')->question_preview_link(
|
||||
$question->id, $this->qbank->get_most_specific_context(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_action_menu_link(\stdClass $question): ?\action_menu_link {
|
||||
if (!\question_bank::is_qtype_installed($question->qtype)) {
|
||||
// It sometimes happens that people end up with junk questions
|
||||
// in their question bank of a type that is no longer installed.
|
||||
// We cannot do most actions on them, because that leads to errors.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!question_has_capability_on($question, 'use')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$context = $this->qbank->get_most_specific_context();
|
||||
$url = question_preview_url($question->id, null, null, null, null, $context);
|
||||
return new \action_menu_link_secondary($url, new \pix_icon('t/preview', ''),
|
||||
$this->strpreview, ['target' => 'questionpreview']);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class question_name_column extends column_base {
|
||||
protected $checkboxespresent = null;
|
||||
|
||||
public function get_name() {
|
||||
return 'questionname';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
return get_string('question');
|
||||
}
|
||||
|
||||
protected function label_for($question) {
|
||||
if (is_null($this->checkboxespresent)) {
|
||||
$this->checkboxespresent = $this->qbank->has_column('core_question\local\bank\checkbox_column');
|
||||
}
|
||||
if ($this->checkboxespresent) {
|
||||
return 'checkq' . $question->id;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
$labelfor = $this->label_for($question);
|
||||
if ($labelfor) {
|
||||
echo '<label for="' . $labelfor . '">';
|
||||
}
|
||||
echo format_string($question->name);
|
||||
if ($labelfor) {
|
||||
echo '</label>';
|
||||
}
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
return array('q.id', 'q.name');
|
||||
}
|
||||
|
||||
public function is_sortable() {
|
||||
return 'q.name';
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A question bank column showing the question name with idnumber and tags.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A question bank column showing the question name with idnumber and tags.
|
||||
*
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class question_name_idnumber_tags_column extends question_name_column {
|
||||
public function get_name() {
|
||||
return 'qnameidnumbertags';
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
global $OUTPUT;
|
||||
|
||||
$layoutclasses = 'd-inline-flex flex-nowrap overflow-hidden w-100';
|
||||
$labelfor = $this->label_for($question);
|
||||
if ($labelfor) {
|
||||
echo '<label for="' . $labelfor . '" class="' . $layoutclasses . '">';
|
||||
$closetag = '</label>';
|
||||
} else {
|
||||
echo '<span class="' . $layoutclasses . '">';
|
||||
$closetag = '</span>';
|
||||
}
|
||||
|
||||
// Question name.
|
||||
echo \html_writer::span(format_string($question->name), 'questionname flex-grow-1 flex-shrink-1 text-truncate');
|
||||
|
||||
// Question idnumber.
|
||||
if ($question->idnumber !== null && $question->idnumber !== '') {
|
||||
echo ' ' . \html_writer::span(
|
||||
\html_writer::span(get_string('idnumber', 'question'), 'accesshide') . ' ' .
|
||||
\html_writer::span(s($question->idnumber), 'badge badge-primary'), 'ml-1');
|
||||
}
|
||||
|
||||
// Question tags.
|
||||
if (!empty($question->tags)) {
|
||||
$tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
|
||||
echo $OUTPUT->tag_list($tags, null, 'd-inline flex-shrink-1 text-truncate ml-1', 0, null, true);
|
||||
}
|
||||
|
||||
echo $closetag; // Computed above to ensure it matches.
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
$fields = parent::get_required_fields();
|
||||
$fields[] = 'q.idnumber';
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function is_sortable() {
|
||||
return [
|
||||
'name' => ['field' => 'q.name', 'title' => get_string('questionname', 'question')],
|
||||
'idnumber' => ['field' => 'q.idnumber', 'title' => get_string('idnumber', 'question')],
|
||||
];
|
||||
}
|
||||
|
||||
public function load_additional_data(array $questions) {
|
||||
parent::load_additional_data($questions);
|
||||
parent::load_question_tags($questions);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class question_text_row extends row_base {
|
||||
protected $formatoptions;
|
||||
|
||||
protected function init() {
|
||||
$this->formatoptions = new \stdClass();
|
||||
$this->formatoptions->noclean = true;
|
||||
$this->formatoptions->para = false;
|
||||
}
|
||||
|
||||
public function get_name() {
|
||||
return 'questiontext';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
return get_string('questiontext', 'question');
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
$text = question_rewrite_question_preview_urls($question->questiontext, $question->id,
|
||||
$question->contextid, 'question', 'questiontext', $question->id,
|
||||
$question->contextid, 'core_question');
|
||||
$text = format_text($text, $question->questiontextformat,
|
||||
$this->formatoptions);
|
||||
if ($text == '') {
|
||||
$text = ' ';
|
||||
}
|
||||
echo $text;
|
||||
}
|
||||
|
||||
public function get_extra_joins() {
|
||||
return array('qc' => 'JOIN {question_categories} qc ON qc.id = q.category');
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
return array('q.id', 'q.questiontext', 'q.questiontextformat', 'qc.contextid');
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A column type for the name of the question type.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question type.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class question_type_column extends column_base {
|
||||
public function get_name() {
|
||||
return 'qtype';
|
||||
}
|
||||
|
||||
protected function get_title() {
|
||||
return get_string('qtypeveryshort', 'question');
|
||||
}
|
||||
|
||||
protected function get_title_tip() {
|
||||
return get_string('questiontype', 'question');
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
echo print_question_icon($question);
|
||||
}
|
||||
|
||||
public function get_required_fields() {
|
||||
return array('q.qtype');
|
||||
}
|
||||
|
||||
public function is_sortable() {
|
||||
return 'q.qtype';
|
||||
}
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A class for efficiently finds questions at random from the question bank.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2015 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
|
||||
|
||||
/**
|
||||
* This class efficiently finds questions at random from the question bank.
|
||||
*
|
||||
* You can ask for questions at random one at a time. Each time you ask, you
|
||||
* pass a category id, and whether to pick from that category and all subcategories
|
||||
* or just that category.
|
||||
*
|
||||
* The number of teams each question has been used is tracked, and we will always
|
||||
* return a question from among those elegible that has been used the fewest times.
|
||||
* So, if there are questions that have not been used yet in the category asked for,
|
||||
* one of those will be returned. However, within one instantiation of this class,
|
||||
* we will never return a given question more than once, and we will never return
|
||||
* questions passed into the constructor as $usedquestions.
|
||||
*
|
||||
* @copyright 2015 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
class random_question_loader {
|
||||
/** @var \qubaid_condition which usages to consider previous attempts from. */
|
||||
protected $qubaids;
|
||||
|
||||
/** @var array qtypes that cannot be used by random questions. */
|
||||
protected $excludedqtypes;
|
||||
|
||||
/** @var array categoryid & include subcategories => num previous uses => questionid => 1. */
|
||||
protected $availablequestionscache = array();
|
||||
|
||||
/**
|
||||
* @var array questionid => num recent uses. Questions that have been used,
|
||||
* but that is not yet recorded in the DB.
|
||||
*/
|
||||
protected $recentlyusedquestions;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param \qubaid_condition $qubaids the usages to consider when counting previous uses of each question.
|
||||
* @param array $usedquestions questionid => number of times used count. If we should allow for
|
||||
* further existing uses of a question in addition to the ones in $qubaids.
|
||||
*/
|
||||
public function __construct(\qubaid_condition $qubaids, array $usedquestions = array()) {
|
||||
$this->qubaids = $qubaids;
|
||||
$this->recentlyusedquestions = $usedquestions;
|
||||
|
||||
foreach (\question_bank::get_all_qtypes() as $qtype) {
|
||||
if (!$qtype->is_usable_by_random()) {
|
||||
$this->excludedqtypes[] = $qtype->name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick a question at random from the given category, from among those with the fewest uses.
|
||||
* If an array of tag ids are specified, then only the questions that are tagged with ALL those tags will be selected.
|
||||
*
|
||||
* It is up the the caller to verify that the cateogry exists. An unknown category
|
||||
* behaves like an empty one.
|
||||
*
|
||||
* @param int $categoryid the id of a category in the question bank.
|
||||
* @param bool $includesubcategories wether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param array $tagids An array of tag ids. A question has to be tagged with all the provided tagids (if any)
|
||||
* in order to be eligible for being picked.
|
||||
* @return int|null the id of the question picked, or null if there aren't any.
|
||||
*/
|
||||
public function get_next_question_id($categoryid, $includesubcategories, $tagids = []) {
|
||||
$this->ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids);
|
||||
|
||||
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
|
||||
if (empty($this->availablequestionscache[$categorykey])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
reset($this->availablequestionscache[$categorykey]);
|
||||
$lowestcount = key($this->availablequestionscache[$categorykey]);
|
||||
reset($this->availablequestionscache[$categorykey][$lowestcount]);
|
||||
$questionid = key($this->availablequestionscache[$categorykey][$lowestcount]);
|
||||
$this->use_question($questionid);
|
||||
return $questionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key into {@link $availablequestionscache} for this combination of options.
|
||||
* @param int $categoryid the id of a category in the question bank.
|
||||
* @param bool $includesubcategories wether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param array $tagids an array of tag ids.
|
||||
* @return string the cache key.
|
||||
*/
|
||||
protected function get_category_key($categoryid, $includesubcategories, $tagids = []) {
|
||||
if ($includesubcategories) {
|
||||
$key = $categoryid . '|1';
|
||||
} else {
|
||||
$key = $categoryid . '|0';
|
||||
}
|
||||
|
||||
if (!empty($tagids)) {
|
||||
$key .= '|' . implode('|', $tagids);
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate {@link $availablequestionscache} for this combination of options.
|
||||
* @param int $categoryid The id of a category in the question bank.
|
||||
* @param bool $includesubcategories Whether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param array $tagids An array of tag ids. If an array is provided, then
|
||||
* only the questions that are tagged with ALL the provided tagids will be loaded.
|
||||
*/
|
||||
protected function ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids = []) {
|
||||
global $DB;
|
||||
|
||||
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
|
||||
|
||||
if (isset($this->availablequestionscache[$categorykey])) {
|
||||
// Data is already in the cache, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the available questions from the question bank.
|
||||
if ($includesubcategories) {
|
||||
$categoryids = question_categorylist($categoryid);
|
||||
} else {
|
||||
$categoryids = array($categoryid);
|
||||
}
|
||||
|
||||
list($extraconditions, $extraparams) = $DB->get_in_or_equal($this->excludedqtypes,
|
||||
SQL_PARAMS_NAMED, 'excludedqtype', false);
|
||||
|
||||
$questionidsandcounts = \question_bank::get_finder()->get_questions_from_categories_and_tags_with_usage_counts(
|
||||
$categoryids, $this->qubaids, 'q.qtype ' . $extraconditions, $extraparams, $tagids);
|
||||
if (!$questionidsandcounts) {
|
||||
// No questions in this category.
|
||||
$this->availablequestionscache[$categorykey] = array();
|
||||
return;
|
||||
}
|
||||
|
||||
// Put all the questions with each value of $prevusecount in separate arrays.
|
||||
$idsbyusecount = array();
|
||||
foreach ($questionidsandcounts as $questionid => $prevusecount) {
|
||||
if (isset($this->recentlyusedquestions[$questionid])) {
|
||||
// Recently used questions are never returned.
|
||||
continue;
|
||||
}
|
||||
$idsbyusecount[$prevusecount][] = $questionid;
|
||||
}
|
||||
|
||||
// Now put that data into our cache. For each count, we need to shuffle
|
||||
// questionids, and make those the keys of an array.
|
||||
$this->availablequestionscache[$categorykey] = array();
|
||||
foreach ($idsbyusecount as $prevusecount => $questionids) {
|
||||
shuffle($questionids);
|
||||
$this->availablequestionscache[$categorykey][$prevusecount] = array_combine(
|
||||
$questionids, array_fill(0, count($questionids), 1));
|
||||
}
|
||||
ksort($this->availablequestionscache[$categorykey]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the internal data structures to indicate that a given question has
|
||||
* been used one more time.
|
||||
*
|
||||
* @param int $questionid the question that is being used.
|
||||
*/
|
||||
protected function use_question($questionid) {
|
||||
if (isset($this->recentlyusedquestions[$questionid])) {
|
||||
$this->recentlyusedquestions[$questionid] += 1;
|
||||
} else {
|
||||
$this->recentlyusedquestions[$questionid] = 1;
|
||||
}
|
||||
|
||||
foreach ($this->availablequestionscache as $categorykey => $questionsforcategory) {
|
||||
foreach ($questionsforcategory as $numuses => $questionids) {
|
||||
if (!isset($questionids[$questionid])) {
|
||||
continue;
|
||||
}
|
||||
unset($this->availablequestionscache[$categorykey][$numuses][$questionid]);
|
||||
if (empty($this->availablequestionscache[$categorykey][$numuses])) {
|
||||
unset($this->availablequestionscache[$categorykey][$numuses]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of available question ids for the given criteria.
|
||||
*
|
||||
* @param int $categoryid The id of a category in the question bank.
|
||||
* @param bool $includesubcategories Whether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param array $tagids An array of tag ids. If an array is provided, then
|
||||
* only the questions that are tagged with ALL the provided tagids will be loaded.
|
||||
* @return int[] The list of question ids
|
||||
*/
|
||||
protected function get_question_ids($categoryid, $includesubcategories, $tagids = []) {
|
||||
$this->ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids);
|
||||
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
|
||||
$cachedvalues = $this->availablequestionscache[$categorykey];
|
||||
$questionids = [];
|
||||
|
||||
foreach ($cachedvalues as $usecount => $ids) {
|
||||
$questionids = array_merge($questionids, array_keys($ids));
|
||||
}
|
||||
|
||||
return $questionids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given question is available in a given category. If so, mark it used.
|
||||
* If an optional list of tag ids are provided, then the question must be tagged with
|
||||
* ALL of the provided tags to be considered as available.
|
||||
*
|
||||
* @param int $categoryid the id of a category in the question bank.
|
||||
* @param bool $includesubcategories wether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param int $questionid the question that is being used.
|
||||
* @param array $tagids An array of tag ids. Only the questions that are tagged with all the provided tagids can be available.
|
||||
* @return bool whether the question is available in the requested category.
|
||||
*/
|
||||
public function is_question_available($categoryid, $includesubcategories, $questionid, $tagids = []) {
|
||||
$this->ensure_questions_for_category_loaded($categoryid, $includesubcategories, $tagids);
|
||||
$categorykey = $this->get_category_key($categoryid, $includesubcategories, $tagids);
|
||||
|
||||
foreach ($this->availablequestionscache[$categorykey] as $questionids) {
|
||||
if (isset($questionids[$questionid])) {
|
||||
$this->use_question($questionid);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of available questions for the given criteria.
|
||||
*
|
||||
* @param int $categoryid The id of a category in the question bank.
|
||||
* @param bool $includesubcategories Whether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param array $tagids An array of tag ids. If an array is provided, then
|
||||
* only the questions that are tagged with ALL the provided tagids will be loaded.
|
||||
* @param int $limit Maximum number of results to return.
|
||||
* @param int $offset Number of items to skip from the begging of the result set.
|
||||
* @param string[] $fields The fields to return for each question.
|
||||
* @return \stdClass[] The list of question records
|
||||
*/
|
||||
public function get_questions(
|
||||
$categoryid,
|
||||
$includesubcategories,
|
||||
$tagids = [],
|
||||
$limit = 100,
|
||||
$offset = 0,
|
||||
$fields = []
|
||||
) {
|
||||
global $DB;
|
||||
|
||||
$questionids = $this->get_question_ids($categoryid, $includesubcategories, $tagids);
|
||||
if (empty($questionids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (empty($fields)) {
|
||||
// Return all fields.
|
||||
$fieldsstring = '*';
|
||||
} else {
|
||||
$fieldsstring = implode(',', $fields);
|
||||
}
|
||||
|
||||
return $DB->get_records_list(
|
||||
'question',
|
||||
'id',
|
||||
$questionids,
|
||||
'id',
|
||||
$fieldsstring,
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of available questions for the given criteria.
|
||||
*
|
||||
* @param int $categoryid The id of a category in the question bank.
|
||||
* @param bool $includesubcategories Whether to pick a question from exactly
|
||||
* that category, or that category and subcategories.
|
||||
* @param array $tagids An array of tag ids. If an array is provided, then
|
||||
* only the questions that are tagged with ALL the provided tagids will be loaded.
|
||||
* @return int The number of questions matching the criteria.
|
||||
*/
|
||||
public function count_questions($categoryid, $includesubcategories, $tagids = []) {
|
||||
$questionids = $this->get_question_ids($categoryid, $includesubcategories, $tagids);
|
||||
return count($questionids);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Base class for 'columns' that are actually displayed as a row following the main question row.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Base class for 'columns' that are actually displayed as a row following the main question row.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to core_question/local/bank
|
||||
*/
|
||||
abstract class row_base extends column_base {
|
||||
public function is_extra_row() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function display_start($question, $rowclasses) {
|
||||
if ($rowclasses) {
|
||||
echo '<tr class="' . $rowclasses . '">' . "\n";
|
||||
} else {
|
||||
echo "<tr>\n";
|
||||
}
|
||||
echo '<td colspan="' . $this->qbank->get_column_count() . '" class="' . $this->get_name() . '">';
|
||||
}
|
||||
|
||||
protected function display_end($question, $rowclasses) {
|
||||
echo "</td></tr>\n";
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,10 @@ class category_condition extends condition {
|
||||
true, -1, false);
|
||||
$displaydata['categoryselect'] = \html_writer::select($catmenu, 'category', $this->cat, [],
|
||||
array('class' => 'searchoptions custom-select', 'id' => 'id_selectacategory'));
|
||||
$displaydata['categorydesc'] = $this->print_category_info($this->category);
|
||||
$displaydata['categorydesc'] = '';
|
||||
if ($this->category) {
|
||||
$displaydata['categorydesc'] = $this->print_category_info($this->category);
|
||||
}
|
||||
return $PAGE->get_renderer('core_question', 'bank')->render_category_condition($displaydata);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The question tags column subclass.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2018 Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_question\bank;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Action to add and remove tags to questions.
|
||||
*
|
||||
* @copyright 2018 Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class tags_action_column extends action_column_base implements menuable_action {
|
||||
/**
|
||||
* @var string store this lang string for performance.
|
||||
*/
|
||||
protected $managetags;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
// Removed for conflicting js calls.
|
||||
// ...global $CFG;.
|
||||
// ...if ($CFG->usetags) {.
|
||||
// ...global $PAGE;.
|
||||
// ...$PAGE->requires->js_call_amd('core_question/edit_tags', 'init', ['#questionscontainer']);.
|
||||
// ...}.
|
||||
$this->managetags = get_string('managetags', 'tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name for this column.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'tagsaction';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display tags column content.
|
||||
*
|
||||
* @param object $question The question database record.
|
||||
* @param string $rowclasses
|
||||
*/
|
||||
protected function display_content($question, $rowclasses) {
|
||||
global $OUTPUT;
|
||||
|
||||
if (\core_tag_tag::is_enabled('core_question', 'question') &&
|
||||
question_has_capability_on($question, 'view')) {
|
||||
|
||||
[$url, $attributes] = $this->get_link_url_and_attributes($question);
|
||||
echo \html_writer::link($url, $OUTPUT->pix_icon('t/tags',
|
||||
$this->managetags), $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper used by display_content and get_action_menu_link.
|
||||
*
|
||||
* @param object $question the row from the $question table, augmented with extra information.
|
||||
* @return array with two elements, \moodle_url and
|
||||
* an array or data $attributes needed to make the JavaScript work.
|
||||
*/
|
||||
protected function get_link_url_and_attributes($question) {
|
||||
$url = new \moodle_url($this->qbank->edit_question_url($question->id));
|
||||
|
||||
$attributes = [
|
||||
'data-action' => 'edittags',
|
||||
'data-cantag' => question_has_capability_on($question, 'tag'),
|
||||
'data-contextid' => $this->qbank->get_most_specific_context()->id,
|
||||
'data-questionid' => $question->id
|
||||
];
|
||||
|
||||
return [$url, $attributes];
|
||||
}
|
||||
|
||||
public function get_action_menu_link(\stdClass $question): ?\action_menu_link {
|
||||
if (!\core_tag_tag::is_enabled('core_question', 'question') ||
|
||||
!question_has_capability_on($question, 'view')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$url, $attributes] = $this->get_link_url_and_attributes($question);
|
||||
return new \action_menu_link_secondary($url, new \pix_icon('t/tags', ''),
|
||||
$this->managetags, $attributes);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -170,7 +170,6 @@ class core_question_external extends external_api {
|
||||
}
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/question/type/tags_form.php');
|
||||
|
||||
$cantag = question_has_capability_on($question, 'tag');
|
||||
$questioncontext = \context::instance_by_id($question->contextid);
|
||||
@@ -182,7 +181,7 @@ class core_question_external extends external_api {
|
||||
'contexts' => $contexts->all()
|
||||
];
|
||||
|
||||
$mform = new \core_question\form\tags(null, $formoptions, 'post', '', null, $cantag, $data);
|
||||
$mform = new \qbank_tagquestion\form\tags_form(null, $formoptions, 'post', '', null, $cantag, $data);
|
||||
|
||||
if ($validateddata = $mform->get_data()) {
|
||||
if ($cantag) {
|
||||
|
||||
@@ -51,12 +51,11 @@ class edit_menu_column extends column_base {
|
||||
*
|
||||
* @param column_base[] $allcolumns a set of columns.
|
||||
* @return column_base[] the non-action columns from the set.
|
||||
* @todo MDL-72004 changes for class renaming.
|
||||
*/
|
||||
public function claim_menuable_columns($allcolumns): array {
|
||||
$remainingcolumns = [];
|
||||
foreach ($allcolumns as $key => $column) {
|
||||
if ($column instanceof menuable_action || $column instanceof \core_question\bank\menuable_action) {
|
||||
if ($column instanceof menuable_action) {
|
||||
$this->actions[$key] = $column;
|
||||
} else {
|
||||
$remainingcolumns[$key] = $column;
|
||||
|
||||
@@ -198,7 +198,6 @@ class view {
|
||||
* Get the list of qbank plugins with available objects for features.
|
||||
*
|
||||
* @return array
|
||||
* @todo MDL-72004 changes for class renaming.
|
||||
*/
|
||||
protected function get_question_bank_plugins(): array {
|
||||
$questionbankclasscolumns = [];
|
||||
@@ -223,16 +222,12 @@ class view {
|
||||
|
||||
foreach ($corequestionbankcolumns as $fullname) {
|
||||
$shortname = $fullname;
|
||||
if (!class_exists($fullname)) {
|
||||
if (class_exists('core_question\\local\\bank\\' . $fullname)) {
|
||||
$fullname = 'core_question\\local\\bank\\' . $fullname;
|
||||
} else if (class_exists('core_question\\bank\\' . $fullname)) {
|
||||
$fullname = 'core_question\\bank\\' . $fullname;
|
||||
} else {
|
||||
throw new \coding_exception("No such class exists: $fullname");
|
||||
}
|
||||
if (class_exists('core_question\\local\\bank\\' . $fullname)) {
|
||||
$fullname = 'core_question\\local\\bank\\' . $fullname;
|
||||
$questionbankclasscolumns[$shortname] = new $fullname($this);
|
||||
} else {
|
||||
$questionbankclasscolumns[$shortname] = '';
|
||||
}
|
||||
$questionbankclasscolumns[$shortname] = new $fullname($this);
|
||||
}
|
||||
$plugins = \core_component::get_plugin_list_with_class('qbank', 'plugin_feature', 'plugin_feature.php');
|
||||
foreach ($plugins as $componentname => $plugin) {
|
||||
@@ -271,6 +266,13 @@ class view {
|
||||
$questionbankclasscolumns[$key] = $newpluginclasscolumn;
|
||||
}
|
||||
|
||||
// Mitigate the error in case of any regression.
|
||||
foreach ($questionbankclasscolumns as $shortname => $questionbankclasscolumn) {
|
||||
if (empty($questionbankclasscolumn)){
|
||||
unset($questionbankclasscolumns[$shortname]);
|
||||
}
|
||||
}
|
||||
|
||||
return $questionbankclasscolumns;
|
||||
}
|
||||
|
||||
@@ -278,30 +280,15 @@ class view {
|
||||
* Loads all the available columns.
|
||||
*
|
||||
* @return array
|
||||
* @todo MDL-72004 changes for class renaming.
|
||||
*/
|
||||
protected function wanted_columns(): array {
|
||||
global $CFG;
|
||||
$this->requiredcolumns = [];
|
||||
|
||||
if (empty($CFG->questionbankcolumns)) {
|
||||
$questionbankcolumns = $this->get_question_bank_plugins();
|
||||
foreach ($questionbankcolumns as $classobject) {
|
||||
$this->requiredcolumns[get_class($classobject)] = $classobject;
|
||||
}
|
||||
} else {
|
||||
// Config overrides the array, but uses the deprecated classes.
|
||||
$questionbankcolumns = explode(',', $CFG->questionbankcolumns);
|
||||
foreach ($questionbankcolumns as $fullname) {
|
||||
if (! class_exists($fullname)) {
|
||||
if (class_exists('core_question\\bank\\' . $fullname)) {
|
||||
$fullname = 'core_question\\bank\\' . $fullname;
|
||||
} else {
|
||||
throw new \coding_exception("No such class exists: $fullname");
|
||||
}
|
||||
}
|
||||
$this->requiredcolumns[$fullname] = new $fullname($this);
|
||||
$questionbankcolumns = $this->get_question_bank_plugins();
|
||||
foreach ($questionbankcolumns as $classobject) {
|
||||
if (empty($classobject)) {
|
||||
continue;
|
||||
}
|
||||
$this->requiredcolumns[get_class($classobject)] = $classobject;
|
||||
}
|
||||
|
||||
return $this->requiredcolumns;
|
||||
@@ -333,12 +320,11 @@ class view {
|
||||
*
|
||||
* @param array $wanted Collection of column names
|
||||
* @param string $heading The name of column that is set as heading
|
||||
* @todo MDL-72004 changes for class renaming.
|
||||
*/
|
||||
protected function init_columns($wanted, $heading = ''): void {
|
||||
// If we are using the edit menu column, allow it to absorb all the actions.
|
||||
foreach ($wanted as $column) {
|
||||
if ($column instanceof edit_menu_column || $column instanceof \core_question\bank\edit_menu_column) {
|
||||
if ($column instanceof edit_menu_column) {
|
||||
$wanted = $column->claim_menuable_columns($wanted);
|
||||
break;
|
||||
}
|
||||
@@ -479,20 +465,15 @@ class view {
|
||||
/**
|
||||
* Default sort for question data.
|
||||
* @return int[]
|
||||
* @todo MDL-72004 changes for class renaming.
|
||||
*/
|
||||
protected function default_sort(): array {
|
||||
$defaultsort = [];
|
||||
if (class_exists('\\qbank_viewquestiontype\\question_type_column')) {
|
||||
$sort = 'qbank_viewquestiontype\question_type_column';
|
||||
} else {
|
||||
$sort = 'core_question\bank\question_type_column';
|
||||
}
|
||||
$defaultsort[$sort] = 1;
|
||||
if (class_exists('\\qbank_viewquestionname\\question_name_idnumber_tags_column')) {
|
||||
$sort = 'qbank_viewquestionname\question_name_idnumber_tags_column';
|
||||
} else {
|
||||
$sort = 'core_question\bank\question_name_idnumber_tags_column';
|
||||
}
|
||||
$defaultsort[$sort . '-name'] = 1;
|
||||
|
||||
@@ -544,7 +525,6 @@ class view {
|
||||
/**
|
||||
* Create the SQL query to retrieve the indicated questions, based on
|
||||
* \core_question\bank\search\condition filters.
|
||||
* @todo MDL-72004 changes for class renaming and default sort.
|
||||
*/
|
||||
protected function build_query(): void {
|
||||
// Get the required tables and fields.
|
||||
@@ -878,8 +858,6 @@ class view {
|
||||
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_viewquestiontext')) {
|
||||
echo $PAGE->get_renderer('core_question', 'bank')->render_showtext_checkbox($displaydata);
|
||||
}
|
||||
} else {
|
||||
echo $PAGE->get_renderer('core_question', 'bank')->render_showtext_checkbox($displaydata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,6 +1094,7 @@ class view {
|
||||
*
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see print_table()
|
||||
* @todo Final deprecation of this function in moodle 4.4
|
||||
*/
|
||||
protected function start_table() {
|
||||
debugging('Function start_table() is deprecated, please use print_table() instead.', DEBUG_DEVELOPER);
|
||||
@@ -1131,6 +1110,7 @@ class view {
|
||||
*
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see print_table()
|
||||
* @todo Final deprecation of this function in moodle 4.4
|
||||
*/
|
||||
protected function end_table() {
|
||||
debugging('Function end_table() is deprecated, please use print_table() instead.', DEBUG_DEVELOPER);
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The qbank_chooser renderable.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2016 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use context_course;
|
||||
use core\output\chooser_section;
|
||||
use lang_string;
|
||||
use moodle_url;
|
||||
use question_bank;
|
||||
|
||||
|
||||
/**
|
||||
* The qbank_chooser renderable class.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2016 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see \qbank_editquestion\qbank_chooser
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class qbank_chooser extends \core\output\chooser {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $real The real question types.
|
||||
* @param array $fake The fake question types.
|
||||
* @param stdClass $course The course.
|
||||
* @param array $hiddenparams Hidden parameters.
|
||||
* @param context $context The relevant context.
|
||||
*/
|
||||
public function __construct($real, $fake, $course, $hiddenparams, $context) {
|
||||
$sections = [];
|
||||
$sections[] = new chooser_section('questions', new lang_string('questions', 'question'),
|
||||
array_map(function($qtype) use ($context) {
|
||||
return new qbank_chooser_item($qtype, $context);
|
||||
}, $real));
|
||||
|
||||
if (!empty($fake)) {
|
||||
$sections[] = new chooser_section('other', new lang_string('other'),
|
||||
array_map(function ($qtype) use ($context) {
|
||||
return new qbank_chooser_item($qtype, $context);
|
||||
}, $fake));
|
||||
}
|
||||
|
||||
parent::__construct(new moodle_url('/question/question.php'),
|
||||
new lang_string('chooseqtypetoadd', 'question'), $sections, 'qtype');
|
||||
|
||||
$this->set_instructions(new lang_string('selectaqtypefordescription', 'question'));
|
||||
|
||||
$this->set_method('get');
|
||||
$this->add_param('courseid', $course->id);
|
||||
foreach ($hiddenparams as $k => $v) {
|
||||
$this->add_param($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the question bank chooser.
|
||||
*
|
||||
* @param stdClass $course The course.
|
||||
* @param array $hiddenparams Hidden parameters.
|
||||
* @param array|null $allowedqtypes Allowed question types.
|
||||
* @return qbank_chooser
|
||||
*/
|
||||
public static function get($course, $hiddenparams, array $allowedqtypes = null) {
|
||||
$realqtypes = array();
|
||||
$fakeqtypes = array();
|
||||
|
||||
foreach (question_bank::get_creatable_qtypes() as $qtypename => $qtype) {
|
||||
if ($allowedqtypes && !in_array($qtypename, $allowedqtypes)) {
|
||||
continue;
|
||||
}
|
||||
if ($qtype->is_real_question_type()) {
|
||||
$realqtypes[] = $qtype;
|
||||
} else {
|
||||
$fakeqtypes[] = $qtype;
|
||||
}
|
||||
}
|
||||
|
||||
return new static($realqtypes, $fakeqtypes, $course, $hiddenparams, context_course::instance($course->id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The qbank_chooser_item renderable.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2016 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use lang_string;
|
||||
use pix_icon;
|
||||
|
||||
|
||||
/**
|
||||
* The qbank_chooser_item renderable class.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2016 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see \qbank_editquestion\qbank_chooser_item
|
||||
* @todo MDL-72004 delete the class and add it to lib/db/renameclasses.php pointing to the plugin
|
||||
*/
|
||||
class qbank_chooser_item extends \core\output\chooser_item {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $qtype The question type.
|
||||
* @param context $context The relevant context.
|
||||
*/
|
||||
public function __construct($qtype, $context) {
|
||||
$icon = new pix_icon('icon', $qtype->local_name(), $qtype->plugin_name(), [
|
||||
'class' => 'icon',
|
||||
'title' => $qtype->local_name()
|
||||
]);
|
||||
$help = new lang_string('pluginnamesummary', $qtype->plugin_name());
|
||||
parent::__construct($qtype->plugin_name(), $qtype->menu_name(), $qtype->name(), $icon, $help, $context);
|
||||
}
|
||||
|
||||
}
|
||||
+10
-154
@@ -108,7 +108,7 @@ function question_is_only_child_of_top_category_in_context($categoryid) {
|
||||
has been deprecated and moved to qbank_managecategories plugin,
|
||||
Please use qbank_managecategories\helper::question_is_only_child_of_top_category_in_context() instead.',
|
||||
DEBUG_DEVELOPER);
|
||||
return \qbank_managecategories\helper::question_is_only_child_of_top_category_in_contextt($categoryid);
|
||||
return \qbank_managecategories\helper::question_is_only_child_of_top_category_in_context($categoryid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,151 +140,6 @@ function question_can_delete_cat($todelete) {
|
||||
\qbank_managecategories\helper::question_can_delete_cat($todelete);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for representing a column in a {@see question_bank_view}.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('core_question\local\bank\column_base', 'question_bank_column_base', true);
|
||||
|
||||
/**
|
||||
* A column with a checkbox for each question with name q{questionid}.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('core_question\local\bank\checkbox_column', 'question_bank_checkbox_column', true);
|
||||
|
||||
/**
|
||||
* A column type for the name of the question type.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_viewquestiontype\question_type_column', 'question_bank_question_type_column', true);
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_viewquestionname\viewquestionname_column_helper', 'question_bank_question_name_column', true);
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question creator.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_viewcreator\creator_name_column', 'question_bank_creator_name_column', true);
|
||||
|
||||
|
||||
/**
|
||||
* A column type for the name of the question last modifier.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_viewcreator\modifier_name_column', 'question_bank_modifier_name_column', true);
|
||||
|
||||
|
||||
/**
|
||||
* A base class for actions that are an icon that lets you manipulate the question in some way.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('core_question\local\bank\action_column_base', 'question_bank_action_column_base', true);
|
||||
|
||||
|
||||
/**
|
||||
* Base class for question bank columns that just contain an action icon.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_editquestion\edit_action_column', 'question_bank_edit_action_column', true);
|
||||
|
||||
/**
|
||||
* Question bank column for the duplicate action icon.
|
||||
*
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_editquestion\copy_action_column', 'question_bank_copy_action_column', true);
|
||||
|
||||
/**
|
||||
* Question bank columns for the preview action icon.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_previewquestion\preview_action_column', 'question_bank_preview_action_column', true);
|
||||
|
||||
|
||||
/**
|
||||
* action to delete (or hide) a question, or restore a previously hidden question.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('core_question\bank\delete_action_column', 'question_bank_delete_action_column', true);
|
||||
|
||||
/**
|
||||
* Base class for 'columns' that are actually displayed as a row following the main question row.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('core_question\local\bank\row_base', 'question_bank_row_base', true);
|
||||
|
||||
/**
|
||||
* A column type for the name of the question name.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('qbank_viewquestiontext\question_text_row', 'question_bank_question_text_row', true);
|
||||
|
||||
/**
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 2.7 MDL-40457
|
||||
* @todo MDl-72004 delete the class alias, not done in MDL-71516 for any potential error from other plugins.
|
||||
*/
|
||||
class_alias('core_question\local\bank\view', 'question_bank_view', true);
|
||||
|
||||
/**
|
||||
* Common setup for all pages for editing questions.
|
||||
* @param string $baseurl the name of the script calling this funciton. For examle 'qusetion/edit.php'.
|
||||
@@ -322,7 +177,7 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $unused =
|
||||
$params['qperpage'] = optional_param('qperpage', null, PARAM_INT);
|
||||
|
||||
// Question table sorting options.
|
||||
for ($i = 1; $i <= question_bank_view::MAX_SORTS; $i++) {
|
||||
for ($i = 1; $i <= core_question\local\bank\view::MAX_SORTS; $i++) {
|
||||
$param = 'qbs' . $i;
|
||||
if ($sort = optional_param($param, '', PARAM_TEXT)) {
|
||||
$params[$param] = $sort;
|
||||
@@ -371,7 +226,7 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $unused =
|
||||
* 'qbs1' => PARAM_TEXT,
|
||||
* 'qbs2' => PARAM_TEXT,
|
||||
* 'qbs3' => PARAM_TEXT,
|
||||
* ... and more qbs keys up to question_bank_view::MAX_SORTS ...
|
||||
* ... and more qbs keys up to core_question\local\bank\view::MAX_SORTS ...
|
||||
* ];
|
||||
*
|
||||
* @param string $edittab Code for this edit tab
|
||||
@@ -481,7 +336,7 @@ function question_build_edit_resources($edittab, $baseurl, $params) {
|
||||
// This need to occur after the override_active_url call above because
|
||||
// these values change on the page request causing the URLs to mismatch
|
||||
// when trying to work out the active node.
|
||||
for ($i = 1; $i <= question_bank_view::MAX_SORTS; $i++) {
|
||||
for ($i = 1; $i <= core_question\local\bank\view::MAX_SORTS; $i++) {
|
||||
$param = 'qbs' . $i;
|
||||
if (isset($params[$param])) {
|
||||
$value = clean_param($params[$param], PARAM_TEXT);
|
||||
@@ -637,12 +492,14 @@ function require_login_in_context($contextorid = null){
|
||||
* those qtypes will be shown. Example value array('description', 'multichoice').
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see \qbank_editquestion\editquestion_helper::print_choose_qtype_to_add_form()
|
||||
* @todo MDL-72004 deprecate the function and add debugging message.
|
||||
* @todo Final deprecation of this class in moodle 4.4 MDL-72438
|
||||
*/
|
||||
function print_choose_qtype_to_add_form($hiddenparams, array $allowedqtypes = null, $enablejs = true) {
|
||||
debugging('Function print_choose_qtype_to_add_form() is deprecated,
|
||||
please use \qbank_editquestion\editquestion_helper::print_choose_qtype_to_add_form() instead.', DEBUG_DEVELOPER);
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
|
||||
$chooser = core_question\output\qbank_chooser::get($PAGE->course, $hiddenparams, $allowedqtypes);
|
||||
$chooser = \qbank_editquestion\qbank_chooser::get($PAGE->course, $hiddenparams, $allowedqtypes);
|
||||
$renderer = $PAGE->get_renderer('question', 'bank');
|
||||
|
||||
return $renderer->render($chooser);
|
||||
@@ -661,6 +518,7 @@ function print_choose_qtype_to_add_form($hiddenparams, array $allowedqtypes = nu
|
||||
* @param bool $disabled if true, the button will be disabled.
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see \qbank_editquestion\editquestion_helper::create_new_question_button()
|
||||
* @todo Final deprecation of this class in moodle 4.4 MDL-72438
|
||||
*/
|
||||
function create_new_question_button($categoryid, $params, $caption, $tooltip = '', $disabled = false) {
|
||||
debugging('Function create_new_question_button() has been deprecated and moved to bank/editquestion,
|
||||
@@ -668,7 +526,7 @@ function create_new_question_button($categoryid, $params, $caption, $tooltip = '
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
static $choiceformprinted = false;
|
||||
$params['category'] = $categoryid;
|
||||
$url = new moodle_url('/question/addquestion.php', $params);
|
||||
$url = new moodle_url('/question/bank/editquestion/addquestion.php', $params);
|
||||
echo $OUTPUT->single_button($url, $caption, 'get', array('disabled'=>$disabled, 'title'=>$tooltip));
|
||||
|
||||
if (!$choiceformprinted) {
|
||||
@@ -678,5 +536,3 @@ function create_new_question_button($categoryid, $params, $caption, $tooltip = '
|
||||
$choiceformprinted = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,13 +50,11 @@ class core_question_renderer extends plugin_renderer_base {
|
||||
* If false, just show the icon.
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see qbank_previewquestion\output\renderer
|
||||
* @todo MDL-71679 uncomment the debugging message after implementing the changes in mod_quiz
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
public function question_preview_link($questionid, context $context, $showlabel) {
|
||||
// Debugging message will be re-added after implementing the changes in mod_quiz.
|
||||
// ...debugging('Function question_preview_link() has been deprecated and moved to qbank_previewquestion plugin,
|
||||
// Please use qbank_previewquestion renderer.', DEBUG_DEVELOPER);.
|
||||
debugging('Function question_preview_link() has been deprecated and moved to qbank_previewquestion plugin,
|
||||
Please use qbank_previewquestion renderer.', DEBUG_DEVELOPER);
|
||||
|
||||
return $this->page->get_renderer('qbank_previewquestion')->question_preview_link(
|
||||
$questionid, $context, $showlabel
|
||||
@@ -351,7 +349,7 @@ class core_question_renderer extends plugin_renderer_base {
|
||||
$params['returnurl'] = $params['returnurl']->out_as_local_url(false);
|
||||
}
|
||||
$params['id'] = $qa->get_question_id();
|
||||
$editurl = new moodle_url('/question/question.php', $params);
|
||||
$editurl = new moodle_url('/question/bank/editquestion/question.php', $params);
|
||||
|
||||
return html_writer::tag('div', html_writer::link(
|
||||
$editurl, $this->pix_icon('t/edit', get_string('edit'), '', array('class' => 'iconsmall')) .
|
||||
|
||||
@@ -21,78 +21,7 @@
|
||||
* @subpackage questionbank
|
||||
* @copyright 2007 Jamie Pratt [email protected]
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Form to export questions from the question bank.
|
||||
*
|
||||
* @copyright 2007 Jamie Pratt [email protected]
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71573
|
||||
* @see qbank_exportquestions\form\export_form
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
class question_export_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
debugging('Class question_export_form in \core_question\export_form is deprecated,
|
||||
please use core_question\bank\exportquestions\export_form instead.', DEBUG_DEVELOPER);
|
||||
|
||||
global $OUTPUT;
|
||||
|
||||
$mform = $this->_form;
|
||||
|
||||
$defaultcategory = $this->_customdata['defaultcategory'];
|
||||
$contexts = $this->_customdata['contexts'];
|
||||
|
||||
// Choice of format, with help.
|
||||
$mform->addElement('header', 'fileformat', get_string('fileformat', 'question'));
|
||||
|
||||
$fileformatnames = get_import_export_formats('export');
|
||||
$radioarray = array();
|
||||
$separators = array();
|
||||
foreach ($fileformatnames as $shortname => $fileformatname) {
|
||||
$radioarray[] = $mform->createElement('radio', 'format', '', $fileformatname, $shortname);
|
||||
|
||||
$separator = '';
|
||||
if (get_string_manager()->string_exists('pluginname_help', 'qformat_' . $shortname)) {
|
||||
$separator .= $OUTPUT->help_icon('pluginname', 'qformat_' . $shortname);
|
||||
}
|
||||
$separator .= '<div class="w-100"></div>';
|
||||
$separators[] = $separator;
|
||||
}
|
||||
|
||||
$radioarray[] = $mform->createElement('static', 'makelasthelpiconshowup', '');
|
||||
$mform->addGroup($radioarray, "formatchoices", '', $separators, false);
|
||||
$mform->addRule("formatchoices", null, 'required', null, 'client');
|
||||
|
||||
// Export options.
|
||||
$mform->addElement('header', 'general', get_string('general', 'form'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('exportcategory', 'question'),
|
||||
array('contexts' => $contexts, 'top' => true));
|
||||
$mform->setDefault('category', $defaultcategory);
|
||||
$mform->addHelpButton('category', 'exportcategory', 'question');
|
||||
|
||||
$categorygroup = array();
|
||||
$categorygroup[] = $mform->createElement('checkbox', 'cattofile', '', get_string('tofilecategory', 'question'));
|
||||
$categorygroup[] = $mform->createElement('checkbox', 'contexttofile', '', get_string('tofilecontext', 'question'));
|
||||
$mform->addGroup($categorygroup, 'categorygroup', '', '', false);
|
||||
$mform->disabledIf('categorygroup', 'cattofile', 'notchecked');
|
||||
$mform->setDefault('cattofile', 1);
|
||||
$mform->setDefault('contexttofile', 1);
|
||||
|
||||
// Set a template for the format select elements
|
||||
$renderer = $mform->defaultRenderer();
|
||||
$template = "{help} {element}\n";
|
||||
$renderer->setGroupElementTemplate($template, 'format');
|
||||
|
||||
// Submit buttons.
|
||||
$this->add_action_buttons(false, get_string('exportquestions', 'question'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Stack - http://stack.maths.ed.ac.uk/
|
||||
//
|
||||
// Stack is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Stack is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Stack. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to download the export of a single question.
|
||||
*
|
||||
* @copyright 2015 the Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__.'/../config.php');
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/question/format/xml/format.php');
|
||||
|
||||
// Get the parameters from the URL.
|
||||
$questionid = required_param('id', PARAM_INT);
|
||||
$cmid = optional_param('cmid', 0, PARAM_INT);
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT);
|
||||
$urlparams = ['id' => $questionid, 'sesskey' => sesskey()];
|
||||
|
||||
if ($cmid) {
|
||||
$cm = get_coursemodule_from_id(null, $cmid);
|
||||
require_login($cm->course, false, $cm);
|
||||
$thiscontext = context_module::instance($cmid);
|
||||
$urlparams['cmid'] = $cmid;
|
||||
} else if ($courseid) {
|
||||
require_login($courseid, false);
|
||||
$thiscontext = context_course::instance($courseid);
|
||||
$urlparams['courseid'] = $courseid;
|
||||
} else {
|
||||
print_error('missingcourseorcmid', 'question');
|
||||
}
|
||||
require_sesskey();
|
||||
|
||||
// Load the necessary data.
|
||||
$contexts = new question_edit_contexts($thiscontext);
|
||||
$questiondata = question_bank::load_question_data($questionid);
|
||||
|
||||
// Check permissions.
|
||||
question_require_capability_on($questiondata, 'view');
|
||||
|
||||
// Initialise $PAGE. Nothing is output, so this does not really matter. Just avoids notices.
|
||||
$nexturl = new moodle_url('/question/type/stack/questiontestrun.php', $urlparams);
|
||||
$PAGE->set_url('/question/exportone.php', $urlparams);
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
|
||||
// Set up the export format.
|
||||
$qformat = new qformat_xml();
|
||||
$filename = question_default_export_filename($COURSE, $questiondata) .
|
||||
$qformat->export_file_extension();
|
||||
$qformat->setContexts($contexts->having_one_edit_tab_cap('export'));
|
||||
$qformat->setCourse($COURSE);
|
||||
$qformat->setQuestions([$questiondata]);
|
||||
$qformat->setCattofile(false);
|
||||
$qformat->setContexttofile(false);
|
||||
|
||||
// Do the export.
|
||||
if (!$qformat->exportpreprocess()) {
|
||||
send_file_not_found();
|
||||
}
|
||||
if (!$content = $qformat->exportprocess(true)) {
|
||||
send_file_not_found();
|
||||
}
|
||||
send_file($content, $filename, 0, 0, true, true, $qformat->mime_type());
|
||||
@@ -1,149 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines the import questions form.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->dirroot . '/question/editlib.php');
|
||||
require_once($CFG->dirroot . '/question/import_form.php');
|
||||
require_once($CFG->dirroot . '/question/format.php');
|
||||
|
||||
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) =
|
||||
question_edit_setup('import', '/question/import.php');
|
||||
|
||||
// get display strings
|
||||
$txt = new stdClass();
|
||||
$txt->importerror = get_string('importerror', 'question');
|
||||
$txt->importquestions = get_string('importquestions', 'question');
|
||||
|
||||
list($catid, $catcontext) = explode(',', $pagevars['cat']);
|
||||
if (!$category = $DB->get_record("question_categories", array('id' => $catid))) {
|
||||
print_error('nocategory', 'question');
|
||||
}
|
||||
|
||||
$categorycontext = context::instance_by_id($category->contextid);
|
||||
$category->context = $categorycontext;
|
||||
//this page can be called without courseid or cmid in which case
|
||||
//we get the context from the category object.
|
||||
if ($contexts === null) { // need to get the course from the chosen category
|
||||
$contexts = new question_edit_contexts($categorycontext);
|
||||
$thiscontext = $contexts->lowest();
|
||||
if ($thiscontext->contextlevel == CONTEXT_COURSE){
|
||||
require_login($thiscontext->instanceid, false);
|
||||
} elseif ($thiscontext->contextlevel == CONTEXT_MODULE){
|
||||
list($module, $cm) = get_module_from_cmid($thiscontext->instanceid);
|
||||
require_login($cm->course, false, $cm);
|
||||
}
|
||||
$contexts->require_one_edit_tab_cap($edittab);
|
||||
}
|
||||
|
||||
$PAGE->set_url($thispageurl);
|
||||
|
||||
$import_form = new question_import_form($thispageurl, array('contexts'=>$contexts->having_one_edit_tab_cap('import'),
|
||||
'defaultcategory'=>$pagevars['cat']));
|
||||
|
||||
if ($import_form->is_cancelled()){
|
||||
redirect($thispageurl);
|
||||
}
|
||||
//==========
|
||||
// PAGE HEADER
|
||||
//==========
|
||||
$PAGE->set_title($txt->importquestions);
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Print horizontal nav if needed.
|
||||
$renderer = $PAGE->get_renderer('core_question', 'bank');
|
||||
echo $renderer->extra_horizontal_navigation();
|
||||
|
||||
// file upload form sumitted
|
||||
if ($form = $import_form->get_data()) {
|
||||
|
||||
// file checks out ok
|
||||
$fileisgood = false;
|
||||
|
||||
// work out if this is an uploaded file
|
||||
// or one from the filesarea.
|
||||
$realfilename = $import_form->get_new_filename('newfile');
|
||||
$importfile = make_request_directory() . "/{$realfilename}";
|
||||
if (!$result = $import_form->save_file('newfile', $importfile, true)) {
|
||||
throw new moodle_exception('uploadproblem');
|
||||
}
|
||||
|
||||
$formatfile = 'format/' . $form->format . '/format.php';
|
||||
if (!is_readable($formatfile)) {
|
||||
throw new moodle_exception('formatnotfound', 'question', '', $form->format);
|
||||
}
|
||||
|
||||
require_once($formatfile);
|
||||
|
||||
$classname = 'qformat_' . $form->format;
|
||||
$qformat = new $classname();
|
||||
|
||||
// load data into class
|
||||
$qformat->setCategory($category);
|
||||
$qformat->setContexts($contexts->having_one_edit_tab_cap('import'));
|
||||
$qformat->setCourse($COURSE);
|
||||
$qformat->setFilename($importfile);
|
||||
$qformat->setRealfilename($realfilename);
|
||||
$qformat->setMatchgrades($form->matchgrades);
|
||||
$qformat->setCatfromfile(!empty($form->catfromfile));
|
||||
$qformat->setContextfromfile(!empty($form->contextfromfile));
|
||||
$qformat->setStoponerror($form->stoponerror);
|
||||
|
||||
// Do anything before that we need to
|
||||
if (!$qformat->importpreprocess()) {
|
||||
print_error('cannotimport', '', $thispageurl->out());
|
||||
}
|
||||
|
||||
// Process the uploaded file
|
||||
if (!$qformat->importprocess()) {
|
||||
print_error('cannotimport', '', $thispageurl->out());
|
||||
}
|
||||
|
||||
// In case anything needs to be done after
|
||||
if (!$qformat->importpostprocess()) {
|
||||
print_error('cannotimport', '', $thispageurl->out());
|
||||
}
|
||||
|
||||
// Log the import into this category.
|
||||
$eventparams = [
|
||||
'contextid' => $qformat->category->contextid,
|
||||
'other' => ['format' => $form->format, 'categoryid' => $qformat->category->id],
|
||||
];
|
||||
$event = \core\event\questions_imported::create($eventparams);
|
||||
$event->trigger();
|
||||
|
||||
$params = $thispageurl->params() + array(
|
||||
'category' => $qformat->category->id . ',' . $qformat->category->contextid);
|
||||
echo $OUTPUT->continue_button(new moodle_url('edit.php', $params));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
echo $OUTPUT->heading_with_help($txt->importquestions, 'importquestions', 'question');
|
||||
|
||||
/// Print upload form
|
||||
$import_form->display();
|
||||
echo $OUTPUT->footer();
|
||||
+3
-136
@@ -21,140 +21,7 @@
|
||||
* @subpackage questionbank
|
||||
* @copyright 2007 Jamie Pratt [email protected]
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71585
|
||||
* @see \qbank_importquestions\form\question_import_form
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Form to import questions into the question bank.
|
||||
*
|
||||
* @copyright 2007 Jamie Pratt [email protected]
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_import_form extends moodleform {
|
||||
|
||||
protected function definition() {
|
||||
global $OUTPUT;
|
||||
|
||||
$mform = $this->_form;
|
||||
|
||||
$defaultcategory = $this->_customdata['defaultcategory'];
|
||||
$contexts = $this->_customdata['contexts'];
|
||||
|
||||
// Choice of import format, with help icons.
|
||||
$mform->addElement('header', 'fileformat', get_string('fileformat', 'question'));
|
||||
|
||||
$fileformatnames = get_import_export_formats('import');
|
||||
$radioarray = array();
|
||||
$separators = array();
|
||||
foreach ($fileformatnames as $shortname => $fileformatname) {
|
||||
$radioarray[] = $mform->createElement('radio', 'format', '', $fileformatname, $shortname);
|
||||
|
||||
$separator = '';
|
||||
if (get_string_manager()->string_exists('pluginname_help', 'qformat_' . $shortname)) {
|
||||
$separator .= $OUTPUT->help_icon('pluginname', 'qformat_' . $shortname);
|
||||
}
|
||||
$separator .= '<div class="w-100"></div>';
|
||||
$separators[] = $separator;
|
||||
}
|
||||
|
||||
$radioarray[] = $mform->createElement('static', 'makelasthelpiconshowup', '');
|
||||
$mform->addGroup($radioarray, "formatchoices", '', $separators, false);
|
||||
$mform->addRule("formatchoices", null, 'required', null, 'client');
|
||||
|
||||
// Import options.
|
||||
$mform->addElement('header','general', get_string('general', 'form'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('importcategory', 'question'), compact('contexts'));
|
||||
$mform->setDefault('category', $defaultcategory);
|
||||
$mform->addHelpButton('category', 'importcategory', 'question');
|
||||
|
||||
$categorygroup = array();
|
||||
$categorygroup[] = $mform->createElement('checkbox', 'catfromfile', '', get_string('getcategoryfromfile', 'question'));
|
||||
$categorygroup[] = $mform->createElement('checkbox', 'contextfromfile', '', get_string('getcontextfromfile', 'question'));
|
||||
$mform->addGroup($categorygroup, 'categorygroup', '', '', false);
|
||||
$mform->disabledIf('categorygroup', 'catfromfile', 'notchecked');
|
||||
$mform->setDefault('catfromfile', 1);
|
||||
$mform->setDefault('contextfromfile', 1);
|
||||
|
||||
$matchgrades = array();
|
||||
$matchgrades['error'] = get_string('matchgradeserror', 'question');
|
||||
$matchgrades['nearest'] = get_string('matchgradesnearest', 'question');
|
||||
$mform->addElement('select', 'matchgrades', get_string('matchgrades', 'question'), $matchgrades);
|
||||
$mform->addHelpButton('matchgrades', 'matchgrades', 'question');
|
||||
$mform->setDefault('matchgrades', 'error');
|
||||
|
||||
$mform->addElement('selectyesno', 'stoponerror', get_string('stoponerror', 'question'));
|
||||
$mform->setDefault('stoponerror', 1);
|
||||
$mform->addHelpButton('stoponerror', 'stoponerror', 'question');
|
||||
|
||||
// The file to import
|
||||
$mform->addElement('header', 'importfileupload', get_string('importquestions', 'question'));
|
||||
|
||||
$mform->addElement('filepicker', 'newfile', get_string('import'));
|
||||
$mform->addRule('newfile', null, 'required', null, 'client');
|
||||
|
||||
// Submit button.
|
||||
$mform->addElement('submit', 'submitbutton', get_string('import'));
|
||||
|
||||
// Set a template for the format select elements
|
||||
$renderer = $mform->defaultRenderer();
|
||||
$template = "{help} {element}\n";
|
||||
$renderer->setGroupElementTemplate($template, 'format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a file has been uploaded, and that it is of a plausible type.
|
||||
* @param array $data the submitted data.
|
||||
* @param array $errors the errors so far.
|
||||
* @return array the updated errors.
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
protected function validate_uploaded_file($data, $errors) {
|
||||
if (empty($data['newfile'])) {
|
||||
$errors['newfile'] = get_string('required');
|
||||
return $errors;
|
||||
}
|
||||
|
||||
$files = $this->get_draft_files('newfile');
|
||||
if (!is_array($files) || count($files) < 1) {
|
||||
$errors['newfile'] = get_string('required');
|
||||
return $errors;
|
||||
}
|
||||
|
||||
if (empty($data['format'])) {
|
||||
$errors['format'] = get_string('required');
|
||||
return $errors;
|
||||
}
|
||||
|
||||
$formatfile = 'format/' . $data['format'] . '/format.php';
|
||||
if (!is_readable($formatfile)) {
|
||||
throw new moodle_exception('formatnotfound', 'question', '', $data['format']);
|
||||
}
|
||||
|
||||
require_once($formatfile);
|
||||
|
||||
$classname = 'qformat_' . $data['format'];
|
||||
$qformat = new $classname();
|
||||
|
||||
$file = reset($files);
|
||||
if (!$qformat->can_import_file($file)) {
|
||||
$a = new stdClass();
|
||||
$a->actualtype = $file->get_mimetype();
|
||||
$a->expectedtype = $qformat->mime_type();
|
||||
$errors['newfile'] = get_string('importwrongfiletype', 'question', $a);
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
$errors = $this->validate_uploaded_file($data, $errors);
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -43,7 +43,6 @@ function core_question_output_fragment_tags_form($args) {
|
||||
|
||||
if (!empty($args['id'])) {
|
||||
global $CFG, $DB;
|
||||
require_once($CFG->dirroot . '/question/type/tags_form.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
$id = clean_param($args['id'], PARAM_INT);
|
||||
$editingcontext = $args['context'];
|
||||
@@ -88,7 +87,7 @@ function core_question_output_fragment_tags_form($args) {
|
||||
];
|
||||
|
||||
$cantag = question_has_capability_on($question, 'tag');
|
||||
$mform = new \core_question\form\tags(null, $formoptions, 'post', '', null, $cantag, $data);
|
||||
$mform = new \qbank_tagquestion\form\tags_form(null, $formoptions, 'post', '', null, $cantag, $data);
|
||||
$mform->set_data($data);
|
||||
|
||||
return $mform->render();
|
||||
|
||||
+1
-31
@@ -21,37 +21,7 @@
|
||||
* @subpackage questionbank
|
||||
* @copyright 2008 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Form for moving questions between categories.
|
||||
*
|
||||
* @copyright 2008 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0 MDL-71585
|
||||
* @see qbank_managecategories\form\question_move_form
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
class question_move_form extends moodleform {
|
||||
protected function definition() {
|
||||
debugging('Class question_move_form in \core_question\move_form is deprecated,
|
||||
please use qbank_managecategories\form\question_move_form instead.', DEBUG_DEVELOPER);
|
||||
|
||||
$mform = $this->_form;
|
||||
|
||||
$currentcat = $this->_customdata['currentcat'];
|
||||
$contexts = $this->_customdata['contexts'];
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category', 'question'), compact('contexts', 'currentcat'));
|
||||
|
||||
$this->add_action_buttons(true, get_string('categorymoveto', 'question'));
|
||||
|
||||
$mform->addElement('hidden', 'delete', $currentcat);
|
||||
$mform->setType('delete', PARAM_INT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This page displays a preview of a question
|
||||
*
|
||||
* The preview uses the option settings from the activity within which the question
|
||||
* is previewed or the default settings if no activity is specified. The question session
|
||||
* information is stored in the session as an array of subsequent states rather
|
||||
* than in the database.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionengine
|
||||
* @copyright Alex Smith {@link http://maths.york.ac.uk/serving_maths} and
|
||||
* numerous contributors.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once(__DIR__ . '/previewlib.php');
|
||||
|
||||
/**
|
||||
* The maximum number of variants previewable. If there are more variants than this for a question
|
||||
* then we only allow the selection of the first x variants.
|
||||
* @var integer
|
||||
*/
|
||||
define('QUESTION_PREVIEW_MAX_VARIANTS', 100);
|
||||
|
||||
// Get and validate question id.
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$question = question_bank::load_question($id);
|
||||
|
||||
// Were we given a particular context to run the question in?
|
||||
// This affects things like filter settings, or forced theme or language.
|
||||
if ($cmid = optional_param('cmid', 0, PARAM_INT)) {
|
||||
$cm = get_coursemodule_from_id(false, $cmid);
|
||||
require_login($cm->course, false, $cm);
|
||||
$context = context_module::instance($cmid);
|
||||
|
||||
} else if ($courseid = optional_param('courseid', 0, PARAM_INT)) {
|
||||
require_login($courseid);
|
||||
$context = context_course::instance($courseid);
|
||||
|
||||
} else {
|
||||
require_login();
|
||||
$category = $DB->get_record('question_categories',
|
||||
array('id' => $question->category), '*', MUST_EXIST);
|
||||
$context = context::instance_by_id($category->contextid);
|
||||
$PAGE->set_context($context);
|
||||
// Note that in the other cases, require_login will set the correct page context.
|
||||
}
|
||||
question_require_capability_on($question, 'use');
|
||||
$PAGE->set_pagelayout('popup');
|
||||
|
||||
// Get and validate display options.
|
||||
$maxvariant = min($question->get_num_variants(), QUESTION_PREVIEW_MAX_VARIANTS);
|
||||
$options = new qbank_previewquestion\question_preview_options($question);
|
||||
$options->load_user_defaults();
|
||||
$options->set_from_request();
|
||||
$PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark,
|
||||
$options, $options->variant, $context));
|
||||
|
||||
// Get and validate existing preview, or start a new one.
|
||||
$previewid = optional_param('previewid', 0, PARAM_INT);
|
||||
|
||||
if ($previewid) {
|
||||
try {
|
||||
$quba = question_engine::load_questions_usage_by_activity($previewid);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// This may not seem like the right error message to display, but
|
||||
// actually from the user point of view, it makes sense.
|
||||
print_error('submissionoutofsequencefriendlymessage', 'question',
|
||||
question_preview_url($question->id, $options->behaviour,
|
||||
$options->maxmark, $options, $options->variant, $context), null, $e);
|
||||
}
|
||||
|
||||
if ($quba->get_owning_context()->instanceid != $USER->id) {
|
||||
print_error('notyourpreview', 'question');
|
||||
}
|
||||
|
||||
$slot = $quba->get_first_question_number();
|
||||
$usedquestion = $quba->get_question($slot, false);
|
||||
if ($usedquestion->id != $question->id) {
|
||||
print_error('questionidmismatch', 'question');
|
||||
}
|
||||
$question = $usedquestion;
|
||||
$options->variant = $quba->get_variant($slot);
|
||||
|
||||
} else {
|
||||
$quba = question_engine::make_questions_usage_by_activity(
|
||||
'core_question_preview', context_user::instance($USER->id));
|
||||
$quba->set_preferred_behaviour($options->behaviour);
|
||||
$slot = $quba->add_question($question, $options->maxmark);
|
||||
|
||||
if ($options->variant) {
|
||||
$options->variant = min($maxvariant, max(1, $options->variant));
|
||||
} else {
|
||||
$options->variant = rand(1, $maxvariant);
|
||||
}
|
||||
|
||||
$quba->start_question($slot, $options->variant);
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
question_engine::save_questions_usage_by_activity($quba);
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
$options->behaviour = $quba->get_preferred_behaviour();
|
||||
$options->maxmark = $quba->get_question_max_mark($slot);
|
||||
|
||||
// Create the settings form, and initialise the fields.
|
||||
$optionsform = new preview_options_form(question_preview_form_url($question->id, $context, $previewid),
|
||||
array('quba' => $quba, 'maxvariant' => $maxvariant));
|
||||
$optionsform->set_data($options);
|
||||
|
||||
// Process change of settings, if that was requested.
|
||||
if ($newoptions = $optionsform->get_submitted_data()) {
|
||||
// Set user preferences.
|
||||
$options->save_user_preview_options($newoptions);
|
||||
if (!isset($newoptions->variant)) {
|
||||
$newoptions->variant = $options->variant;
|
||||
}
|
||||
if (isset($newoptions->saverestart)) {
|
||||
qbank_previewquestion\helper::restart_preview($previewid, $question->id, $newoptions, $context);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare a URL that is used in various places.
|
||||
$actionurl = question_preview_action_url($question->id, $quba->get_id(), $options, $context);
|
||||
|
||||
// Process any actions from the buttons at the bottom of the form.
|
||||
if (data_submitted() && confirm_sesskey()) {
|
||||
|
||||
try {
|
||||
|
||||
if (optional_param('restart', false, PARAM_BOOL)) {
|
||||
qbank_previewquestion\helper::restart_preview($previewid, $question->id, $options, $context);
|
||||
|
||||
} else if (optional_param('fill', null, PARAM_BOOL)) {
|
||||
$correctresponse = $quba->get_correct_response($slot);
|
||||
if (!is_null($correctresponse)) {
|
||||
$quba->process_action($slot, $correctresponse);
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
question_engine::save_questions_usage_by_activity($quba);
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
redirect($actionurl);
|
||||
|
||||
} else if (optional_param('finish', null, PARAM_BOOL)) {
|
||||
$quba->process_all_actions();
|
||||
$quba->finish_all_questions();
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
question_engine::save_questions_usage_by_activity($quba);
|
||||
$transaction->allow_commit();
|
||||
redirect($actionurl);
|
||||
|
||||
} else {
|
||||
$quba->process_all_actions();
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
question_engine::save_questions_usage_by_activity($quba);
|
||||
$transaction->allow_commit();
|
||||
|
||||
$scrollpos = optional_param('scrollpos', '', PARAM_RAW);
|
||||
if ($scrollpos !== '') {
|
||||
$actionurl->param('scrollpos', (int) $scrollpos);
|
||||
}
|
||||
redirect($actionurl);
|
||||
}
|
||||
|
||||
} catch (question_out_of_sequence_exception $e) {
|
||||
print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// This sucks, if we display our own custom error message, there is no way
|
||||
// to display the original stack trace.
|
||||
$debuginfo = '';
|
||||
if (!empty($e->debuginfo)) {
|
||||
$debuginfo = $e->debuginfo;
|
||||
}
|
||||
print_error('errorprocessingresponses', 'question', $actionurl,
|
||||
$e->getMessage(), $debuginfo);
|
||||
}
|
||||
}
|
||||
|
||||
if ($question->length) {
|
||||
$displaynumber = '1';
|
||||
} else {
|
||||
$displaynumber = 'i';
|
||||
}
|
||||
$restartdisabled = array();
|
||||
$finishdisabled = array();
|
||||
$filldisabled = array();
|
||||
if ($quba->get_question_state($slot)->is_finished()) {
|
||||
$finishdisabled = array('disabled' => 'disabled');
|
||||
$filldisabled = array('disabled' => 'disabled');
|
||||
}
|
||||
// If question type cannot give us a correct response, disable this button.
|
||||
if (is_null($quba->get_correct_response($slot))) {
|
||||
$filldisabled = array('disabled' => 'disabled');
|
||||
}
|
||||
if (!$previewid) {
|
||||
$restartdisabled = array('disabled' => 'disabled');
|
||||
}
|
||||
|
||||
// Prepare technical info to be output.
|
||||
$qa = $quba->get_question_attempt($slot);
|
||||
$technical = array();
|
||||
$technical[] = get_string('behaviourbeingused', 'question',
|
||||
question_engine::get_behaviour_name($qa->get_behaviour_name()));
|
||||
$technical[] = get_string('technicalinfominfraction', 'question', $qa->get_min_fraction());
|
||||
$technical[] = get_string('technicalinfomaxfraction', 'question', $qa->get_max_fraction());
|
||||
$technical[] = get_string('technicalinfovariant', 'question', $qa->get_variant());
|
||||
$technical[] = get_string('technicalinfoquestionsummary', 'question', s($qa->get_question_summary()));
|
||||
$technical[] = get_string('technicalinforightsummary', 'question', s($qa->get_right_answer_summary()));
|
||||
$technical[] = get_string('technicalinforesponsesummary', 'question', s($qa->get_response_summary()));
|
||||
$technical[] = get_string('technicalinfostate', 'question', '' . $qa->get_state());
|
||||
|
||||
// Start output.
|
||||
$title = get_string('previewquestion', 'question', format_string($question->name));
|
||||
$headtags = question_engine::initialise_js() . $quba->render_question_head_html($slot);
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($title);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Start the question form.
|
||||
echo html_writer::start_tag('form', array('method' => 'post', 'action' => $actionurl,
|
||||
'enctype' => 'multipart/form-data', 'id' => 'responseform'));
|
||||
echo html_writer::start_tag('div');
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'slots', 'value' => $slot));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'scrollpos', 'value' => '', 'id' => 'scrollpos'));
|
||||
echo html_writer::end_tag('div');
|
||||
|
||||
// Output the question.
|
||||
echo $quba->render_question($slot, $options, $displaynumber);
|
||||
|
||||
// Finish the question form.
|
||||
echo html_writer::start_tag('div', array('id' => 'previewcontrols', 'class' => 'controls'));
|
||||
echo html_writer::empty_tag('input', $restartdisabled + array('type' => 'submit',
|
||||
'name' => 'restart', 'value' => get_string('restart', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1'));
|
||||
echo html_writer::empty_tag('input', $finishdisabled + array('type' => 'submit',
|
||||
'name' => 'save', 'value' => get_string('save', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1',
|
||||
'id' => 'id_save_question_preview'));
|
||||
echo html_writer::empty_tag('input', $filldisabled + array('type' => 'submit',
|
||||
'name' => 'fill', 'value' => get_string('fillincorrect', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1'));
|
||||
echo html_writer::empty_tag('input', $finishdisabled + array('type' => 'submit',
|
||||
'name' => 'finish', 'value' => get_string('submitandfinish', 'question'), 'class' => 'btn btn-secondary mr-1 mb-1',
|
||||
'id' => 'id_finish_question_preview'));
|
||||
echo html_writer::end_tag('div');
|
||||
echo html_writer::end_tag('form');
|
||||
|
||||
// Output the technical info.
|
||||
print_collapsible_region_start('', 'techinfo', get_string('technicalinfo', 'question'),
|
||||
'core_question_preview_techinfo_collapsed', true, false, $OUTPUT->help_icon('technicalinfo', 'question'));
|
||||
foreach ($technical as $info) {
|
||||
echo html_writer::tag('p', $info, array('class' => 'notifytiny'));
|
||||
}
|
||||
print_collapsible_region_end();
|
||||
|
||||
// Output a link to export this single question.
|
||||
if (question_has_capability_on($question, 'view')) {
|
||||
if (class_exists('qbank_exporttoxml\\helper')) {
|
||||
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_exporttoxml')) {
|
||||
$exportfunction = '\\qbank_exporttoxml\\helper::question_get_export_single_question_url';
|
||||
echo html_writer::link($exportfunction($question),
|
||||
get_string('exportonequestion', 'question'));
|
||||
}
|
||||
} else {
|
||||
$exportfunction = 'question_get_export_single_question_url';
|
||||
echo html_writer::link($exportfunction($question),
|
||||
get_string('exportonequestion', 'question'));
|
||||
}
|
||||
}
|
||||
|
||||
// Log the preview of this question.
|
||||
$event = \core\event\question_viewed::create_from_question_instance($question, $context);
|
||||
$event->trigger();
|
||||
|
||||
// Display the settings form.
|
||||
$optionsform->display();
|
||||
|
||||
$PAGE->requires->js_module('core_question_engine');
|
||||
$PAGE->requires->strings_for_js(array(
|
||||
'closepreview',
|
||||
), 'question');
|
||||
$PAGE->requires->yui_module('moodle-question-preview', 'M.question.preview.init');
|
||||
$PAGE->requires->js_call_amd('core_form/submit', 'init', ['id_save_question_preview']);
|
||||
$PAGE->requires->js_call_amd('core_form/submit', 'init', ['id_finish_question_preview']);
|
||||
echo $OUTPUT->footer();
|
||||
+1
-200
@@ -21,211 +21,12 @@
|
||||
* @subpackage questionengine
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Settings form for the preview options.
|
||||
*
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see qbank_previewquestion\form\preview_options_form
|
||||
* @todo MDL-71679 class renaming
|
||||
*/
|
||||
class preview_options_form extends moodleform {
|
||||
|
||||
public function definition() {
|
||||
debugging('Class preview_options_form has been deprecated and moved to qbank_previewquestion plugin,
|
||||
please use qbank_previewquestion\form\preview_options_form instead.', DEBUG_DEVELOPER);
|
||||
$mform = $this->_form;
|
||||
|
||||
$hiddenofvisible = array(
|
||||
question_display_options::HIDDEN => get_string('notshown', 'question'),
|
||||
question_display_options::VISIBLE => get_string('shown', 'question'),
|
||||
);
|
||||
|
||||
$mform->addElement('header', 'attemptoptionsheader', get_string('attemptoptions', 'question'));
|
||||
|
||||
$behaviours = question_engine::get_behaviour_options(
|
||||
$this->_customdata['quba']->get_preferred_behaviour());
|
||||
$mform->addElement('select', 'behaviour',
|
||||
get_string('howquestionsbehave', 'question'), $behaviours);
|
||||
$mform->addHelpButton('behaviour', 'howquestionsbehave', 'question');
|
||||
|
||||
$mform->addElement('float', 'maxmark', get_string('markedoutof', 'question'),
|
||||
array('size' => '5'));
|
||||
|
||||
if ($this->_customdata['maxvariant'] > 1) {
|
||||
$variants = range(1, $this->_customdata['maxvariant']);
|
||||
$mform->addElement('select', 'variant', get_string('questionvariant', 'question'),
|
||||
array_combine($variants, $variants));
|
||||
}
|
||||
$mform->setType('variant', PARAM_INT);
|
||||
|
||||
$mform->addElement('submit', 'saverestart',
|
||||
get_string('restartwiththeseoptions', 'question'));
|
||||
|
||||
$mform->addElement('header', 'displayoptionsheader', get_string('displayoptions', 'question'));
|
||||
|
||||
$mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'),
|
||||
$hiddenofvisible);
|
||||
|
||||
$marksoptions = array(
|
||||
question_display_options::HIDDEN => get_string('notshown', 'question'),
|
||||
question_display_options::MAX_ONLY => get_string('showmaxmarkonly', 'question'),
|
||||
question_display_options::MARK_AND_MAX => get_string('showmarkandmax', 'question'),
|
||||
);
|
||||
$mform->addElement('select', 'marks', get_string('marks', 'question'), $marksoptions);
|
||||
|
||||
$mform->addElement('select', 'markdp', get_string('decimalplacesingrades', 'question'),
|
||||
question_engine::get_dp_options());
|
||||
|
||||
$mform->addElement('select', 'feedback',
|
||||
get_string('specificfeedback', 'question'), $hiddenofvisible);
|
||||
|
||||
$mform->addElement('select', 'generalfeedback',
|
||||
get_string('generalfeedback', 'question'), $hiddenofvisible);
|
||||
|
||||
$mform->addElement('select', 'rightanswer',
|
||||
get_string('rightanswer', 'question'), $hiddenofvisible);
|
||||
|
||||
$mform->addElement('select', 'history',
|
||||
get_string('responsehistory', 'question'), $hiddenofvisible);
|
||||
|
||||
$mform->addElement('submit', 'saveupdate',
|
||||
get_string('updatedisplayoptions', 'question'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays question preview options as default and set the options.
|
||||
*
|
||||
* Setting default, getting and setting user preferences in question preview options.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see qbank_previewquestion\output\question_preview_options
|
||||
* @todo MDL-71679 class renaming
|
||||
*/
|
||||
class question_preview_options extends question_display_options {
|
||||
/** @var string the behaviour to use for this preview. */
|
||||
public $behaviour;
|
||||
|
||||
/** @var number the maximum mark to use for this preview. */
|
||||
public $maxmark;
|
||||
|
||||
/** @var int the variant of the question to preview. */
|
||||
public $variant;
|
||||
|
||||
/** @var string prefix to append to field names to get user_preference names. */
|
||||
const OPTIONPREFIX = 'question_preview_options_';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param stdClass $question
|
||||
*/
|
||||
public function __construct($question) {
|
||||
debugging('Class question_preview_options has been deprecated and moved to qbank_previewquestion plugin,
|
||||
please use qbank_previewquestion\question_preview_options instead.', DEBUG_DEVELOPER);
|
||||
$this->behaviour = 'deferredfeedback';
|
||||
$this->maxmark = $question->defaultmark;
|
||||
$this->variant = null;
|
||||
$this->correctness = self::VISIBLE;
|
||||
$this->marks = self::MARK_AND_MAX;
|
||||
$this->markdp = get_config('quiz', 'decimalpoints');
|
||||
$this->feedback = self::VISIBLE;
|
||||
$this->numpartscorrect = $this->feedback;
|
||||
$this->generalfeedback = self::VISIBLE;
|
||||
$this->rightanswer = self::VISIBLE;
|
||||
$this->history = self::HIDDEN;
|
||||
$this->flags = self::HIDDEN;
|
||||
$this->manualcomment = self::HIDDEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array names of the options we store in the user preferences table.
|
||||
*/
|
||||
protected function get_user_pref_fields() {
|
||||
return array('behaviour', 'correctness', 'marks', 'markdp', 'feedback',
|
||||
'generalfeedback', 'rightanswer', 'history');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array names and param types of the options we read from the request.
|
||||
*/
|
||||
protected function get_field_types() {
|
||||
return array(
|
||||
'behaviour' => PARAM_ALPHA,
|
||||
'maxmark' => PARAM_LOCALISEDFLOAT,
|
||||
'variant' => PARAM_INT,
|
||||
'correctness' => PARAM_BOOL,
|
||||
'marks' => PARAM_INT,
|
||||
'markdp' => PARAM_INT,
|
||||
'feedback' => PARAM_BOOL,
|
||||
'generalfeedback' => PARAM_BOOL,
|
||||
'rightanswer' => PARAM_BOOL,
|
||||
'history' => PARAM_BOOL,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the value of the options from the user_preferences table.
|
||||
*/
|
||||
public function load_user_defaults() {
|
||||
$defaults = get_config('question_preview');
|
||||
foreach ($this->get_user_pref_fields() as $field) {
|
||||
$this->$field = get_user_preferences(
|
||||
self::OPTIONPREFIX . $field, $defaults->$field);
|
||||
}
|
||||
$this->numpartscorrect = $this->feedback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a change to the user's preview options to the database.
|
||||
* @param object $newoptions
|
||||
*/
|
||||
public function save_user_preview_options($newoptions) {
|
||||
foreach ($this->get_user_pref_fields() as $field) {
|
||||
if (isset($newoptions->$field)) {
|
||||
set_user_preference(self::OPTIONPREFIX . $field, $newoptions->$field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of any fields included in the request.
|
||||
*/
|
||||
public function set_from_request() {
|
||||
foreach ($this->get_field_types() as $field => $type) {
|
||||
$this->$field = optional_param($field, $this->$field, $type);
|
||||
}
|
||||
$this->numpartscorrect = $this->feedback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string URL fragment. Parameters needed in the URL when continuing
|
||||
* this preview.
|
||||
*/
|
||||
public function get_url_params() {
|
||||
$params = array();
|
||||
foreach ($this->get_field_types() as $field => $notused) {
|
||||
if ($field == 'behaviour' || $field == 'maxmark' || is_null($this->$field)) {
|
||||
continue;
|
||||
}
|
||||
$params[$field] = $this->$field;
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
|
||||
use qbank_previewquestion\question_preview_options;
|
||||
|
||||
/**
|
||||
* Called via pluginfile.php -> question_pluginfile to serve files belonging to
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Page for editing questions.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once(__DIR__ . '/editlib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
// Read URL parameters telling us which question to edit.
|
||||
$id = optional_param('id', 0, PARAM_INT); // question id
|
||||
$makecopy = optional_param('makecopy', 0, PARAM_BOOL);
|
||||
$qtype = optional_param('qtype', '', PARAM_COMPONENT);
|
||||
$categoryid = optional_param('category', 0, PARAM_INT);
|
||||
$cmid = optional_param('cmid', 0, PARAM_INT);
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT);
|
||||
$wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
|
||||
$originalreturnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
|
||||
$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
|
||||
$inpopup = optional_param('inpopup', 0, PARAM_BOOL);
|
||||
$scrollpos = optional_param('scrollpos', 0, PARAM_INT);
|
||||
|
||||
$url = new moodle_url('/question/question.php');
|
||||
if ($id !== 0) {
|
||||
$url->param('id', $id);
|
||||
}
|
||||
if ($makecopy) {
|
||||
$url->param('makecopy', $makecopy);
|
||||
}
|
||||
if ($qtype !== '') {
|
||||
$url->param('qtype', $qtype);
|
||||
}
|
||||
if ($categoryid !== 0) {
|
||||
$url->param('category', $categoryid);
|
||||
}
|
||||
if ($cmid !== 0) {
|
||||
$url->param('cmid', $cmid);
|
||||
}
|
||||
if ($courseid !== 0) {
|
||||
$url->param('courseid', $courseid);
|
||||
}
|
||||
if ($wizardnow !== '') {
|
||||
$url->param('wizardnow', $wizardnow);
|
||||
}
|
||||
if ($originalreturnurl !== 0) {
|
||||
$url->param('returnurl', $originalreturnurl);
|
||||
}
|
||||
if ($appendqnumstring !== '') {
|
||||
$url->param('appendqnumstring', $appendqnumstring);
|
||||
}
|
||||
if ($inpopup !== 0) {
|
||||
$url->param('inpopup', $inpopup);
|
||||
}
|
||||
if ($scrollpos) {
|
||||
$url->param('scrollpos', $scrollpos);
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if ($cmid) {
|
||||
$questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
|
||||
} else {
|
||||
$questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
|
||||
}
|
||||
navigation_node::override_active_url($questionbankurl);
|
||||
|
||||
if ($originalreturnurl) {
|
||||
if (strpos($originalreturnurl, '/') !== 0) {
|
||||
throw new coding_exception("returnurl must be a local URL starting with '/'. $originalreturnurl was given.");
|
||||
}
|
||||
$returnurl = new moodle_url($originalreturnurl);
|
||||
} else {
|
||||
$returnurl = $questionbankurl;
|
||||
}
|
||||
if ($scrollpos) {
|
||||
$returnurl->param('scrollpos', $scrollpos);
|
||||
}
|
||||
|
||||
if ($cmid){
|
||||
list($module, $cm) = get_module_from_cmid($cmid);
|
||||
require_login($cm->course, false, $cm);
|
||||
$thiscontext = context_module::instance($cmid);
|
||||
} elseif ($courseid) {
|
||||
require_login($courseid, false);
|
||||
$thiscontext = context_course::instance($courseid);
|
||||
$module = null;
|
||||
$cm = null;
|
||||
} else {
|
||||
print_error('missingcourseorcmid', 'question');
|
||||
}
|
||||
$contexts = new question_edit_contexts($thiscontext);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
|
||||
if (optional_param('addcancel', false, PARAM_BOOL)) {
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
if (!$question = $DB->get_record('question', array('id' => $id))) {
|
||||
print_error('questiondoesnotexist', 'question', $returnurl);
|
||||
}
|
||||
// We can use $COURSE here because it's been initialised as part of the
|
||||
// require_login above. Passing it as the third parameter tells the function
|
||||
// to filter the course tags by that course.
|
||||
get_question_options($question, true, [$COURSE]);
|
||||
|
||||
} else if ($categoryid && $qtype) { // only for creating new questions
|
||||
$question = new stdClass();
|
||||
$question->category = $categoryid;
|
||||
$question->qtype = $qtype;
|
||||
$question->createdby = $USER->id;
|
||||
|
||||
// Check that users are allowed to create this question type at the moment.
|
||||
if (!question_bank::qtype_enabled($qtype)) {
|
||||
print_error('cannotenable', 'question', $returnurl, $qtype);
|
||||
}
|
||||
|
||||
} else if ($categoryid) {
|
||||
// Category, but no qtype. They probably came from the addquestion.php
|
||||
// script without choosing a question type. Send them back.
|
||||
$addurl = new moodle_url('/question/addquestion.php', $url->params());
|
||||
$addurl->param('validationerror', 1);
|
||||
redirect($addurl);
|
||||
|
||||
} else {
|
||||
print_error('notenoughdatatoeditaquestion', 'question', $returnurl);
|
||||
}
|
||||
|
||||
$qtypeobj = question_bank::get_qtype($question->qtype);
|
||||
|
||||
if (isset($question->categoryobject)) {
|
||||
$category = $question->categoryobject;
|
||||
} else {
|
||||
// Validate the question category.
|
||||
if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
|
||||
print_error('categorydoesnotexist', 'question', $returnurl);
|
||||
}
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
$question->formoptions = new stdClass();
|
||||
|
||||
$categorycontext = context::instance_by_id($category->contextid);
|
||||
$question->contextid = $category->contextid;
|
||||
$addpermission = has_capability('moodle/question:add', $categorycontext);
|
||||
|
||||
if ($id) {
|
||||
$question->formoptions->canedit = question_has_capability_on($question, 'edit');
|
||||
$question->formoptions->canmove = $addpermission && question_has_capability_on($question, 'move');
|
||||
$question->formoptions->cansaveasnew = $addpermission &&
|
||||
(question_has_capability_on($question, 'view') || $question->formoptions->canedit);
|
||||
$question->formoptions->repeatelements = $question->formoptions->canedit || $question->formoptions->cansaveasnew;
|
||||
$formeditable = $question->formoptions->canedit || $question->formoptions->cansaveasnew || $question->formoptions->canmove;
|
||||
if (!$formeditable) {
|
||||
question_require_capability_on($question, 'view');
|
||||
}
|
||||
if ($makecopy) {
|
||||
// If we are duplicating a question, add some indication to the question name.
|
||||
$question->name = get_string('questionnamecopy', 'question', $question->name);
|
||||
$question->idnumber = core_question_find_next_unused_idnumber($question->idnumber, $category->id);
|
||||
$question->beingcopied = true;
|
||||
}
|
||||
|
||||
} else { // creating a new question
|
||||
$question->formoptions->canedit = question_has_capability_on($question, 'edit');
|
||||
$question->formoptions->canmove = (question_has_capability_on($question, 'move') && $addpermission);
|
||||
$question->formoptions->cansaveasnew = false;
|
||||
$question->formoptions->repeatelements = true;
|
||||
$formeditable = true;
|
||||
require_capability('moodle/question:add', $categorycontext);
|
||||
}
|
||||
$question->formoptions->mustbeusable = (bool) $appendqnumstring;
|
||||
|
||||
// Validate the question type.
|
||||
$PAGE->set_pagetype('question-type-' . $question->qtype);
|
||||
|
||||
// Create the question editing form.
|
||||
if ($wizardnow !== '') {
|
||||
$mform = $qtypeobj->next_wizard_form('question.php', $question, $wizardnow, $formeditable);
|
||||
} else {
|
||||
$mform = $qtypeobj->create_editing_form('question.php', $question, $category, $contexts, $formeditable);
|
||||
}
|
||||
$toform = fullclone($question); // send the question object and a few more parameters to the form
|
||||
$toform->category = "{$category->id},{$category->contextid}";
|
||||
$toform->scrollpos = $scrollpos;
|
||||
if ($formeditable && $id){
|
||||
$toform->categorymoveto = $toform->category;
|
||||
}
|
||||
|
||||
$toform->appendqnumstring = $appendqnumstring;
|
||||
$toform->returnurl = $originalreturnurl;
|
||||
$toform->makecopy = $makecopy;
|
||||
if ($cm !== null){
|
||||
$toform->cmid = $cm->id;
|
||||
$toform->courseid = $cm->course;
|
||||
} else {
|
||||
$toform->courseid = $COURSE->id;
|
||||
}
|
||||
|
||||
$toform->inpopup = $inpopup;
|
||||
|
||||
$mform->set_data($toform);
|
||||
|
||||
if ($mform->is_cancelled()) {
|
||||
if ($inpopup) {
|
||||
close_window();
|
||||
} else {
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
} else if ($fromform = $mform->get_data()) {
|
||||
// If we are saving as a copy, break the connection to the old question.
|
||||
if ($makecopy) {
|
||||
$question->id = 0;
|
||||
$question->hidden = 0; // Copies should not be hidden.
|
||||
}
|
||||
|
||||
/// Process the combination of usecurrentcat, categorymoveto and category form
|
||||
/// fields, so the save_question method only has to consider $fromform->category
|
||||
if (!empty($fromform->usecurrentcat)) {
|
||||
// $fromform->category is the right category to save in.
|
||||
} else {
|
||||
if (!empty($fromform->categorymoveto)) {
|
||||
$fromform->category = $fromform->categorymoveto;
|
||||
} else {
|
||||
// $fromform->category is the right category to save in.
|
||||
}
|
||||
}
|
||||
|
||||
/// If we are moving a question, check we have permission to move it from
|
||||
/// whence it came. (Where we are moving to is validated by the form.)
|
||||
list($newcatid, $newcontextid) = explode(',', $fromform->category);
|
||||
if (!empty($question->id) && $newcatid != $question->category) {
|
||||
$contextid = $newcontextid;
|
||||
question_require_capability_on($question, 'move');
|
||||
} else {
|
||||
$contextid = $category->contextid;
|
||||
}
|
||||
|
||||
// Ensure we redirect back to the category the question is being saved into.
|
||||
$returnurl->param('category', $fromform->category);
|
||||
|
||||
// We are actually saving the question.
|
||||
if (!empty($question->id)) {
|
||||
question_require_capability_on($question, 'edit');
|
||||
} else {
|
||||
require_capability('moodle/question:add', context::instance_by_id($contextid));
|
||||
if (!empty($fromform->makecopy) && !$question->formoptions->cansaveasnew) {
|
||||
print_error('nopermissions', '', '', 'edit');
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a new question, save defaults for user in user_preferences table.
|
||||
if (empty($question->id)) {
|
||||
$qtypeobj->save_defaults_for_new_questions($fromform);
|
||||
}
|
||||
$question = $qtypeobj->save_question($question, $fromform);
|
||||
if (isset($fromform->tags)) {
|
||||
// If we have any question context level tags then set those tags now.
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question->id,
|
||||
context::instance_by_id($contextid), $fromform->tags, 0);
|
||||
}
|
||||
|
||||
if (isset($fromform->coursetags)) {
|
||||
// If we have and course context level tags then set those now.
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question->id,
|
||||
context_course::instance($fromform->courseid), $fromform->coursetags, 0);
|
||||
}
|
||||
|
||||
// Purge this question from the cache.
|
||||
question_bank::notify_question_edited($question->id);
|
||||
|
||||
// If we are saving and continuing to edit the question.
|
||||
if (!empty($fromform->updatebutton)) {
|
||||
$url->param('id', $question->id);
|
||||
$url->remove_params('makecopy');
|
||||
redirect($url);
|
||||
}
|
||||
|
||||
if ($qtypeobj->finished_edit_wizard($fromform)) {
|
||||
if ($inpopup) {
|
||||
echo $OUTPUT->notification(get_string('changessaved'), '');
|
||||
close_window(3);
|
||||
} else {
|
||||
$returnurl->param('lastchanged', $question->id);
|
||||
if ($appendqnumstring) {
|
||||
$returnurl->param($appendqnumstring, $question->id);
|
||||
$returnurl->param('sesskey', sesskey());
|
||||
$returnurl->param('cmid', $cmid);
|
||||
}
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
} else {
|
||||
$nexturlparams = array(
|
||||
'returnurl' => $originalreturnurl,
|
||||
'appendqnumstring' => $appendqnumstring,
|
||||
'scrollpos' => $scrollpos);
|
||||
if (isset($fromform->nextpageparam) && is_array($fromform->nextpageparam)){
|
||||
//useful for passing data to the next page which is not saved in the database.
|
||||
$nexturlparams += $fromform->nextpageparam;
|
||||
}
|
||||
$nexturlparams['id'] = $question->id;
|
||||
$nexturlparams['wizardnow'] = $fromform->wizard;
|
||||
$nexturl = new moodle_url('/question/question.php', $nexturlparams);
|
||||
if ($cmid){
|
||||
$nexturl->param('cmid', $cmid);
|
||||
} else {
|
||||
$nexturl->param('courseid', $COURSE->id);
|
||||
}
|
||||
redirect($nexturl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$streditingquestion = $qtypeobj->get_heading();
|
||||
$PAGE->set_title($streditingquestion);
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
$PAGE->navbar->add($streditingquestion);
|
||||
|
||||
// Display a heading, question editing form and possibly some extra content needed for
|
||||
// for this question type.
|
||||
echo $OUTPUT->header();
|
||||
$qtypeobj->display_question_editing_page($mform, $question, $wizardnow);
|
||||
echo $OUTPUT->footer();
|
||||
@@ -98,9 +98,11 @@ class core_question_bank_renderer extends plugin_renderer_base {
|
||||
* @return string
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see \qbank_editquestion\output\renderer
|
||||
* @todo MDL-72004 deprecate the function and add debugging message.
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
public function render_qbank_chooser(renderable $qbankchooser) {
|
||||
debugging('Function render_qbank_chooser is deprecated,
|
||||
please use qbank_editquestion renderer instead.', DEBUG_DEVELOPER);
|
||||
return $this->render_from_template('core_question/qbank_chooser', $qbankchooser->export_for_template($this));
|
||||
}
|
||||
|
||||
@@ -162,6 +164,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
|
||||
* @param object $course The course that will be displayed
|
||||
* @param array $hiddenparams Any hidden parameters to add to the form
|
||||
* @return string The composed HTML for the questionbank chooser
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
public function qbank_chooser($real, $fake, $course, $hiddenparams) {
|
||||
debugging('Method core_question_bank_renderer::qbank_chooser() is deprecated, ' .
|
||||
@@ -174,6 +177,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
|
||||
*
|
||||
* @param array $types A set of question types as used by the qbank_chooser_module function
|
||||
* @return string The composed HTML for the module
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
protected function qbank_chooser_types($types) {
|
||||
debugging('Method core_question_bank_renderer::qbank_chooser_types() is deprecated, ' .
|
||||
@@ -188,6 +192,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
|
||||
* If the module contains subtypes in the types option, then these will also be displayed.
|
||||
* @param array $classes Additional classes to add to the encompassing div element
|
||||
* @return string The composed HTML for the question type
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
protected function qbank_chooser_qtype($qtype, $classes = array()) {
|
||||
debugging('Method core_question_bank_renderer::qbank_chooser_qtype() is deprecated, ' .
|
||||
@@ -201,6 +206,7 @@ class core_question_bank_renderer extends plugin_renderer_base {
|
||||
* @param string $title The language string identifier
|
||||
* @param string $identifier The component identifier
|
||||
* @return string The composed HTML for the title
|
||||
* @todo Final deprecation on Moodle 4.4 MDL-72438
|
||||
*/
|
||||
protected function qbank_chooser_title($title, $identifier = null) {
|
||||
debugging('Method core_question_bank_renderer::qbank_chooser_title() is deprecated, ' .
|
||||
|
||||
@@ -337,16 +337,9 @@ class question_dataset_dependent_items_form extends question_wizard_form {
|
||||
$buttonarray = [];
|
||||
$buttonarray[] = $mform->createElement(
|
||||
'submit', 'savechanges', get_string('savechanges'));
|
||||
|
||||
// Todo MDL-72004 changes for class renaming and default sort.
|
||||
if (class_exists('qbank_previewquestion\\preview_action_column')) {
|
||||
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) {
|
||||
$previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link(
|
||||
$this->question->id, $this->categorycontext, true);
|
||||
}
|
||||
} else {
|
||||
$previewlink = $PAGE->get_renderer('core_question')->question_preview_link(
|
||||
$this->question->id, $this->categorycontext, true);
|
||||
if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) {
|
||||
$previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link($this->question->id,
|
||||
$this->categorycontext, true);
|
||||
}
|
||||
$buttonarray[] = $mform->createElement('static', 'previewlink', '', $previewlink);
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The mform to manage question tags.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2018 Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_question\form;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/lib/formslib.php');
|
||||
require_once($CFG->dirroot . '/lib/questionlib.php');
|
||||
/**
|
||||
* The mform class for manage question tags.
|
||||
*
|
||||
* @copyright 2018 Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @deprecated since Moodle 4.0
|
||||
* @see \qbank_tagquestion\form\tags_form
|
||||
* @todo MDL-71679 class renaming
|
||||
*/
|
||||
class tags extends \moodleform {
|
||||
|
||||
/**
|
||||
* The form definition
|
||||
*/
|
||||
public function definition() {
|
||||
debugging('Class column_base in core_question\form\tags is deprecated,
|
||||
please use qbank_tagquestion\form\tags_form instead.', DEBUG_DEVELOPER);
|
||||
$mform = $this->_form;
|
||||
$customdata = $this->_customdata;
|
||||
|
||||
$mform->disable_form_change_checker();
|
||||
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'categoryid');
|
||||
$mform->setType('categoryid', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'contextid');
|
||||
$mform->setType('contextid', PARAM_INT);
|
||||
|
||||
$mform->addElement('static', 'questionname', get_string('questionname', 'question'));
|
||||
$mform->addElement('static', 'questioncategory', get_string('categorycurrent', 'question'));
|
||||
$mform->addElement('static', 'context', '');
|
||||
|
||||
if (\core_tag_tag::is_enabled('core_question', 'question')) {
|
||||
$tags = \core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $customdata['contexts']);
|
||||
$tagstrings = [];
|
||||
foreach ($tags as $tag) {
|
||||
$tagstrings[$tag->name] = $tag->name;
|
||||
}
|
||||
|
||||
$options = [
|
||||
'tags' => true,
|
||||
'multiple' => true,
|
||||
'noselectionstring' => get_string('anytags', 'quiz'),
|
||||
];
|
||||
$mform->addElement('autocomplete', 'tags', get_string('tags'), $tagstrings, $options);
|
||||
|
||||
// Is the question category in a course context?
|
||||
$qcontext = $customdata['questioncontext'];
|
||||
$qcoursecontext = $qcontext->get_course_context(false);
|
||||
$iscourseoractivityquestion = !empty($qcoursecontext);
|
||||
// Is the current context we're editing in a course context?
|
||||
$editingcontext = $customdata['editingcontext'];
|
||||
$editingcoursecontext = $editingcontext->get_course_context(false);
|
||||
$iseditingcontextcourseoractivity = !empty($editingcoursecontext);
|
||||
|
||||
if ($iseditingcontextcourseoractivity && !$iscourseoractivityquestion) {
|
||||
// If the question is being edited in a course or activity context
|
||||
// and the question isn't a course or activity level question then
|
||||
// allow course tags to be added to the course.
|
||||
$coursetagheader = get_string('questionformtagheader', 'core_question',
|
||||
$editingcoursecontext->get_context_name(true));
|
||||
$mform->addElement('autocomplete', 'coursetags', $coursetagheader, $tagstrings, $options);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ This files describes API changes for code that uses the question API.
|
||||
are divided in two different parts, base classes and feature classes. All the base
|
||||
classes are moved classes/local/bank and all the feature classes will be moved to
|
||||
the plugin for that feature.
|
||||
|
||||
2) submit_tags_form and associated external services for question tag, tags_form in question/type,
|
||||
core_question_output_fragment_tags_form method in lib is deprecated and moved to the tagquestion plugin.
|
||||
|
||||
@@ -19,6 +20,59 @@ This files describes API changes for code that uses the question API.
|
||||
The following classes are deprecated in previewlib and moves the previewquestion plugin:
|
||||
question_preview_options, preview_options_form.
|
||||
|
||||
5) submit_tags_form and associated external services for question tag, tags_form in question/type,
|
||||
core_question_output_fragment_tags_form method in lib is deprecated and moved to the tagquestion plugin.
|
||||
|
||||
6) Function question_get_export_single_question_url() in questionlib has been deprecated
|
||||
and moved to qbank_exporttoxml plugin, the new location is:
|
||||
qbank_exporttoxml\exporttoxml_helper::question_get_export_single_question_url().
|
||||
|
||||
7) The following classes are deleted and available in the new location:
|
||||
'core_question\bank\action_column_base' => 'core_question\local\bank\action_column_base',
|
||||
'core_question\bank\checkbox_column' => 'core_question\local\bank\checkbox_column',
|
||||
'core_question\bank\column_base' => 'core_question\local\bank\column_base',
|
||||
'core_question\bank\edit_menu_column' => 'core_question\local\bank\edit_menu_column',
|
||||
'core_question\bank\menu_action_column_base' => 'core_question\local\bank\menu_action_column_base',
|
||||
'core_question\bank\menuable_action' => 'core_question\local\bank\menuable_action',
|
||||
'core_question\bank\random_question_loader' => 'core_question\local\bank\random_question_loader',
|
||||
'core_question\bank\row_base' => 'core_question\local\bank\row_base',
|
||||
'core_question\bank\view' => 'core_question\local\bank\view',
|
||||
'core_question\bank\copy_action_column' => 'qbank_editquestion\copy_action_column',
|
||||
'core_question\bank\edit_action_column' => 'qbank_editquestion\edit_action_column',
|
||||
'core_question\bank\creator_name_column' => 'qbank_viewcreator\creator_name_column',
|
||||
'core_question\bank\modifier_name_column' => 'qbank_viewcreator\modifier_name_column',
|
||||
'core_question\bank\question_name_column' => 'qbank_viewquestionname\viewquestionname_column_helper',
|
||||
'core_question\bank\question_name_idnumber_tags_column' => 'qbank_viewquestionname\question_name_idnumber_tags_column',
|
||||
'core_question\bank\delete_action_column' => 'qbank_deletequestion\delete_action_column',
|
||||
'core_question\bank\export_xml_action_column' => 'qbank_exporttoxml\export_xml_action_column',
|
||||
'core_question\bank\preview_action_column' => 'qbank_previewquestion\preview_action_column',
|
||||
'core_question\bank\question_text_row' => 'qbank_viewquestiontext\question_text_row',
|
||||
'core_question\bank\question_type_column' => 'qbank_viewquestiontype\question_type_column',
|
||||
'core_question\bank\tags_action_column' => 'qbank_tagquestion\tags_action_column',
|
||||
'core_question\form\tags' => '\qbank_tagquestion\form\tags_form',
|
||||
'core_question\output\qbank_chooser' => 'qbank_editquestion\qbank_chooser',
|
||||
'core_question\output\qbank_chooser_item' => 'qbank_editquestion\qbank_chooser_item',
|
||||
|
||||
8) The following classes are deprecated and moved to a new location. These are marked for final deprecation on 4.4:
|
||||
'question_category_list' => 'qbank_managecategories\question_category_list',
|
||||
'question_category_list_item' => 'qbank_managecategories\question_category_list_item',
|
||||
'question_category_object' => 'qbank_managecategories\question_category_object',
|
||||
'question_category_edit_form' => 'qbank_managecategories\form\category_form',
|
||||
'question_export_form' => 'qbank_exportquestions\form\export_form',
|
||||
'question_import_form' => 'qbank_importquestions\form\question_import_form',
|
||||
'question_move_form' => 'qbank_managecategories\form\question_move_form',
|
||||
'preview_options_form' => 'qbank_previewquestion\form\preview_options_form',
|
||||
'question_preview_options' => 'qbank_previewquestion\output\question_preview_options',
|
||||
'category_form' => 'qbank_managecategories\form\category_form',
|
||||
'export_form' => 'qbank_exportquestions\form\export_form'.
|
||||
|
||||
9) The following functions are deprecated and moved to the new location:
|
||||
question_preview_question_pluginfile() => qbank_previewquestion\helper::question_preview_question_pluginfile(),
|
||||
question_preview_action_url() => qbank_previewquestion\helper::question_preview_action_url(),
|
||||
question_preview_form_url() => qbank_previewquestion\helper::question_preview_form_url(),
|
||||
restart_preview() => qbank_previewquestion\helper::restart_preview(),
|
||||
core_question_output_fragment_tags_form() => /question/bank/qbank_tagquestion/lib.php.
|
||||
|
||||
=== 3.9 ==
|
||||
|
||||
1) For years, the ..._questions_in_use callback has been the right way for plugins to
|
||||
|
||||
Reference in New Issue
Block a user