class quiz_question_bank_view extends question_bank_view {
protected $quizhasattempts = false;
- public function __construct() {
-
+ public function __construct($contexts, $pageurl, $cm = null) {
+ parent::__construct($contexts, $pageurl, $cm);
}
/**
* category Chooses the category
* displayoptions Sets display options
*/
- function display($tabname, $contexts, $pageurl, $cm, $page, $perpage, $sortorder,
+ public function display($tabname, $page, $perpage, $sortorder,
$sortorderdecoded, $cat, $recurse, $showhidden, $showquestiontext){
global $COURSE, $DB;
- if (optional_param('deleteselected', false, PARAM_BOOL)){ // teacher still has to confirm
- // make a list of all the questions that are selected
- $rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted.
- $questionlist = ''; // comma separated list of ids of questions to be deleted
- $questionnames = ''; // string with names of questions separated by <br /> with
- // an asterix in front of those that are in use
- $inuse = false; // set to true if at least one of the questions is in use
- foreach ($rawquestions as $key => $value) { // Parse input for question ids
- if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
- $key = $matches[1];
- $questionlist .= $key.',';
- question_require_capability_on($key, 'edit');
- if ($DB->record_exists('quiz_question_instances', array('question' => $key))) {
- $questionnames .= '* ';
- $inuse = true;
- }
- $questionnames .= $DB->get_field('question', 'name', array('id' => $key)) . '<br />';
- }
- }
- if (!$questionlist) { // no questions were selected
- redirect($pageurl->out());
- }
- $questionlist = rtrim($questionlist, ',');
-
- // Add an explanation about questions in use
- if ($inuse) {
- $questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
- }
- notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
- $pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))),
- $pageurl->out_action());
-
+ if ($this->process_actions_needing_ui()) {
return;
}
print_box_start('generalbox questionbank');
- $this->display_category_form($contexts->having_one_edit_tab_cap($tabname),
- $pageurl, $cat, $recurse, $showhidden, $showquestiontext);
+ $this->display_category_form($this->contexts->having_one_edit_tab_cap($tabname),
+ $this->baseurl, $cat, $recurse, $showhidden, $showquestiontext);
// continues with list of questions
- $this->display_question_list($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, isset($cm) ? $cm : null,
+ $this->display_question_list($this->contexts->having_one_edit_tab_cap($tabname), $this->baseurl, $cat, $this->cm,
$recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext,
- $contexts->having_cap('moodle/question:add'));
+ $this->contexts->having_cap('moodle/question:add'));
echo '<hr/><form method="get" action="edit.php" id="displayoptions">';
echo "<fieldset class='invisiblefieldset'>";
- echo $pageurl->hidden_params_out(array('recurse', 'showhidden',
+ echo $this->baseurl->hidden_params_out(array('recurse', 'showhidden',
'showquestiontext'));
$this->display_category_form_checkbox('recurse', $recurse);
$this->display_category_form_checkbox('showhidden', $showhidden);
/**
* prints a form to choose categories
*/
- function display_category_form($contexts, $pageurl, $current, $recurse=1,
+ protected function display_category_form($contexts, $pageurl, $current, $recurse=1,
$showhidden=false, $showquestiontext=false) {
global $CFG;
* @param boolean $showhidden True if also hidden questions should be displayed
* @param boolean $showquestiontext whether the text of each question should be shown in the list
*/
- function display_question_list($contexts, $pageurl, $categoryandcontext,
+ protected function display_question_list($contexts, $pageurl, $categoryandcontext,
$cm = null, $recurse=1, $page=0, $perpage=100, $showhidden=false,
$sortorder='typename', $sortorderdecoded='qtype, name ASC',
$showquestiontext = false, $addcontexts = array()) {
- global $USER, $CFG, $THEME, $COURSE, $DB;
+ global $CFG, $COURSE, $DB;
list($categoryid, $contextid)= explode(',', $categoryandcontext);
// There are no questions on the requested page.
$page = 0;
- if (!$questionsatall = $DB->get_records_select('question',
+ if (!$questions = $DB->get_records_select('question',
"category $usql AND parent = '0' $showhidden", $params, $sortorderdecoded,
'*', 0, $perpage)) {
// There are no questions at all
echo '</fieldset>';
echo "</form>\n";
}
-}
-/**
- * Add an arbitrary element to array at a specified index, pushing the rest
- * back.
- *
- * @param array $array The array to operate on
- * @param mixed $value The element to add
- * @param integer $at The position at which to add the element
- * @return array
- */
-function array_add_at($array,$value,$at){
- $beginpart=array_slice($array, 0,$at);
- $endpart=array_slice($array, $at, (count($array)-$at) );
- $beginpart[]=$value;
- $result=array_merge($beginpart,$endpart);
- return $result;
+ protected function display_question_sort_options($pageurl, $sortorder){
+ //sort options
+ $html = "<div class=\"mdl-align questionsortoptions\">";
+ // POST method should only be used for parameters that change data
+ // or if POST method has to be used, the user must be redirected immediately to
+ // non-POSTed page to not break the back button
+ $html .= '<form method="get" action="edit.php">';
+ $html .= '<fieldset class="invisiblefieldset" style="display: block;">';
+ $html .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
+ $html .= $pageurl->hidden_params_out(array('qsortorder'));
+ //choose_from_menu concatenates the form name with
+ //"menu" so the label is for menuqsortorder
+ $sortoptions = array('alpha' => get_string("qname", "quiz"),
+ 'typealpha' => get_string("qtypename", "quiz"),
+ 'age' => get_string("age", "quiz"));
+ $a = choose_from_menu($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true);
+ $html .= '<label for="menuqsortorder">'.get_string('sortquestionsbyx', 'quiz', $a).'</label>';
+ $html .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>';
+ $html .= '</fieldset>';
+ $html .= "</form>\n";
+ $html .= "</div>\n";
+ echo $html;
+ }
+
+ public function process_actions() {
+ global $CFG, $COURSE, $DB;
+ /// Now, check for commands on this page and modify variables as necessary
+ if (optional_param('move', false, PARAM_BOOL) and confirm_sesskey()) { /// Move selected questions to new category
+ $category = required_param('category', PARAM_SEQUENCE);
+ list($tocategoryid, $contextid) = explode(',', $category);
+ if (! $tocategory = $DB->get_record('question_categories', array('id' => $tocategoryid, 'contextid' => $contextid))) {
+ print_error('cannotfindcate', 'question');
+ }
+ $tocontext = get_context_instance_by_id($contextid);
+ require_capability('moodle/question:add', $tocontext);
+ $rawdata = (array) data_submitted();
+ $questionids = array();
+ foreach ($rawdata as $key => $value) { // Parse input for question ids
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ $key = $matches[1];
+ $questionids[] = $key;
+ }
+ }
+ if ($questionids){
+ list($usql, $params) = $DB->get_in_or_equal($questionids);
+ $sql = "SELECT q.*, c.contextid FROM {question} q, {question_categories} c WHERE q.id $usql AND c.id = q.category";
+ if (!$questions = $DB->get_records_sql($sql, $params)){
+ print_error('questiondoesnotexist', 'question', $pageurl->out());
+ }
+ $checkforfiles = false;
+ foreach ($questions as $question){
+ //check capabilities
+ question_require_capability_on($question, 'move');
+ $fromcontext = get_context_instance_by_id($question->contextid);
+ if (get_filesdir_from_context($fromcontext) != get_filesdir_from_context($tocontext)){
+ $checkforfiles = true;
+ }
+ }
+ $returnurl = $pageurl->out(false, array('category'=>"$tocategoryid,$contextid"));
+ if (!$checkforfiles){
+ if (!question_move_questions_to_category(implode(',', $questionids), $tocategory->id)) {
+ print_error('errormovingquestions', 'question', $returnurl, $questionids);
+ }
+ redirect($returnurl);
+ } else {
+ $movecontexturl = new moodle_url($CFG->wwwroot.'/question/contextmoveq.php',
+ array('returnurl' => $returnurl,
+ 'ids'=>$questionidlist,
+ 'tocatid'=> $tocategoryid));
+ if ($cm){
+ $movecontexturl->param('cmid', $cm->id);
+ } else {
+ $movecontexturl->param('courseid', $COURSE->id);
+ }
+ redirect($movecontexturl->out());
+ }
+ }
+ }
+
+ if (optional_param('deleteselected', false, PARAM_BOOL)) { // delete selected questions from the category
+ if (($confirm = optional_param('confirm', '', PARAM_ALPHANUM)) and confirm_sesskey()) { // teacher has already confirmed the action
+ $deleteselected = required_param('deleteselected');
+ if ($confirm == md5($deleteselected)) {
+ if ($questionlist = explode(',', $deleteselected)) {
+ // for each question either hide it if it is in use or delete it
+ foreach ($questionlist as $questionid) {
+ question_require_capability_on($questionid, 'edit');
+ if ($DB->record_exists('quiz_question_instances', array('question' => $questionid))) {
+ if (!$DB->set_field('question', 'hidden', 1, array('id' => $questionid))) {
+ question_require_capability_on($questionid, 'edit');
+ print_error('cannothidequestion', 'question');
+ }
+ } else {
+ delete_question($questionid);
+ }
+ }
+ }
+ redirect($pageurl->out());
+ } else {
+ print_error('invalidconfirm', 'question');
+ }
+ }
+ }
+
+ // Unhide a question
+ if(($unhide = optional_param('unhide', '', PARAM_INT)) and confirm_sesskey()) {
+ question_require_capability_on($unhide, 'edit');
+ if(!$DB->set_field('question', 'hidden', 0, array('id', $unhide))) {
+ print_error('cannotunhidequestion', 'question');
+ }
+ redirect($pageurl->out());
+ }
+ }
+
+ public function process_actions_needing_ui() {
+ if (optional_param('deleteselected', false, PARAM_BOOL)) {
+ // make a list of all the questions that are selected
+ $rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted.
+ $questionlist = ''; // comma separated list of ids of questions to be deleted
+ $questionnames = ''; // string with names of questions separated by <br /> with
+ // an asterix in front of those that are in use
+ $inuse = false; // set to true if at least one of the questions is in use
+ foreach ($rawquestions as $key => $value) { // Parse input for question ids
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ $key = $matches[1];
+ $questionlist .= $key.',';
+ question_require_capability_on($key, 'edit');
+ if ($DB->record_exists('quiz_question_instances', array('question' => $key))) {
+ $questionnames .= '* ';
+ $inuse = true;
+ }
+ $questionnames .= $DB->get_field('question', 'name', array('id' => $key)) . '<br />';
+ }
+ }
+ if (!$questionlist) { // no questions were selected
+ redirect($this->baseurl->out());
+ }
+ $questionlist = rtrim($questionlist, ',');
+
+ // Add an explanation about questions in use
+ if ($inuse) {
+ $questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
+ }
+ notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
+ $pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))),
+ $pageurl->out_action());
+
+ return true;
+ }
+ }
}
/**
}
abstract class question_bank_column_base {
+ protected $qbank;
+
+ /**
+ * Constructor.
+ * @param $qbank the question_bank_view we are helping to render.
+ */
+ public function __construct(question_bank_view $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() {
+ }
/**
* Output the column header cell.
* @param integer $currentsort 0 for none. 1 for normal sort, -1 for reverse sort.
*/
- public function display_header($currentsort) {
- // TODO.
+ public function display_header() {
+ echo '<th class=header ' . $this->get_name() . '" scope="col">';
+ $sortable = $this->is_sortable();
+ $name = $this->get_name();
+ $title = $this->get_title();
+ 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'], !empty($details['reverse']));
+ }
+ echo implode(' / ', $links);
+ } else if ($sortable) {
+ echo $this->make_sort_link($name, $this->qbank->get_sort($name), $title);
+ } else {
+ echo $title;
+ }
+ echo "</th>\n";
+ }
+
+ /**
+ * Title for this column. Not used if is_sortable returns an array.
+ * @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 function get_title() {
+ return '';
+ }
+
+ /**
+ * Get a link that changes the sort order, and indicates the current sort state.
+ * @param $name internal name used for this type of sorting.
+ * @param $currentsort the current sort order -1, 0, 1 for descending, none, ascending.
+ * @param $title the link text.
+ * @param $defaultreverse whether the default sort order for this column is descending, rather than ascending.
+ * @return string HTML fragment.
+ */
+ protected function make_sort_link($name, $currentsort, $title, $defaultreverse = false) {
+ $newsortreverse = $defaultreverse;
+ if ($currentsort) {
+ $newsortreverse = $currentsort > 0;
+ }
+ if ($newsortreverse) {
+ $tip = get_string('sortbyxreverse', '', $title);
+ } else {
+ $tip = get_string('sortbyx', '', $title);
+ }
+ echo '<a href="' . $this->qbank->new_sort_url($name, $newsortreverse) . '" title="' . $tip . '">';
+ echo $title;
+ if ($currentsort) {
+ echo $this->get_sort_icon($currentsort < 0);
+ }
+ echo '</a>';
+ }
+
+ /**
+ * Get an icon representing the corrent sort state.
+ * @param $reverse sort is descending, not ascending.
+ * @return string HTML image tag.
+ */
+ protected function get_sort_icon($reverse) {
+ global $CFG;
+ if ($reverse) {
+ return ' <img src="' . $CFG->pixpath . '/t/up.gif" alt="' . get_string('desc') . '" />';
+ } else {
+ return ' <img src="' . $CFG->pixpath . '/t/down.gif" alt="' . get_string('asc') . '" />';
+ }
}
/**
}
protected function display_start($question, $rowclasses) {
- echo '<td class="' . $this->get_css_classes($question, $rowclasses) . '">';
+ echo '<td class="' . $this->get_name() . '">';
}
/**
* @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.
- * @return string CSS class names that should be applied to this column. Should normally be
- * a simple work relating the the column type like 'questionname'.
+ * @return string internal name for this column. Used as a CSS class name, and to store information about the current sort.
*/
- abstract protected function get_css_classes($question, $rowclasses);
+ abstract protected function get_name();
/**
* Output the contents of this column.
abstract protected function display_content($question, $rowclasses);
protected function display_end($question, $rowclasses) {
- echo '</td>';
+ echo "</td>\n";
}
/**
/**
* Can this column be sorted on? You can return either:
* + false for no (the default),
- * + true for yes, or
- * + an array of subnames to sort on. E.g. 'firstname', 'lastname'.
- * If this method returns true, sort_expression must be implemented.
- * @return mixed
+ * + 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', 'field' => 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;
* @param string $normaldir 'ASC' or 'DESC'
* @return string 'ASC' or 'DESC'
*/
- protected function sortorder($reverse, $normaldir = 'ASC') {
- switch ($normaldir) {
- case 'ASC':
- if ($reverse) {
- return ' DESC';
- } else {
- return ' ASC';
- }
- case 'DESC':
- if ($reverse) {
- return ' ASC';
- } else {
- return ' DESC';
- }
- default:
- throw new coding_exception('$normaldir should be ASC or DESC.');
+ protected function sortorder($reverse) {
+ if ($reverse) {
+ return ' DESC';
+ } else {
+ return ' ASC';
}
}
* @return string some SQL to go in the order by clause.
*/
public function sort_expression($reverse, $subsort) {
- throw new coding_exception('A subclass of question_bank_column_base must implement sort_expression if is_sortable returns true.');
+ $sortable = $this->is_sortable();
+ if (is_array($sortable)) {
+ if (array_key_exists($subsort, $sortable)) {
+ return $sortable[$sortable]['field'] . $this->sortorder($reverse, !empty($sortable[$sortable]['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.');
+ }
}
}
class question_bank_checkbox_column extends question_bank_column_base {
protected $strselect;
- public function __construct() {
- parent::__construct();
+ public function init() {
$this->strselect = get_string('select', 'quiz');
}
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'checkbox';
}
+ protected function get_title() {
+ return '<input type="checkbox" disabled="disabled" />';
+ }
+
protected function display_content($question, $rowclasses) {
echo '<input title="' . $this->strselect . '" type="checkbox" name="q' .
$question->id . '" id="checkq' . $question->id . '" value="1" />';
* A column type for the name of the question type.
*/
class question_bank_question_type_column extends question_bank_column_base {
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'qtype';
}
+ protected function get_title() {
+ return get_string('qtypeveryshort', 'question');
+ }
+
protected function display_content($question, $rowclasses) {
echo print_question_icon($question);
}
}
public function is_sortable() {
- return true;
- }
-
- public function sort_expression($reverse, $subsort) {
- return 'q.qtype' . $this->sortorder($reverse);
+ return 'q.qtype';
}
}
* A column type for the name of the question name.
*/
class question_bank_question_name_column extends question_bank_column_base {
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'questionname';
}
+ protected function get_title() {
+ return get_string('question');
+ }
+
protected function display_content($question, $rowclasses) {
echo format_string($question->name);
}
}
public function is_sortable() {
- return true;
- }
-
- public function sort_expression($reverse, $subsort) {
- return 'q.name' . $this->sortorder($reverse);
+ return 'q.name';
}
}
* A column type for the name of the question creator.
*/
class question_bank_creator_name_column extends question_bank_column_base {
- protected function get_css_classes($question, $rowclasses) {
+ protected 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;
}
public function is_sortable() {
- return array('firstname', 'lastname');
- }
-
- public function sort_expression($reverse, $subsort) {
- if (in_array($subsort, $this->is_sortable())) {
- return 'uc.' . $subsort . $this->sortorder($reverse);
- } else {
- throw new coding_exception('Unexpected $subsort type.');
- }
+ return array(
+ 'firstname' => array('field' => 'uc.firstname', 'title' => get_string('firstname')),
+ 'lastname' => array('field' => 'uc.lastname', 'title' => get_string('lastname')),
+ );
}
}
* A column type for the name of the question last modifier.
*/
class question_bank_modifier_name_column extends question_bank_column_base {
- protected function get_css_classes($question, $rowclasses) {
+ protected 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;
}
public function is_sortable() {
- return array('firstname', 'lastname');
- }
-
- public function sort_expression($reverse, $subsort) {
- if (in_array($subsort, $this->is_sortable())) {
- return 'um.' . $subsort . $this->sortorder($reverse);
- } else {
- throw new coding_exception('Unexpected $subsort type.');
- }
+ return array(
+ 'firstname' => array('field' => 'um.firstname', 'title' => get_string('firstname')),
+ 'lastname' => array('field' => 'um.lastname', 'title' => get_string('lastname')),
+ );
}
}
* A base class for actions that are an icon that lets you manipulate the question in some way.
*/
abstract class question_bank_action_column_base extends question_bank_column_base {
+
+ protected function get_title() {
+ return ' ';
+ }
+
protected function print_icon($icon, $title, $url) {
global $CFG;
echo '<a title="' . $title . '" href="' . $url . '">
class question_bank_edit_action_column extends question_bank_action_column_base {
protected $stredit;
protected $strview;
- protected $questionurl;
- public function __construct($questionurl) {
- parent::__construct();
- $this->questionurl = $questionurl;
+ public function init() {
+ parent::init();
$this->stredit = get_string('edit');
$this->strview = get_string('view');
}
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'editaction';
}
protected function display_content($question, $rowclasses) {
if (question_has_capability_on($question, 'edit') ||
question_has_capability_on($question, 'move')) {
- $this->print_icon('edit', $this->stredit, $this->questionurl->out(false, array('id' => $question->id)));
+ $this->print_icon('edit', $this->stredit, $this->qbank->edit_question_url($question->id));
} else {
- $this->print_icon('info', $this->strview, $this->questionurl->out(false, array('id' => $question->id)));
+ $this->print_icon('info', $this->strview, $this->qbank->edit_question_url($question->id));
}
}
}
class question_bank_preview_action_column extends question_bank_action_column_base {
protected $strpreview;
- protected $quizorcourseid;
- public function __construct($quizorcourseid) {
- parent::__construct();
- $this->quizorcourseid = $quizorcourseid;
+ public function init() {
+ parent::init();
$this->stredit = get_string('preview');
}
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'previewaction';
}
protected function display_content($question, $rowclasses) {
if (question_has_capability_on($question, 'use')) {
- link_to_popup_window('/question/preview.php?id=' . $question->id .
- $this->quizorcourseid, 'questionpreview',
+ link_to_popup_window($this->qbank->preview_question_url($question->id), 'questionpreview',
' <img src="' . $CFG->pixpath . '/t/preview.gif" class="iconsmall" alt="' . $this->strpreview . '" />',
0, 0, $this->strpreview, QUESTION_PREVIEW_POPUP_OPTIONS);
}
class question_bank_move_action_column extends question_bank_action_column_base {
protected $strmove;
- protected $questionurl;
- public function __construct($questionurl) {
- parent::__construct();
- $this->questionurl = $questionurl;
+ public function init() {
+ parent::init();
$this->strmove = get_string('move');
}
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'editaction';
}
protected function display_content($question, $rowclasses) {
if (question_has_capability_on($question, 'move')) {
- $this->print_icon('move', $this->strmove, $this->questionurl->out(false, array('id' => $question->id)));
+ $this->print_icon('move', $this->strmove, $this->qbank->edit_question_url($question->id));
}
}
}
class question_bank_delete_action_column extends question_bank_action_column_base {
protected $strdelete;
protected $strrestore;
- protected $questionurl;
- public function __construct($questionurl) {
- parent::__construct();
- $this->questionurl = $questionurl;
+ public function init() {
+ parent::init();
$this->strdelete = get_string('delete');
$this->strrestore = get_string('restore');
}
- protected function get_css_classes($question, $rowclasses) {
+ protected function get_name() {
return 'deleteaction';
}
protected function display_content($question, $rowclasses) {
if (question_has_capability_on($question, 'edit')) {
if ($question->hidden) {
- $this->print_icon('restore', $this->strrestore, $pageurl->out(false, array('unhide' => $question->id)));
+ $this->print_icon('restore', $this->strrestore, $this->qbank->base_url()->out(false, array('unhide' => $question->id)));
} else {
$this->print_icon('restore', $this->strrestore,
- $pageurl->out(false, array('deleteselected' => $question->id, 'q' . $question->id => 1)));
+ $this->qbank->base_url()->out(false, array('deleteselected' => $question->id, 'q' . $question->id => 1)));
}
}
}
* + outputting table headers.
*/
class question_bank_view {
- public function __construct() {
+ protected $baseurl;
+ protected $editquestionurl;
+ protected $quizorcourseid;
+ protected $contexts;
+ protected $cm;
+
+ public function __construct($contexts, $pageurl, $cm = null) {
+ global $CFG, $COURSE;
+ $this->contexts = $contexts;
+ $this->baseurl = $pageurl;
+ $this->cm = $cm;
+
+ if (!empty($cm) && $cm->modname == 'quiz') {
+ $this->quizorcourseid = '&quizid=' . $cm->instance;
+ } else {
+ $this->quizorcourseid = '&courseid=' .$COURSE->id;
+ }
+
+ // Create the url of the new question page to forward to.
+ $this->editquestionurl = new moodle_url("$CFG->wwwroot/question/question.php",
+ array('returnurl' => $pageurl->out()));
+ if ($cm !== null){
+ $this->editquestionurl->param('cmid', $cm->id);
+ } else {
+ $this->editquestionurl->param('courseid', $COURSE->id);
+ }
+ }
+
+ public function base_url($questionid) {
+ return $baseurl;
+ }
+
+ public function edit_question_url($questionid) {
+ return $this->editquestionurl->out(false, array('id' => $questionid));
+ }
+
+ public function preview_question_url($questionid) {
+ global $CFG;
+ return $CFG->wwwroot . '/question/preview.php?id=' . $question->id . $this->quizorcourseid;
}
/**
* category Chooses the category
* displayoptions Sets display options
*/
- function display($tabname, $contexts, $pageurl, $cm, $page, $perpage, $sortorder,
+ public function display($tabname, $page, $perpage, $sortorder,
$sortorderdecoded, $cat, $recurse, $showhidden, $showquestiontext){
global $COURSE, $DB;
- if (optional_param('deleteselected', false, PARAM_BOOL)){ // teacher still has to confirm
- // make a list of all the questions that are selected
- $rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted.
- $questionlist = ''; // comma separated list of ids of questions to be deleted
- $questionnames = ''; // string with names of questions separated by <br /> with
- // an asterix in front of those that are in use
- $inuse = false; // set to true if at least one of the questions is in use
- foreach ($rawquestions as $key => $value) { // Parse input for question ids
- if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
- $key = $matches[1];
- $questionlist .= $key.',';
- question_require_capability_on($key, 'edit');
- if ($DB->record_exists('quiz_question_instances', array('question' => $key))) {
- $questionnames .= '* ';
- $inuse = true;
- }
- $questionnames .= $DB->get_field('question', 'name', array('id' => $key)) . '<br />';
- }
- }
- if (!$questionlist) { // no questions were selected
- redirect($pageurl->out());
- }
- $questionlist = rtrim($questionlist, ',');
-
- // Add an explanation about questions in use
- if ($inuse) {
- $questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
- }
- notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
- $pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))),
- $pageurl->out_action());
-
+ if ($this->process_actions_needing_ui()) {
return;
}
print_box_start('generalbox questionbank');
print_heading(get_string('questionbank', 'question'), '', 2);
- $this->display_category_form($contexts->having_one_edit_tab_cap($tabname),
- $pageurl, $cat, $recurse, $showhidden, $showquestiontext);
+ $this->display_category_form($this->contexts->having_one_edit_tab_cap($tabname),
+ $this->baseurl, $cat, $recurse, $showhidden, $showquestiontext);
// continues with list of questions
- $this->display_question_list($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, isset($cm) ? $cm : null,
+ $this->display_question_list($this->contexts->having_one_edit_tab_cap($tabname), $this->baseurl, $cat, $this->cm,
$recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext,
- $contexts->having_cap('moodle/question:add'));
+ $this->contexts->having_cap('moodle/question:add'));
print_box_end();
}
/**
* prints a form to choose categories
*/
- function display_category_form($contexts, $pageurl, $current, $recurse=1,
+ protected function display_category_form($contexts, $pageurl, $current, $recurse=1,
$showhidden=false, $showquestiontext=false) {
global $CFG;
* @param boolean $showhidden True if also hidden questions should be displayed
* @param boolean $showquestiontext whether the text of each question should be shown in the list
*/
- function display_question_list($contexts, $pageurl, $categoryandcontext,
+ protected function display_question_list($contexts, $pageurl, $categoryandcontext,
$cm = null, $recurse=1, $page=0, $perpage=100, $showhidden=false,
$sortorder='typename', $sortorderdecoded='qtype, name ASC',
$showquestiontext = false, $addcontexts = array()) {
- global $USER, $CFG, $THEME, $COURSE, $DB;
+ global $CFG, $COURSE, $DB;
list($categoryid, $contextid)= explode(',', $categoryandcontext);
echo "</form>\n";
}
- function display_question_sort_options($pageurl, $sortorder){
- global $USER;
+ protected function display_question_sort_options($pageurl, $sortorder){
//sort options
$html = "<div class=\"mdl-align questionsortoptions\">";
// POST method should only be used for parameters that change data
echo $html;
}
- function process_actions($pageurl, $cm){
+ public function process_actions() {
global $CFG, $COURSE, $DB;
/// Now, check for commands on this page and modify variables as necessary
if (optional_param('move', false, PARAM_BOOL) and confirm_sesskey()) { /// Move selected questions to new category
redirect($pageurl->out());
}
}
+
+ public function process_actions_needing_ui() {
+ if (optional_param('deleteselected', false, PARAM_BOOL)) {
+ // make a list of all the questions that are selected
+ $rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted.
+ $questionlist = ''; // comma separated list of ids of questions to be deleted
+ $questionnames = ''; // string with names of questions separated by <br /> with
+ // an asterix in front of those that are in use
+ $inuse = false; // set to true if at least one of the questions is in use
+ foreach ($rawquestions as $key => $value) { // Parse input for question ids
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ $key = $matches[1];
+ $questionlist .= $key.',';
+ question_require_capability_on($key, 'edit');
+ if ($DB->record_exists('quiz_question_instances', array('question' => $key))) {
+ $questionnames .= '* ';
+ $inuse = true;
+ }
+ $questionnames .= $DB->get_field('question', 'name', array('id' => $key)) . '<br />';
+ }
+ }
+ if (!$questionlist) { // no questions were selected
+ redirect($this->baseurl->out());
+ }
+ $questionlist = rtrim($questionlist, ',');
+
+ // Add an explanation about questions in use
+ if ($inuse) {
+ $questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
+ }
+ notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
+ $pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))),
+ $pageurl->out_action());
+
+ return true;
+ }
+ }
}
/**