MDL-79863 qtype_ordering: Qtype_ordering: Numbering for lists (123.., abc...) (#42)

Thanks Mahmoud. Great job!
This commit is contained in:
Mahmoud Kassaei 2019-07-11 00:12:22 +01:00 committed by Mathew May
parent 9935253fea
commit 76a6fce839
14 changed files with 152 additions and 19 deletions

View File

@ -1 +1 @@
define(["jquery",require.specified("core/dragdrop")?"core/dragdrop":"qtype_ordering/dragdrop",require.specified("core/key_codes")?"core/key_codes":"qtype_ordering/key_codes"],function(a,b,c){return function(d){var e=null,f=null,g=null,h=null,i=null,j=function(c,h){e={time:(new Date).getTime(),x:h.x,y:h.y},g=a(c.currentTarget).closest(d.itemInPage),"undefined"!=typeof d.reorderStart&&d.reorderStart(g.closest(d.list),g),f=r(),i=a(d.proxyHtml.replace("%%ITEM_HTML%%",g.html()).replace("%%ITEM_CLASS_NAME%%",g.attr("class"))),a(document.body).append(i),i.css("position","absolute"),i.css(g.offset()),i.width(g.outerWidth()),i.height(g.outerHeight()),g.addClass(d.itemMovingClass),b.start(c,i,k,m)},k=function(){var b=g.closest(d.list),c=null,e=null;b.find(d.item).each(function(b,d){var f=q(d,i);(null===c||f<e)&&(c=a(d),e=f)}),c[0]!==g[0]&&(p(i)<p(c)?g.insertBefore(c):g.insertAfter(c))},l=function(a,b){var c=[];return a.split(",").forEach(function(a){b.split(",").forEach(function(b){c.push(a.trim()+" "+b.trim())})}),c.join(", ")},m=function(a,b){"undefined"!=typeof d.reorderEnd&&d.reorderEnd(g.closest(d.list),g);var c=r();s(f,c)?(new Date).getTime()-e.time<500&&Math.abs(e.x-a)<10&&Math.abs(e.y-b)<10&&g[0].focus():d.reorderDone(g.closest(d.list),g,c),i.remove(),i=null,g.removeClass(d.itemMovingClass),g=null,e=null},n=function(a,b){var d;switch(a.keyCode){case c.space:case c.arrowRight:case c.arrowDown:a.preventDefault(),a.stopPropagation(),d=document.getElementById(b.attr("id"));var e=d.nextSibling;null!==e&&e.parentNode.insertBefore(e,e.previousSibling);break;case c.arrowLeft:case c.arrowUp:a.preventDefault(),a.stopPropagation(),d=document.getElementById(b.attr("id"));var f=d.previousSibling;null!==f&&f.parentNode.insertBefore(f,f.nextSibling.nextSibling)}},o=function(a){return a.offset().left+a.outerWidth()/2},p=function(a){return a.offset().top+a.outerHeight()/2},q=function(b,c){var d=a(b),e=a(c),f=o(d)-o(e),g=p(d)-p(e);return Math.sqrt(f*f+g*g)},r=function(){return(g||h).closest(d.list).find(d.item).map(function(a,b){return d.idGetter(b)}).get()},s=function(a,b){return a.length===b.length&&a.every(function(a,c){return a===b[c]})};d.itemInPage=l(d.list,d.item),a(d.list).on("mousedown touchstart",d.item,function(a){var c=b.prepare(a);c.start&&j(a,c)}),a(d.list).on("keydown",d.item,function(b){h=a(b.currentTarget).closest(d.itemInPage),f=r(),n(b,h);var c=r();s(f,c)||d.reorderDone(h.closest(d.list),h,c)}),a(d.itemInPage).attr("tabindex","0")}});
define(["jquery",require.specified("core/dragdrop")?"core/dragdrop":"qtype_ordering/dragdrop",require.specified("core/key_codes")?"core/key_codes":"qtype_ordering/key_codes"],function(a,b,c){return function(d){var e=null,f=null,g=null,h=null,i=null,j=function(c,h){e={time:(new Date).getTime(),x:h.x,y:h.y},g=a(c.currentTarget).closest(d.itemInPage),"undefined"!=typeof d.reorderStart&&d.reorderStart(g.closest(d.list),g),f=s(),i=a(d.proxyHtml.replace("%%ITEM_HTML%%",g.html()).replace("%%ITEM_CLASS_NAME%%",g.attr("class"))),a(document.body).append(i),i.css("position","absolute"),i.css(g.offset()),i.width(g.outerWidth()),i.height(g.outerHeight()),g.addClass(d.itemMovingClass),l(g),b.start(c,i,k,n)},k=function(){var b=g.closest(d.list),c=null,e=null;b.find(d.item).each(function(b,d){var f=r(d,i);(null===c||f<e)&&(c=a(d),e=f)}),c[0]!==g[0]&&(q(i)<q(c)?g.insertBefore(c):g.insertAfter(c),l(g))},l=function(a){for(var b=a.closest("ol, ul"),c=b.find("li"),d=c.length,e=0;e<d;++e)if(a[0]===c[e]){i.find("li").attr("value",e+1);break}},m=function(a,b){var c=[];return a.split(",").forEach(function(a){b.split(",").forEach(function(b){c.push(a.trim()+" "+b.trim())})}),c.join(", ")},n=function(a,b){"undefined"!=typeof d.reorderEnd&&d.reorderEnd(g.closest(d.list),g);var c=s();t(f,c)?(new Date).getTime()-e.time<500&&Math.abs(e.x-a)<10&&Math.abs(e.y-b)<10&&g[0].focus():d.reorderDone(g.closest(d.list),g,c),i.remove(),i=null,g.removeClass(d.itemMovingClass),g=null,e=null},o=function(a,b){switch(a.keyCode){case c.space:case c.arrowRight:case c.arrowDown:a.preventDefault(),a.stopPropagation();var d=b.next();d.length&&d.insertBefore(b);break;case c.arrowLeft:case c.arrowUp:a.preventDefault(),a.stopPropagation();var e=b.prev();e.length&&e.insertAfter(b)}},p=function(a){return a.offset().left+a.outerWidth()/2},q=function(a){return a.offset().top+a.outerHeight()/2},r=function(b,c){var d=a(b),e=a(c),f=p(d)-p(e),g=q(d)-q(e);return Math.sqrt(f*f+g*g)},s=function(){return(g||h).closest(d.list).find(d.item).map(function(a,b){return d.idGetter(b)}).get()},t=function(a,b){return a.length===b.length&&a.every(function(a,c){return a===b[c]})};d.itemInPage=m(d.list,d.item),a(d.list).on("mousedown touchstart",d.item,function(a){var c=b.prepare(a);c.start&&j(a,c)}),a(d.list).on("keydown",d.item,function(b){h=a(b.currentTarget).closest(d.itemInPage),f=s(),o(b,h);var c=s();t(f,c)||d.reorderDone(h.closest(d.list),h,c)}),a(d.itemInPage).attr("tabindex","0")}});

View File

@ -134,6 +134,7 @@ define([
proxy.width(itemDragging.outerWidth());
proxy.height(itemDragging.outerHeight());
itemDragging.addClass(config.itemMovingClass);
updateProxy(itemDragging);
// Start drag.
drag.start(event, proxy, dragMove, dragEnd);
@ -155,12 +156,29 @@ define([
if (closestItem[0] === itemDragging[0]) {
return;
}
if (midY(proxy) < midY(closestItem)) {
itemDragging.insertBefore(closestItem);
} else {
itemDragging.insertAfter(closestItem);
}
updateProxy(itemDragging);
};
/**
* Update proxy's position.
* @param itemDragging
*/
var updateProxy = function(itemDragging) {
var list = itemDragging.closest('ol, ul');
var items = list.find('li');
var count = items.length;
for (var i = 0; i < count; ++i) {
//proxy.css('margin-left', '20p');
if (itemDragging[0] === items[i]) {
proxy.find('li').attr('value', i + 1);
break;
}
}
};
/**

View File

@ -51,7 +51,7 @@ class backup_qtype_ordering_plugin extends backup_qtype_plugin {
$this->add_question_question_answers($pluginwrapper);
// Now create the qtype own structures.
$fields = array('layouttype', 'selecttype', 'selectcount', 'gradingtype', 'showgrading',
$fields = array('layouttype', 'selecttype', 'selectcount', 'gradingtype', 'showgrading', 'answernumbering',
'correctfeedback', 'correctfeedbackformat',
'incorrectfeedback', 'incorrectfeedbackformat',
'partiallycorrectfeedback', 'partiallycorrectfeedbackformat');

View File

@ -16,6 +16,7 @@
<FIELD NAME="incorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="partiallycorrectfeedback" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="partiallycorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="answernumbering" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="none" SEQUENCE="false" COMMENT="Indicates how and whether the choices should be numbered."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for question_ordering"/>

View File

@ -230,6 +230,22 @@ function xmldb_qtype_ordering_upgrade($oldversion) {
}
upgrade_plugin_savepoint(true, $newversion, 'qtype', 'ordering');
}
$newversion = 2019062000;
if ($oldversion < $newversion) {
// Define field answernumbering to be added to qtype_ordering_options.
$table = new xmldb_table('qtype_ordering_options');
$field = new xmldb_field('answernumbering', XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, 'none', 'partiallycorrectfeedbackformat');
// Conditionally launch add field answernumbering.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Ordering savepoint reached.
upgrade_plugin_savepoint(true, $newversion, 'qtype', 'ordering');
}
return true;
}

View File

@ -123,6 +123,11 @@ class qtype_ordering_edit_form extends question_edit_form {
$elements = array();
$options = array();
$name = 'answernumbering';
$label = get_string($name, 'qtype_ordering');
$mform->addElement('select', $name, $label, qtype_ordering::get_numbering_styles());
$mform->setDefault($name, $this->get_default_value($name, get_config('qtype_ordering', $name)));
$name = 'answerheader';
$label = get_string($name, $plugin);
$elements[] = $mform->createElement('header', $name, $label);

View File

@ -28,6 +28,14 @@ $string['addsingleanswer'] = 'Add one more item';
$string['allornothing'] = 'All or nothing';
$string['answer'] = 'Item text';
$string['answerheader'] = 'Draggable item {no}';
$string['answernumbering'] = 'Number the choices?';
$string['answernumbering123'] = '1., 2., 3., ...';
$string['answernumberingabc'] = 'a., b., c., ...';
$string['answernumberingABCD'] = 'A., B., C., ...';
$string['answernumberingiii'] = 'i., ii., iii., ...';
$string['answernumberingIIII'] = 'I., II., III., ...';
$string['answernumberingnone'] = 'No numbering';
$string['answernumbering_desc'] = 'The default numbering style.';
$string['correctorder'] = 'The correct order for these items is as follows:';

View File

@ -46,6 +46,8 @@ class qtype_ordering_question extends question_graded_automatically {
/** Show answers in one horizontal line */
const LAYOUT_HORIZONTAL = 1;
/** Show answernumbering default */
const ANSWER_NUMBERING_DEFAULT = 'none';
/** @var int Zero grade on any error */
const GRADING_ALL_OR_NOTHING = -1;
@ -541,7 +543,8 @@ class qtype_ordering_question extends question_graded_automatically {
'incorrectfeedback' => '',
'incorrectfeedbackformat' => FORMAT_MOODLE,
'partiallycorrectfeedback' => '',
'partiallycorrectfeedbackformat' => FORMAT_MOODLE
'partiallycorrectfeedbackformat' => FORMAT_MOODLE,
'answernumbering' => self::ANSWER_NUMBERING_DEFAULT
);
$this->options->id = $DB->insert_record('qtype_ordering_options', $this->options);
}

View File

@ -42,6 +42,7 @@ class qtype_ordering extends question_type {
*/
protected function initialise_question_instance(question_definition $question, $questiondata) {
parent::initialise_question_instance($question, $questiondata);
$question->answernumbering = $questiondata->options->answernumbering;
$this->initialise_combined_feedback($question, $questiondata);
}
@ -158,7 +159,6 @@ class qtype_ordering extends question_type {
$DB->set_field('question_answers', 'answer', $answertext, array('id' => $answer->id));
}
}
// Create $options for this ordering question.
$options = (object)array(
'questionid' => $question->id,
@ -166,7 +166,8 @@ class qtype_ordering extends question_type {
'selecttype' => $question->selecttype,
'selectcount' => $question->selectcount,
'gradingtype' => $question->gradingtype,
'showgrading' => $question->showgrading
'showgrading' => $question->showgrading,
'answernumbering' => $question->answernumbering
);
$options = $this->save_combined_feedback_helper($options, $question, $context, true);
$this->save_hints($question, false);
@ -827,4 +828,29 @@ class qtype_ordering extends question_type {
$question->gradingtype = $gradingtype;
$question->showgrading = $showgrading;
}
/**
* Return the answer numbering style
* @param $questiondata
* @return string
*/
public function get_answernumbering($questiondata) {
return $questiondata->options->answernumbering;
}
/**
* @return array of the numbering styles supported. For each one, there
* should be a lang string answernumberingxxx in the qtype_ordering
* language file, and a case in the switch statement in number_in_style,
* and it should be listed in the definition of this column in install.xml.
*/
public static function get_numbering_styles() {
$styles = [];
$numberingoptions = ['abc', 'ABCD', '123', 'iii', 'IIII', \qtype_ordering_question::ANSWER_NUMBERING_DEFAULT];
foreach ($numberingoptions as $numberingoption) {
$styles[$numberingoption] =
get_string('answernumbering' . $numberingoption, 'qtype_ordering');
}
return $styles;
}
}

View File

@ -99,6 +99,7 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
if ($qa->get_state()->is_active()) {
$activeclass = ' orderingactive';
}
$numberingclass = 'numbering' . $question->options->answernumbering;
// Generate ordering items.
foreach ($currentresponse as $position => $answerid) {
@ -136,7 +137,7 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
$img = '';
break;
}
$class = trim("$class $layoutclass");
$class = trim("$class $layoutclass $numberingclass");
// Format the answer text.
$answer = $question->answers[$answerid];

View File

@ -8,8 +8,7 @@
.que.ordering ul.sortablelist {
float : left;
list-style-type : none;
margin : 0;
margin-left : 5px;
margin : 0 0 0 5px;
padding : 4px;
}
.que.ordering ul.sortablelist.orderingactive {
@ -27,7 +26,29 @@
.que.ordering ul.sortablelist li.sortableitem {
position : relative;
cursor : move;
margin-left : 26px; /* The margin is needed for the list-style-type in numberingxxx classes */
}
.que.ordering ul.sortablelist li.sortableitem.numbering123 {
list-style-type : decimal;
}
.que.ordering ul.sortablelist li.sortableitem.numberingabc {
list-style-type : lower-alpha;
}
.que.ordering ul.sortablelist li.sortableitem.numberingABCD {
list-style-type : upper-alpha;
}
.que.ordering ul.sortablelist li.sortableitem.numberingiii {
list-style-type : lower-roman;
}
.que.ordering ul.sortablelist li.sortableitem.numberingIIII {
list-style-type : upper-roman;
}
.que.ordering ul.sortablelist li.sortableitem.numberingnone {
list-style-type : none;
margin-left: 0px;
}
.que.ordering ul.sortablelist li.sortableitem:focus {
border-color: #0a0;
box-shadow: 0 0 5px 5px rgba(255, 255, 150, 1);

View File

@ -70,7 +70,7 @@ class qtype_ordering_test_helper extends question_test_helper {
$q->options->selectcount = 0;
$q->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT;
$q->options->showgrading = true;
$q->options->answernumbering = qtype_ordering_question::ANSWER_NUMBERING_DEFAULT;
return $q;
}
@ -130,6 +130,7 @@ class qtype_ordering_test_helper extends question_test_helper {
$form->selectcount = 0;
$form->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT;
$form->showgrading = true;
$form->answernumbering = qtype_ordering_question::ANSWER_NUMBERING_DEFAULT;
$form->countanswers = 6;
$form->answer = [
@ -174,16 +175,16 @@ class qtype_ordering_test_helper extends question_test_helper {
$questiondata->options->selectcount = 0;
$questiondata->options->gradingtype = qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT;
$questiondata->options->showgrading = true;
$questiondata->options->answernumbering = qtype_ordering_question::ANSWER_NUMBERING_DEFAULT;
$questiondata->options->answers = [
13 => $this->make_answer(13, 'Modular', FORMAT_HTML, 1),
14 => $this->make_answer(14, 'Object', FORMAT_HTML, 2),
15 => $this->make_answer(15, 'Oriented', FORMAT_HTML, 3),
16 => $this->make_answer(16, 'Dynamic', FORMAT_HTML, 4),
17 => $this->make_answer(17, 'Learning', FORMAT_HTML, 5),
18 => $this->make_answer(18, 'Environment', FORMAT_HTML, 6),
13 => $this->make_answer(13, 'Modular', FORMAT_HTML, 1),
14 => $this->make_answer(14, 'Object', FORMAT_HTML, 2),
15 => $this->make_answer(15, 'Oriented', FORMAT_HTML, 3),
16 => $this->make_answer(16, 'Dynamic', FORMAT_HTML, 4),
17 => $this->make_answer(17, 'Learning', FORMAT_HTML, 5),
18 => $this->make_answer(18, 'Environment', FORMAT_HTML, 6),
];
return $questiondata;
}
}

View File

@ -65,7 +65,7 @@ class qtype_ordering_test extends advanced_testcase {
$questiondata = test_question_maker::get_question_data('ordering');
$formdata = test_question_maker::get_question_form_data('ordering');
/* @var core_question_generator $generator */
/** @var core_question_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $generator->create_question_category([]);
@ -160,4 +160,37 @@ class qtype_ordering_test extends advanced_testcase {
);
$this->assertEquals($expectedresponseclasses, $possibleresponses, '', 0.0000005);
}
public function test_get_answernumbering() {
$questiondata = test_question_maker::get_question_data('ordering');
$expected = qtype_ordering_question::ANSWER_NUMBERING_DEFAULT;
$actual = $this->qtype->get_answernumbering($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->answernumbering = 'abc';
$expected = 'abc';
$actual = $this->qtype->get_answernumbering($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->answernumbering = 'ABCD';
$expected = 'ABCD';
$actual = $this->qtype->get_answernumbering($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->answernumbering = '123';
$expected = '123';
$actual = $this->qtype->get_answernumbering($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->answernumbering = 'iii';
$expected = 'iii';
$actual = $this->qtype->get_answernumbering($questiondata);
$this->assertEquals($expected, $actual);
$questiondata->options->answernumbering = 'III';
$expected = 'III';
$actual = $this->qtype->get_answernumbering($questiondata);
$this->assertEquals($expected, $actual);
}
}

View File

@ -29,5 +29,5 @@ $plugin->cron = 0;
$plugin->component = 'qtype_ordering';
$plugin->maturity = MATURITY_STABLE;
$plugin->requires = 2015051100; // Moodle 2.9.
$plugin->version = 2019030689;
$plugin->version = 2019062000;
$plugin->release = '2019-03-06 (89)';