From 131b78b9a70f9ecc2b5e6b7d85d8242eaab14b53 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Fri, 26 Feb 2016 18:21:26 +0800 Subject: [PATCH 1/4] MDL-53254 tags: tag areas inplace editable --- lang/en/tag.php | 2 + lib/amd/build/tag.min.js | 2 +- lib/amd/src/tag.js | 41 +++++++++- tag/classes/areas_table.php | 31 ++------ tag/classes/collection.php | 6 +- tag/classes/collections_table.php | 9 ++- tag/classes/manage_table.php | 2 +- tag/classes/output/tagareacollection.php | 81 ++++++++++++++++++++ tag/classes/output/tagareaenabled.php | 87 ++++++++++++++++++++++ tag/classes/output/tagareashowstandard.php | 82 ++++++++++++++++++++ tag/classes/output/tagname.php | 16 +++- tag/classes/renderer.php | 2 +- tag/lib.php | 13 +++- tag/manage.php | 35 +-------- tag/tests/behat/collections.feature | 28 +++---- tag/tests/behat/standard_tags.feature | 2 + 16 files changed, 352 insertions(+), 87 deletions(-) create mode 100644 tag/classes/output/tagareacollection.php create mode 100644 tag/classes/output/tagareaenabled.php create mode 100644 tag/classes/output/tagareashowstandard.php diff --git a/lang/en/tag.php b/lang/en/tag.php index af4bd3fc3f8..6c52a63e48d 100644 --- a/lang/en/tag.php +++ b/lang/en/tag.php @@ -43,8 +43,10 @@ $string['deleteselected'] = 'Delete selected'; $string['deleted'] = 'Tag(s) deleted'; $string['deletedcoursetags'] = 'Deleted - Course tags'; $string['description'] = 'Description'; +$string['editisstandard'] = 'Change standard tag usage'; $string['editname'] = 'Edit tag name'; $string['edittag'] = 'Edit this tag'; +$string['edittagcollection'] = 'Change tag collection'; $string['entertags'] = 'Enter tags...'; $string['edittagcoll'] = 'Edit tag collection {$a}'; $string['errortagfrontpage'] = 'Tagging the site main page is not allowed'; diff --git a/lib/amd/build/tag.min.js b/lib/amd/build/tag.min.js index 3ba24734dcb..f2950005b15 100644 --- a/lib/amd/build/tag.min.js +++ b/lib/amd/build/tag.min.js @@ -1 +1 @@ -define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{init_tagindex_page:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},init_manage_page:function(){var f=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var g=e.closest("tr").get(0);g&&(d.tags[0].flag?a(g).addClass("flagged-tag"):a(g).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})}}}); \ No newline at end of file +define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){var f=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var g=e.closest("tr").get(0);g&&(d.tags[0].flag?a(g).addClass("flagged-tag"):a(g).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c=b.ajaxreturn;b.oldvalue;if("core_tag"===c.component&&"tagareaenable"===c.itemtype){var d=a(this).attr("data-itemid");a(".tag-collections-table ul[data-collectionid] li[data-areaid="+d+"]").addClass("hidden");var e=c.value;if("1"===e){a(this).closest("tr").removeClass("dimmed_text");var f=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value");a(".tag-collections-table ul[data-collectionid="+f+"] li[data-areaid="+d+"]").removeClass("hidden")}else a(this).closest("tr").addClass("dimmed_text")}if("core_tag"===c.component&&"tagareacollection"===c.itemtype){var d=a(this).attr("data-itemid");a(".tag-collections-table ul[data-collectionid] li[data-areaid="+d+"]").addClass("hidden");var f=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value");"1"===e&&a(".tag-collections-table ul[data-collectionid="+f+"] li[data-areaid="+d+"]").removeClass("hidden")}})}}}); \ No newline at end of file diff --git a/lib/amd/src/tag.js b/lib/amd/src/tag.js index b0f357c6f90..15154e8b336 100644 --- a/lib/amd/src/tag.js +++ b/lib/amd/src/tag.js @@ -29,9 +29,9 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' /** * Initialises tag index page. * - * @method init_tagindex_page + * @method initTagindexPage */ - init_tagindex_page: function() { + initTagindexPage: function() { // Click handler for changing tag type. $('body').delegate('.tagarea[data-ta] a[data-quickload=1]', 'click', function(e) { e.preventDefault(); @@ -57,9 +57,9 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' /** * Initialises tag management page. * - * @method init_manage_page + * @method initManagePage */ - init_manage_page: function() { + initManagePage: function() { var update_modified = function(el) { var row = el.closest('tr').get(0); @@ -174,6 +174,39 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' } ); }); + }, + + /** + * Initialises tag collection management page. + * + * @method initManageCollectionsPage + */ + initManageCollectionsPage: function() { + $('body').on('updated', '[data-inplaceeditable]', function(e) { + var ajaxreturn = e.ajaxreturn; + var oldvalue = e.oldvalue; + if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareaenable') { + var areaid = $(this).attr('data-itemid'); + $(".tag-collections-table ul[data-collectionid] li[data-areaid="+areaid+"]").addClass('hidden'); + var isenabled = ajaxreturn.value; + if (isenabled === '1') { + $(this).closest('tr').removeClass('dimmed_text'); + var collid = $(this).closest('tr').find('[data-itemtype="tagareacollection"]').attr("data-value"); + $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]").removeClass('hidden'); + } else { + $(this).closest('tr').addClass('dimmed_text'); + } + } + if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareacollection') { + var areaid = $(this).attr('data-itemid'); + $(".tag-collections-table ul[data-collectionid] li[data-areaid="+areaid+"]").addClass('hidden'); + var collid = $(this).attr('data-value'); + var isenabled = $(this).closest('tr').find('[data-itemtype="tagareaenable"]').attr("data-value"); + if (isenabled === "1") { + $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]").removeClass('hidden'); + } + } + }); } }; }); \ No newline at end of file diff --git a/tag/classes/areas_table.php b/tag/classes/areas_table.php index 6ae1149c21a..63484c580f8 100644 --- a/tag/classes/areas_table.php +++ b/tag/classes/areas_table.php @@ -69,34 +69,15 @@ class core_tag_areas_table extends html_table { foreach ($tagareas as $itemtype => $it) { foreach ($it as $component => $record) { $areaname = core_tag_area::display_name($record->component, $record->itemtype); - $baseurl = new moodle_url($pageurl, array('ta' => $record->id, 'sesskey' => sesskey())); - if ($record->enabled) { - $enableurl = new moodle_url($baseurl, array('action' => 'areadisable')); - $enabled = html_writer::link($enableurl, $OUTPUT->pix_icon('i/hide', get_string('disable'))); - } else { - $enableurl = new moodle_url($baseurl, array('action' => 'areaenable')); - $enabled = html_writer::link($enableurl, $OUTPUT->pix_icon('i/show', get_string('enable'))); - } - if ($record->enabled && empty($record->locked) && count($tagcollections) > 1) { - $changecollurl = new moodle_url($baseurl, array('action' => 'areasetcoll')); + $tmpl = new \core_tag\output\tagareaenabled($record); + $enabled = $OUTPUT->render_from_template('core/inplace_editable', $tmpl->export_for_template($OUTPUT)); - $select = new single_select($changecollurl, 'areacollid', $tagcollections, $record->tagcollid, null); - $select->set_label(get_string('changetagcoll', 'core_tag', $areaname), array('class' => 'accesshide')); - $collectionselect = $OUTPUT->render($select); - } else { - $collectionselect = $tagcollectionsall[$record->tagcollid]; - } + $tmpl = new \core_tag\output\tagareacollection($record); + $collectionselect = $OUTPUT->render_from_template('core/inplace_editable', $tmpl->export_for_template($OUTPUT)); - if ($record->enabled) { - $changeshowstandardurl = new moodle_url($baseurl, array('action' => 'areasetshowstandard')); - $select = new single_select($changeshowstandardurl, 'showstandard', $standardchoices, - $record->showstandard, null); - $select->set_label(get_string('changeshowstandard', 'core_tag', $areaname), array('class' => 'accesshide')); - $showstandardselect = $OUTPUT->render($select); - } else { - $showstandardselect = $standardchoices[$record->showstandard]; - } + $tmpl = new \core_tag\output\tagareashowstandard($record); + $showstandardselect = $OUTPUT->render_from_template('core/inplace_editable', $tmpl->export_for_template($OUTPUT)); $this->data[] = array( $areaname, diff --git a/tag/classes/collection.php b/tag/classes/collection.php index 2e503dd2bfd..902a1a71086 100644 --- a/tag/classes/collection.php +++ b/tag/classes/collection.php @@ -174,12 +174,12 @@ class core_tag_collection { * @param int $tagcollid * @return array */ - public static function get_areas_names($tagcollid) { - $allitemtypes = core_tag_area::get_areas($tagcollid, true); + public static function get_areas_names($tagcollid, $enabledonly = true) { + $allitemtypes = core_tag_area::get_areas($tagcollid, $enabledonly); $itemtypes = array(); foreach ($allitemtypes as $itemtype => $it) { foreach ($it as $component => $v) { - $itemtypes[] = core_tag_area::display_name($component, $itemtype); + $itemtypes[$v->id] = core_tag_area::display_name($component, $itemtype); } } return $itemtypes; diff --git a/tag/classes/collections_table.php b/tag/classes/collections_table.php index 28ae760e0c7..79e08690071 100644 --- a/tag/classes/collections_table.php +++ b/tag/classes/collections_table.php @@ -87,10 +87,17 @@ class core_tag_collections_table extends html_table { $component = ($tagcoll->component === 'core' || preg_match('/^core_/', $tagcoll->component)) ? get_string('coresystem') : get_string('pluginname', $tagcoll->component); } + $allareas = core_tag_collection::get_areas_names(null, false); + $validareas = core_tag_collection::get_areas_names($tagcoll->id); + $areaslist = array_map(function($key) use ($allareas, $validareas) { + return "
  • {$allareas[$key]}
  • "; + }, array_keys($allareas)); $this->data[] = array( html_writer::link($manageurl, $name), $component, - join(', ', core_tag_collection::get_areas_names($tagcoll->id)), + "', $tagcoll->searchable ? get_string('yes') : '-', $actions); $idx++; diff --git a/tag/classes/manage_table.php b/tag/classes/manage_table.php index f75ec21b6c5..809d74d2a43 100644 --- a/tag/classes/manage_table.php +++ b/tag/classes/manage_table.php @@ -99,7 +99,7 @@ class core_tag_manage_table extends table_sql { $this->collapsible(true); - $PAGE->requires->js_call_amd('core/tag', 'init_manage_page', array()); + $PAGE->requires->js_call_amd('core/tag', 'initManagePage', array()); } diff --git a/tag/classes/output/tagareacollection.php b/tag/classes/output/tagareacollection.php new file mode 100644 index 00000000000..cb845ad9482 --- /dev/null +++ b/tag/classes/output/tagareacollection.php @@ -0,0 +1,81 @@ +. + +/** + * Contains class core_tag\output\tagareacollection + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; +use lang_string; +use core_tag_area; + +/** + * Class to display collection select for the tag area + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagareacollection extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass $tagarea + */ + public function __construct($tagarea) { + $tagcollections = \core_tag_collection::get_collections_menu(true); + $editable = (count($tagcollections) > 1) && empty($tagarea->locked) && + has_capability('moodle/tag:manage', context_system::instance()); + $areaname = core_tag_area::display_name($tagarea->component, $tagarea->itemtype); + $edithint = new lang_string('edittagcollection', 'core_tag'); + $editlabel = new lang_string('changetagcoll', 'core_tag', $areaname); + $value = $tagarea->tagcollid; + + parent::__construct('core_tag', 'tagareacollection', $tagarea->id, $editable, + null, $value, $edithint, $editlabel); + $this->set_type_select($tagcollections); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + global $DB; + require_capability('moodle/tag:manage', \context_system::instance()); + $tagarea = $DB->get_record('tag_area', array('id' => $itemid), '*', MUST_EXIST); + $newvalue = clean_param($newvalue, PARAM_INT); + $tagcollections = \core_tag_collection::get_collections_menu(true); + if (!array_key_exists($newvalue, $tagcollections)) { + throw new \moodle_exception('invalidparameter', 'debug'); + } + $data = array('tagcollid' => $newvalue); + core_tag_area::update($tagarea, $data); + $tagarea->tagcollid = $newvalue; + $tmpl = new self($tagarea); + return $tmpl; + } +} diff --git a/tag/classes/output/tagareaenabled.php b/tag/classes/output/tagareaenabled.php new file mode 100644 index 00000000000..187a9eea2fd --- /dev/null +++ b/tag/classes/output/tagareaenabled.php @@ -0,0 +1,87 @@ +. + +/** + * Contains class core_tag\output\tagareaenabled + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; + +/** + * Class to display tag area enabled control + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagareaenabled extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass $tagarea + */ + public function __construct($tagarea) { + $editable = has_capability('moodle/tag:manage', context_system::instance()); + $value = $tagarea->enabled ? 1 : 0; + + parent::__construct('core_tag', 'tagareaenable', $tagarea->id, $editable, '', $value); + $this->set_type_toggle(); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output + * @return \stdClass + */ + public function export_for_template(\renderer_base $output) { + if ($this->value) { + $this->edithint = get_string('disable'); + $this->displayvalue = $output->pix_icon('i/hide', get_string('disable')); + } else { + $this->edithint = get_string('enable'); + $this->displayvalue = $output->pix_icon('i/show', get_string('enable')); + } + + return parent::export_for_template($output); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + global $DB; + require_capability('moodle/tag:manage', context_system::instance()); + $tagarea = $DB->get_record('tag_area', array('id' => $itemid), '*', MUST_EXIST); + $newvalue = $newvalue ? 1 : 0; + $data = array('enabled' => $newvalue); + \core_tag_area::update($tagarea, $data); + $tagarea->enabled = $newvalue; + $tmpl = new self($tagarea); + return $tmpl; + } +} diff --git a/tag/classes/output/tagareashowstandard.php b/tag/classes/output/tagareashowstandard.php new file mode 100644 index 00000000000..91947f05ccb --- /dev/null +++ b/tag/classes/output/tagareashowstandard.php @@ -0,0 +1,82 @@ +. + +/** + * Contains class core_tag\output\tagareashowstandard + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; +use lang_string; +use core_tag_tag; +use core_tag_area; + +/** + * Class to display tag area show standard control + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagareashowstandard extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass $tagarea + */ + public function __construct($tagarea) { + $editable = has_capability('moodle/tag:manage', context_system::instance()); + $edithint = new lang_string('editisstandard', 'core_tag'); + $value = $tagarea->showstandard; + $areaname = core_tag_area::display_name($tagarea->component, $tagarea->itemtype); + $editlabel = new lang_string('changeshowstandard', 'core_tag', $areaname); + + parent::__construct('core_tag', 'tagareashowstandard', $tagarea->id, $editable, + null, $value, $edithint, $editlabel); + + $standardchoices = array( + core_tag_tag::BOTH_STANDARD_AND_NOT => get_string('standardsuggest', 'tag'), + core_tag_tag::STANDARD_ONLY => get_string('standardforce', 'tag'), + core_tag_tag::HIDE_STANDARD => get_string('standardhide', 'tag') + ); + $this->set_type_select($standardchoices); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + global $DB; + require_capability('moodle/tag:manage', context_system::instance()); + $tagarea = $DB->get_record('tag_area', array('id' => $itemid), '*', MUST_EXIST); + $newvalue = clean_param($newvalue, PARAM_INT); + $data = array('showstandard' => $newvalue); + core_tag_area::update($tagarea, $data); + $tagarea->showstandard = $newvalue; + $tmpl = new self($tagarea); + return $tmpl; + } +} diff --git a/tag/classes/output/tagname.php b/tag/classes/output/tagname.php index 5e3af29bc77..21514d6d362 100644 --- a/tag/classes/output/tagname.php +++ b/tag/classes/output/tagname.php @@ -41,7 +41,7 @@ class tagname extends \core\output\inplace_editable { /** * Constructor. * - * @param stdClass|core_tag $tag + * @param \stdClass|core_tag_tag $tag */ public function __construct($tag) { $editable = has_capability('moodle/tag:manage', context_system::instance()); @@ -52,4 +52,18 @@ class tagname extends \core\output\inplace_editable { core_tag_tag::make_display_name($tag)); parent::__construct('core_tag', 'tagname', $tag->id, $editable, $displayvalue, $value, $edithint, $editlabel); } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + require_capability('moodle/tag:manage', context_system::instance()); + $tag = core_tag_tag::get($itemid, '*', MUST_EXIST); + $tag->update(array('rawname' => $newvalue)); + return new self($tag); + } } diff --git a/tag/classes/renderer.php b/tag/classes/renderer.php index f1eae09e8ec..05f3074e846 100644 --- a/tag/classes/renderer.php +++ b/tag/classes/renderer.php @@ -76,7 +76,7 @@ class core_tag_renderer extends plugin_renderer_base { */ public function tag_index_page($tag, $entities, $tagareaid, $exclusivemode, $fromctx, $ctx, $rec, $page) { global $CFG, $OUTPUT; - $this->page->requires->js_call_amd('core/tag', 'init_tagindex_page'); + $this->page->requires->js_call_amd('core/tag', 'initTagindexPage'); $tagname = $tag->get_display_name(); $systemcontext = context_system::instance(); diff --git a/tag/lib.php b/tag/lib.php index 107a0f5d28d..e67af3ae8f4 100644 --- a/tag/lib.php +++ b/tag/lib.php @@ -44,6 +44,8 @@ function tag_page_type_list($pagetype, $parentcontext, $currentcontext) { /** * Implements callback inplace_editable() allowing to edit values in-place * + * @global moodle_database $DB + * * @param string $itemtype * @param int $itemid * @param mixed $newvalue @@ -51,9 +53,12 @@ function tag_page_type_list($pagetype, $parentcontext, $currentcontext) { */ function core_tag_inplace_editable($itemtype, $itemid, $newvalue) { if ($itemtype === 'tagname') { - require_capability('moodle/tag:manage', context_system::instance()); - $tag = core_tag_tag::get($itemid, '*', MUST_EXIST); - $tag->update(array('rawname' => $newvalue)); - return new \core_tag\output\tagname($tag); + return \core_tag\output\tagname::update($itemid, $newvalue); + } else if ($itemtype === 'tagareaenable') { + return \core_tag\output\tagareaenabled::update($itemid, $newvalue); + } else if ($itemtype === 'tagareacollection') { + return \core_tag\output\tagareacollection::update($itemid, $newvalue); + } else if ($itemtype === 'tagareashowstandard') { + return \core_tag\output\tagareashowstandard::update($itemid, $newvalue); } } diff --git a/tag/manage.php b/tag/manage.php index 7066fafdc30..d3f06c1b37a 100644 --- a/tag/manage.php +++ b/tag/manage.php @@ -138,39 +138,6 @@ switch($action) { redirect($manageurl); break; - case 'areaenable': - case 'areadisable': - if ($tagarea) { - require_sesskey(); - $data = array('enabled' => ($action === 'areaenable') ? 1 : 0); - core_tag_area::update($tagarea, $data); - redirect(new moodle_url($manageurl, array('notice' => 'changessaved'))); - } - redirect($manageurl); - break; - - case 'areasetcoll': - if ($tagarea) { - require_sesskey(); - if ($newtagcollid = optional_param('areacollid', null, PARAM_INT)) { - core_tag_area::update($tagarea, array('tagcollid' => $newtagcollid)); - redirect(new moodle_url($manageurl, array('notice' => 'changessaved'))); - } - } - redirect($manageurl); - break; - - case 'areasetshowstandard': - if ($tagarea) { - require_sesskey(); - if (($showstandard = optional_param('showstandard', null, PARAM_INT)) !== null) { - core_tag_area::update($tagarea, array('showstandard' => $showstandard)); - redirect(new moodle_url($manageurl, array('notice' => 'changessaved'))); - } - } - redirect($manageurl); - break; - case 'delete': require_sesskey(); if (!$tagschecked && $tagid) { @@ -243,6 +210,8 @@ if (!$tagcoll) { echo $OUTPUT->heading(get_string('tagareas', 'core_tag'), 3); echo html_writer::table($tagareastable); + $PAGE->requires->js_call_amd('core/tag', 'initManageCollectionsPage', array()); + echo $OUTPUT->footer(); exit; } diff --git a/tag/tests/behat/collections.feature b/tag/tests/behat/collections.feature index 4a4275b6713..28e7e78434f 100644 --- a/tag/tests/behat/collections.feature +++ b/tag/tests/behat/collections.feature @@ -60,26 +60,27 @@ Feature: Managers can create and manage tag collections @javascript Scenario: Assigning tag area to tag collection - And "User interests" "text" should exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" - And "User interests" "text" should not exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" - When I set the field "Change tag collection of area User interests" to "Hobbies" - Then "User interests" "text" should not exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" - And "User interests" "text" should exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" - And the field "Change tag collection of area User interests" matches value "Hobbies" + And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" + And I should not see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" + When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" + And I set the field "Change tag collection of area User interests" to "Hobbies" + Then I should not see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" + And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" + And I should see "Hobbies" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" And I log out + @javascript Scenario: Disabling tag areas - And "Change tag collection of area User interests" "select" should exist When I click on "Disable" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" - Then "Change tag collection of area User interests" "select" should not exist - And "User interests" "text" should not exist in the "table.tag-collections-table" "css_element" + And I should see "User interests" in the "table.tag-collections-table" "css_element" And I click on "Enable" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" - And "User interests" "text" should exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" - And "Change tag collection of area User interests" "select" should exist + And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" And I log out + @javascript Scenario: Deleting non-empty tag collections - When I set the field "Change tag collection of area User interests" to "Hobbies" + When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" + And I set the field "Change tag collection of area User interests" to "Hobbies" And I click on "Delete" "link" in the "Hobbies" "table_row" Then I should see "Are you sure you want to delete tag collection \"Hobbies\"?" And I press "Yes" @@ -95,7 +96,8 @@ Feature: Managers can create and manage tag collections And I set the field "List of interests" to "Swimming, Tag0, Tag3" And I press "Update profile" And I navigate to "Manage tags" node in "Site administration > Appearance" - When I set the field "Change tag collection of area User interests" to "Hobbies" + When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" + And I set the field "Change tag collection of area User interests" to "Hobbies" And I follow "Hobbies" Then I should see "Swimming" And I should see "Tag0" diff --git a/tag/tests/behat/standard_tags.feature b/tag/tests/behat/standard_tags.feature index 3c9e9728f07..310faf2096e 100644 --- a/tag/tests/behat/standard_tags.feature +++ b/tag/tests/behat/standard_tags.feature @@ -114,6 +114,7 @@ Feature: Manager can add standard tags and change the tag type of existing tags | List of interests | Tag3 , Tag2 | And I press "Update profile" And I navigate to "Manage tags" node in "Site administration > Appearance" + And I click on "Change standard tag usage" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" And the field "Change showing standard tags in area User interests" matches value "Don't suggest" And I set the field "Change showing standard tags in area User interests" to "Suggest" And I follow "Profile" in the user menu @@ -121,6 +122,7 @@ Feature: Manager can add standard tags and change the tag type of existing tags And I expand all fieldsets And I should see "Manage standard tags" And I navigate to "Manage tags" node in "Site administration > Appearance" + And I click on "Change standard tag usage" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" And the field "Change showing standard tags in area User interests" matches value "Suggest" And I set the field "Change showing standard tags in area User interests" to "Force" And I follow "Profile" in the user menu From 352bfbf55c965429e7353acd4764cf08764b527c Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Fri, 26 Feb 2016 22:02:12 +0800 Subject: [PATCH 2/4] MDL-53254 tags: tag collections inplace editable --- lang/en/tag.php | 3 + lib/amd/build/tag.min.js | 2 +- lib/amd/src/tag.js | 82 +++++++++++++++++++--- lib/classes/output/inplace_editable.php | 10 +++ tag/classes/collection.php | 4 +- tag/classes/collection_form.php | 79 ---------------------- tag/classes/collections_table.php | 23 ++++--- tag/classes/output/tagcollname.php | 72 ++++++++++++++++++++ tag/classes/output/tagcollsearchable.php | 86 ++++++++++++++++++++++++ tag/lib.php | 4 ++ tag/manage.php | 69 ++++++------------- tag/tests/behat/collections.feature | 29 +++----- 12 files changed, 293 insertions(+), 170 deletions(-) delete mode 100644 tag/classes/collection_form.php create mode 100644 tag/classes/output/tagcollname.php create mode 100644 tag/classes/output/tagcollsearchable.php diff --git a/lang/en/tag.php b/lang/en/tag.php index 6c52a63e48d..ccc683637c7 100644 --- a/lang/en/tag.php +++ b/lang/en/tag.php @@ -44,7 +44,9 @@ $string['deleted'] = 'Tag(s) deleted'; $string['deletedcoursetags'] = 'Deleted - Course tags'; $string['description'] = 'Description'; $string['editisstandard'] = 'Change standard tag usage'; +$string['editcollname'] = 'Edit tag collection name'; $string['editname'] = 'Edit tag name'; +$string['editsearchable'] = 'Change searchable'; $string['edittag'] = 'Edit this tag'; $string['edittagcollection'] = 'Change tag collection'; $string['entertags'] = 'Enter tags...'; @@ -78,6 +80,7 @@ $string['managetagcolls'] = 'Manage tag collections'; $string['moretags'] = 'more...'; $string['name'] = 'Tag name'; $string['namesalreadybeeingused'] = 'Tag names already being used'; +$string['newcollnamefor'] = 'New name for tag collection {$a}'; $string['newnamefor'] = 'New name for tag {$a}'; $string['nextpage'] = 'More'; $string['notagsfound'] = 'No tags matching "{$a}" found'; diff --git a/lib/amd/build/tag.min.js b/lib/amd/build/tag.min.js index f2950005b15..d5fa9fb66a4 100644 --- a/lib/amd/build/tag.min.js +++ b/lib/amd/build/tag.min.js @@ -1 +1 @@ -define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){var f=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var g=e.closest("tr").get(0);g&&(d.tags[0].flag?a(g).addClass("flagged-tag"):a(g).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c=b.ajaxreturn;b.oldvalue;if("core_tag"===c.component&&"tagareaenable"===c.itemtype){var d=a(this).attr("data-itemid");a(".tag-collections-table ul[data-collectionid] li[data-areaid="+d+"]").addClass("hidden");var e=c.value;if("1"===e){a(this).closest("tr").removeClass("dimmed_text");var f=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value");a(".tag-collections-table ul[data-collectionid="+f+"] li[data-areaid="+d+"]").removeClass("hidden")}else a(this).closest("tr").addClass("dimmed_text")}if("core_tag"===c.component&&"tagareacollection"===c.itemtype){var d=a(this).attr("data-itemid");a(".tag-collections-table ul[data-collectionid] li[data-areaid="+d+"]").addClass("hidden");var f=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value");"1"===e&&a(".tag-collections-table ul[data-collectionid="+f+"] li[data-areaid="+d+"]").removeClass("hidden")}})}}}); \ No newline at end of file +define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){var f=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var g=e.closest("tr").get(0);g&&(d.tags[0].flag?a(g).addClass("flagged-tag"):a(g).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c,d,e,f=b.ajaxreturn;b.oldvalue;"core_tag"===f.component&&"tagareaenable"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),e=f.value,"1"===e?(a(this).closest("tr").removeClass("dimmed_text"),d=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value"),a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden")):a(this).closest("tr").addClass("dimmed_text")),"core_tag"===f.component&&"tagareacollection"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),d=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value"),"1"===e&&a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden"))}),a("body").on("click",".addtagcoll > a",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"addtagcoll",component:"tag"},{key:"name"},{key:"searchable",component:"tag"},{key:"create"},{key:"cancel"}]).done(function(b){var d=a('

    :
    :

    ');d.find('label[for="addtagcoll_name"]').html(b[1]),d.find('label[for="addtagcoll_searchable"]').html(b[2]),d.find("#addtagcoll_submit").attr("value",b[3]),d.find("#addtagcoll_cancel").attr("value",b[4]);var e=new M.core.dialogue({draggable:!0,modal:!0,closeButton:!0,headerContent:b[0],bodyContent:d.html()});e.show(),a("#addtagcoll_form #addtagcoll_name").focus(),a("#addtagcoll_form #addtagcoll_cancel").on("click",function(){e.destroy()}),a("#addtagcoll_form").on("submit",function(){var b=a("#addtagcoll_form #addtagcoll_name").val(),d=a("#addtagcoll_form #addtagcoll_searchable").prop("checked")?1:0;return String(b).length>0&&(window.location.href=c+"&name="+encodeURIComponent(b)+"&searchable="+d),!1})})}),a("body").on("click",".tag-collections-table .action_delete",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"delete"},{key:"suredeletecoll",component:"tag",param:a(this).attr("data-collname")},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})})}}}); \ No newline at end of file diff --git a/lib/amd/src/tag.js b/lib/amd/src/tag.js index 15154e8b336..08ff1a405f7 100644 --- a/lib/amd/src/tag.js +++ b/lib/amd/src/tag.js @@ -183,30 +183,94 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' */ initManageCollectionsPage: function() { $('body').on('updated', '[data-inplaceeditable]', function(e) { - var ajaxreturn = e.ajaxreturn; - var oldvalue = e.oldvalue; + var ajaxreturn = e.ajaxreturn, + oldvalue = e.oldvalue, + areaid, collid, isenabled; if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareaenable') { - var areaid = $(this).attr('data-itemid'); + areaid = $(this).attr('data-itemid'); $(".tag-collections-table ul[data-collectionid] li[data-areaid="+areaid+"]").addClass('hidden'); - var isenabled = ajaxreturn.value; + isenabled = ajaxreturn.value; if (isenabled === '1') { $(this).closest('tr').removeClass('dimmed_text'); - var collid = $(this).closest('tr').find('[data-itemtype="tagareacollection"]').attr("data-value"); + collid = $(this).closest('tr').find('[data-itemtype="tagareacollection"]').attr("data-value"); $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]").removeClass('hidden'); } else { $(this).closest('tr').addClass('dimmed_text'); } } if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareacollection') { - var areaid = $(this).attr('data-itemid'); + areaid = $(this).attr('data-itemid'); $(".tag-collections-table ul[data-collectionid] li[data-areaid="+areaid+"]").addClass('hidden'); - var collid = $(this).attr('data-value'); - var isenabled = $(this).closest('tr').find('[data-itemtype="tagareaenable"]').attr("data-value"); + collid = $(this).attr('data-value'); + isenabled = $(this).closest('tr').find('[data-itemtype="tagareaenable"]').attr("data-value"); if (isenabled === "1") { $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]").removeClass('hidden'); } } - }); + }); + + $('body').on('click', '.addtagcoll > a', function(e) { + e.preventDefault(); + var href = $(this).attr('data-url') + '&sesskey=' + M.cfg.sesskey; + str.get_strings([ + {key : 'addtagcoll', component : 'tag'}, + {key : 'name'}, + {key : 'searchable', component : 'tag'}, + {key : 'create'}, + {key : 'cancel'}, + ]).done(function(s) { + var el = $('
    '+ + '

    : ' + + '
    ' + + ': ' + + '

    ' + + '

    '+ + '

    ' + + '
    '); + el.find('label[for="addtagcoll_name"]').html(s[1]); + el.find('label[for="addtagcoll_searchable"]').html(s[2]); + el.find('#addtagcoll_submit').attr('value', s[3]); + el.find('#addtagcoll_cancel').attr('value', s[4]); + var panel = new M.core.dialogue ({ + draggable: true, + modal: true, + closeButton: true, + headerContent: s[0], + bodyContent: el.html() + }); + panel.show(); + $('#addtagcoll_form #addtagcoll_name').focus(); + $('#addtagcoll_form #addtagcoll_cancel').on('click', function() { + panel.destroy(); + }); + $('#addtagcoll_form').on('submit', function() { + var name = $('#addtagcoll_form #addtagcoll_name').val(); + var searchable = $('#addtagcoll_form #addtagcoll_searchable').prop('checked') ? 1 : 0; + if (String(name).length > 0) { + window.location.href = href + "&name=" + encodeURIComponent(name) + "&searchable=" + searchable; + } + return false; + }); + } + ); + + }); + + $('body').on('click', '.tag-collections-table .action_delete', function(e) { + e.preventDefault(); + var href = $(this).attr('data-url') + '&sesskey=' + M.cfg.sesskey; + str.get_strings([ + {key : 'delete'}, + {key : 'suredeletecoll', component : 'tag', param : $(this).attr('data-collname') }, + {key : 'yes'}, + {key : 'no'}, + ]).done(function(s) { + notification.confirm(s[0], s[1], s[2], s[3], function() { + window.location.href = href; + }); + } + ); + }); } }; }); \ No newline at end of file diff --git a/lib/classes/output/inplace_editable.php b/lib/classes/output/inplace_editable.php index b32ed158189..4e0d6d553c2 100644 --- a/lib/classes/output/inplace_editable.php +++ b/lib/classes/output/inplace_editable.php @@ -226,4 +226,14 @@ class inplace_editable implements templatable, renderable { 'linkeverything' => $this->get_linkeverything() ? 1 : 0, ); } + + /** + * Renders this element + * + * @param renderer_base $output typically, the renderer that's calling this function + * @return string + */ + public function render(\renderer_base $output) { + return $output->render_from_template('core/inplace_editable', $this->export_for_template($output)); + } } diff --git a/tag/classes/collection.php b/tag/classes/collection.php index 902a1a71086..2dd55d27f63 100644 --- a/tag/classes/collection.php +++ b/tag/classes/collection.php @@ -143,7 +143,7 @@ class core_tag_collection { return get_string($identifier, $component); } if (!empty($record->name)) { - return format_string($record->name, true, $syscontext); + return format_string($record->name, true, array('context' => $syscontext)); } else if ($record->isdefault) { return get_string('defautltagcoll', 'tag'); } else { @@ -216,7 +216,7 @@ class core_tag_collection { * Updates the tag collection information * * @param stdClass $tagcoll existing record in DB table tag_coll - * @param stdClass $data data from form core_tag_collection_form + * @param stdClass $data data to update * @return bool wether the record was updated */ public static function update($tagcoll, $data) { diff --git a/tag/classes/collection_form.php b/tag/classes/collection_form.php deleted file mode 100644 index 04a95b75aeb..00000000000 --- a/tag/classes/collection_form.php +++ /dev/null @@ -1,79 +0,0 @@ -. - -/** - * Contains class core_tag_collection_form - * - * @package core - * @copyright 2015 Marina Glancy - * @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 tag collection - * - * @package core - * @copyright 2015 Marina Glancy - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class core_tag_collection_form extends moodleform { - - /** - * Form definition - */ - public function definition() { - $data = fullclone($this->_customdata); - if (isset($data->id)) { - $data->tc = $data->id; - $data->action = 'colledit'; - } else { - $data = new stdClass(); - $data->action = 'colladd'; - $data->isdefault = false; - } - - $mform = $this->_form; - $mform->addElement('hidden', 'tc'); - $mform->setType('tc', PARAM_INT); - $mform->addElement('hidden', 'action'); - $mform->setType('action', PARAM_ALPHA); - - $mform->addElement('text', 'name', get_string('name')); - $mform->setType('name', PARAM_NOTAGS); - $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client'); - if (empty($data->isdefault)) { - $mform->addRule('name', get_string('required'), 'required', null, 'client'); - } else { - $mform->addElement('static', 'collnameexplained', '', get_string('collnameexplained', 'tag', - get_string('defautltagcoll', 'tag'))); - } - - $mform->addElement('advcheckbox', 'searchable', get_string('searchable', 'tag')); - $mform->addHelpButton('searchable', 'searchable', 'tag'); - $mform->setDefault('searchable', 1); - if (!empty($data->isdefault)) { - $mform->freeze('searchable'); - } - - $this->add_action_buttons(); - - $this->set_data($data); - } -} diff --git a/tag/classes/collections_table.php b/tag/classes/collections_table.php index 79e08690071..78cdaca9d56 100644 --- a/tag/classes/collections_table.php +++ b/tag/classes/collections_table.php @@ -35,6 +35,7 @@ class core_tag_collections_table extends html_table { /** * Constructor + * @global \core_renderer $OUTPUT * @param string|moodle_url $pageurl */ public function __construct($pageurl) { @@ -63,25 +64,23 @@ class core_tag_collections_table extends html_table { // Move up. if ($idx > 1) { $url->param('action', 'collmoveup'); - $actions .= $OUTPUT->action_icon($url, new pix_icon('t/up', get_string('moveup'))); + $actions .= $OUTPUT->action_icon($url, new pix_icon('t/up', get_string('moveup')), null, + array('class' => 'action-icon action_moveup')); } // Move down. if ($idx < count($tagcolls) - 1) { $url->param('action', 'collmovedown'); - $actions .= $OUTPUT->action_icon($url, new pix_icon('t/down', get_string('movedown'))); + $actions .= $OUTPUT->action_icon($url, new pix_icon('t/down', get_string('movedown')), null, + array('class' => 'action-icon action_movedown')); } } - if (empty($tagcoll->component)) { - // Edit. - $url->param('action', 'colledit'); - $actions .= $OUTPUT->action_icon($url, new pix_icon('t/edit', get_string('edittagcoll', 'tag', $name))); - } if (!$tagcoll->isdefault && empty($tagcoll->component)) { // Delete. $url->param('action', 'colldelete'); - $actions .= $OUTPUT->action_icon($url, new pix_icon('t/delete', get_string('delete'))); + $actions .= $OUTPUT->action_icon('#', new pix_icon('t/delete', get_string('delete')), null, + array('data-url' => $url, 'data-collname' => $name, + 'class' => 'action-icon action_delete')); } - $manageurl = new moodle_url('/tag/manage.php', array('tc' => $tagcoll->id)); $component = ''; if ($tagcoll->component) { $component = ($tagcoll->component === 'core' || preg_match('/^core_/', $tagcoll->component)) ? @@ -94,11 +93,13 @@ class core_tag_collections_table extends html_table { (array_key_exists($key, $validareas) ? "" : "class=\"hidden\"") . ">{$allareas[$key]}"; }, array_keys($allareas)); + $displayname = new \core_tag\output\tagcollname($tagcoll); + $searchable = new \core_tag\output\tagcollsearchable($tagcoll); $this->data[] = array( - html_writer::link($manageurl, $name), + $displayname->render($OUTPUT), $component, "', - $tagcoll->searchable ? get_string('yes') : '-', + $searchable->render($OUTPUT), $actions); $idx++; } diff --git a/tag/classes/output/tagcollname.php b/tag/classes/output/tagcollname.php new file mode 100644 index 00000000000..dc30b8c8e5c --- /dev/null +++ b/tag/classes/output/tagcollname.php @@ -0,0 +1,72 @@ +. + +/** + * Contains class core_tag\output\tagcollname + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; +use lang_string; +use html_writer; +use core_tag_collection; +use moodle_url; + +/** + * Class to preapare a tag name for display. + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagcollname extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass $tagcoll + */ + public function __construct($tagcoll) { + $editable = has_capability('moodle/tag:manage', context_system::instance()); + $edithint = new lang_string('editcollname', 'core_tag'); + $value = $tagcoll->name; + $name = \core_tag_collection::display_name($tagcoll); + $editlabel = new lang_string('newcollnamefor', 'core_tag', $name); + $manageurl = new moodle_url('/tag/manage.php', array('tc' => $tagcoll->id)); + $displayvalue = html_writer::link($manageurl, $name); + parent::__construct('core_tag', 'tagcollname', $tagcoll->id, $editable, $displayvalue, $value, $edithint, $editlabel); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + global $DB; + require_capability('moodle/tag:manage', context_system::instance()); + $tagcoll = $DB->get_record('tag_coll', array('id' => $itemid), '*', MUST_EXIST); + \core_tag_collection::update($tagcoll, array('name' => $newvalue)); + return new self($tagcoll); + } +} diff --git a/tag/classes/output/tagcollsearchable.php b/tag/classes/output/tagcollsearchable.php new file mode 100644 index 00000000000..87c4ce6f22c --- /dev/null +++ b/tag/classes/output/tagcollsearchable.php @@ -0,0 +1,86 @@ +. + +/** + * Contains class core_tag\output\tagcollsearchable + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; +use lang_string; +use core_tag_collection; + +/** + * Class to display tag collection searchable control + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagcollsearchable extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass $tagcoll + */ + public function __construct($tagcoll) { + $defaultid = core_tag_collection::get_default(); + $editable = $tagcoll->id != $defaultid && + has_capability('moodle/tag:manage', context_system::instance()); + $edithint = new lang_string('editsearchable', 'core_tag'); + $value = $tagcoll->searchable ? 1 : 0; + + parent::__construct('core_tag', 'tagcollsearchable', $tagcoll->id, $editable, $value, $value, $edithint); + $this->set_type_toggle(); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output + * @return \stdClass + */ + public function export_for_template(\renderer_base $output) { + if ($this->value) { + $this->displayvalue = get_string('yes'); + } else { + $this->displayvalue = get_string('no'); + } + + return parent::export_for_template($output); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + global $DB; + require_capability('moodle/tag:manage', context_system::instance()); + $tagcoll = $DB->get_record('tag_coll', array('id' => $itemid), '*', MUST_EXIST); + core_tag_collection::update($tagcoll, array('searchable' => $newvalue)); + return new self($tagcoll); + } +} diff --git a/tag/lib.php b/tag/lib.php index e67af3ae8f4..e438f8a1a99 100644 --- a/tag/lib.php +++ b/tag/lib.php @@ -60,5 +60,9 @@ function core_tag_inplace_editable($itemtype, $itemid, $newvalue) { return \core_tag\output\tagareacollection::update($itemid, $newvalue); } else if ($itemtype === 'tagareashowstandard') { return \core_tag\output\tagareashowstandard::update($itemid, $newvalue); + } else if ($itemtype === 'tagcollname') { + return \core_tag\output\tagcollname::update($itemid, $newvalue); + } else if ($itemtype === 'tagcollsearchable') { + return \core_tag\output\tagcollsearchable::update($itemid, $newvalue); } } diff --git a/tag/manage.php b/tag/manage.php index d3f06c1b37a..8cbbd744cc1 100644 --- a/tag/manage.php +++ b/tag/manage.php @@ -36,7 +36,6 @@ $isstandard = optional_param('isstandard', null, PARAM_INT); $action = optional_param('action', '', PARAM_ALPHA); $perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); $page = optional_param('page', 0, PARAM_INT); -$notice = optional_param('notice', '', PARAM_ALPHA); $tagcollid = optional_param('tc', 0, PARAM_INT); $tagareaid = optional_param('ta', null, PARAM_INT); @@ -74,48 +73,18 @@ $PAGE->set_blocks_editing_capability('moodle/tag:editblocks'); switch($action) { case 'colladd': - case 'colledit': - if ($action === 'colladd' || ($action === 'colledit' && $tagcoll && empty($tagcoll->component))) { - $form = new core_tag_collection_form($manageurl, $tagcoll); - if ($form->is_cancelled()) { - redirect($manageurl); - } else if ($data = $form->get_data()) { - if ($action === 'colladd') { - core_tag_collection::create($data); - } else { - core_tag_collection::update($tagcoll, $data); - } - redirect($manageurl); - } else { - $title = ($action === 'colladd') ? - get_string('addtagcoll', 'tag') : - get_string('edittagcoll', 'tag', core_tag_collection::display_name($tagcoll)); - $PAGE->navbar->add($title); - echo $OUTPUT->header(); - echo $OUTPUT->heading($title, 2); - $form->display(); - echo $OUTPUT->footer(); - exit; - } - } + require_sesskey(); + $name = required_param('name', PARAM_NOTAGS); + $searchable = required_param('searchable', PARAM_BOOL); + core_tag_collection::create(array('name' => $name, 'searchable' => $searchable)); + redirect($manageurl); // TODO message break; case 'colldelete': - $confirm = optional_param('confirm', false, PARAM_BOOL); - if (!$confirm) { - echo $OUTPUT->header(); - $strconfirm = get_string('suredeletecoll', 'tag', core_tag_collection::display_name($tagcoll)); - $params = array('tc' => $tagcoll->id, 'confirm' => 1, 'sesskey' => sesskey(), 'action' => 'colldelete'); - $formcontinue = new single_button(new moodle_url($manageurl, $params), get_string('yes')); - $formcancel = new single_button($manageurl, get_string('no'), 'get'); - echo $OUTPUT->confirm($strconfirm, $formcontinue, $formcancel); - echo $OUTPUT->footer(); - die; - } if ($tagcoll && !$tagcoll->component) { require_sesskey(); core_tag_collection::delete($tagcoll); - redirect(new moodle_url($manageurl, array('notice' => 'changessaved'))); + \core\notification::success(get_string('changessaved', 'core_tag')); } redirect($manageurl); break; @@ -124,7 +93,7 @@ switch($action) { if ($tagcoll) { require_sesskey(); core_tag_collection::change_sortorder($tagcoll, -1); - redirect(new moodle_url($manageurl, array('notice' => 'changessaved'))); + redirect($manageurl, get_string('changessaved', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); } redirect($manageurl); break; @@ -133,7 +102,7 @@ switch($action) { if ($tagcoll) { require_sesskey(); core_tag_collection::change_sortorder($tagcoll, 1); - redirect(new moodle_url($manageurl, array('notice' => 'changessaved'))); + redirect($manageurl, get_string('changessaved', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); } redirect($manageurl); break; @@ -144,14 +113,18 @@ switch($action) { $tagschecked = array($tagid); } core_tag_tag::delete_tags($tagschecked); - redirect(new moodle_url($PAGE->url, $tagschecked ? array('notice' => 'deleted') : null)); + if ($tagschecked) { + redirect($PAGE->url, get_string('deleted', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); + } else { + redirect($PAGE->url); + } break; case 'setflag': require_sesskey(); if ($tagid) { $tagobject->flag(); - redirect(new moodle_url($PAGE->url, array('notice' => 'flagged'))); + redirect($PAGE->url, get_string('flagged', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); } redirect($PAGE->url); break; @@ -160,7 +133,7 @@ switch($action) { require_sesskey(); if ($tagid) { $tagobject->reset_flag(); - redirect(new moodle_url($PAGE->url, array('notice' => 'resetflag'))); + redirect($PAGE->url, get_string('resetflag', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); } redirect($PAGE->url); break; @@ -169,7 +142,7 @@ switch($action) { require_sesskey(); if ($tagid && $tagobject->update( array('isstandard' => $isstandard ? 1 : 0))) { - redirect(new moodle_url($PAGE->url, array('notice' => 'typechanged'))); + redirect($PAGE->url, get_string('typechanged', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); } redirect($PAGE->url); break; @@ -187,16 +160,13 @@ switch($action) { $tagobject->update(array('isstandard' => 1)); } } - redirect(new moodle_url($PAGE->url, $tagobjects ? array('notice' => 'added') : null)); + redirect($PAGE->url, $tagobjects ? get_string('added', 'core_tag') : null, + null, \core\output\notification::NOTIFY_SUCCESS); break; } echo $OUTPUT->header(); -if ($notice && get_string_manager()->string_exists($notice, 'tag')) { - echo $OUTPUT->notification(get_string($notice, 'tag'), 'notifysuccess'); -} - if (!$tagcoll) { // Tag collection is not specified. Display the overview of tag collections and tag areas. $tagareastable = new core_tag_areas_table($manageurl); @@ -205,7 +175,8 @@ if (!$tagcoll) { echo $OUTPUT->heading(get_string('tagcollections', 'core_tag') . $OUTPUT->help_icon('tagcollection', 'tag'), 3); echo html_writer::table($colltable); $url = new moodle_url($manageurl, array('action' => 'colladd')); - echo html_writer::div(html_writer::link($url, get_string('addtagcoll', 'tag')), 'mdl-right addtagcoll'); + echo html_writer::div(html_writer::link('#', get_string('addtagcoll', 'tag'), array('data-url' => $url)), + 'mdl-right addtagcoll'); echo $OUTPUT->heading(get_string('tagareas', 'core_tag'), 3); echo html_writer::table($tagareastable); diff --git a/tag/tests/behat/collections.feature b/tag/tests/behat/collections.feature index 28e7e78434f..ad3dd6994e4 100644 --- a/tag/tests/behat/collections.feature +++ b/tag/tests/behat/collections.feature @@ -1,4 +1,4 @@ -@core @core_tag +@core @core_tag @javascript Feature: Managers can create and manage tag collections In order to use tags effectively As a manager @@ -23,7 +23,7 @@ Feature: Managers can create and manage tag collections And I follow "Add tag collection" And I set the following fields to these values: | Name | Hobbies | - And I press "Save changes" + And I press "Create" Scenario: Adding tag collections When I follow "Hobbies" @@ -31,10 +31,9 @@ Feature: Managers can create and manage tag collections And I log out Scenario: Editing tag collections - When I follow "Edit tag collection Hobbies" - And I set the following fields to these values: - | Name | Newname | - And I press "Save changes" + When I click on "Edit tag collection name" "link" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" + And I set the field "New name for tag collection Hobbies" to "Newname" + And I press key "13" in the field "New name for tag collection Hobbies" Then I should not see "Hobbies" And I should see "Newname" And I log out @@ -43,7 +42,7 @@ Feature: Managers can create and manage tag collections When I follow "Add tag collection" And I set the following fields to these values: | Name | Blogging | - And I press "Save changes" + And I press "Create" Then "Blogging" "link" should appear after "Hobbies" "link" And I click on "Move up" "link" in the "Blogging" "table_row" And "Blogging" "link" should appear before "Hobbies" "link" @@ -58,7 +57,6 @@ Feature: Managers can create and manage tag collections And I should not see "Hobbies" And I log out - @javascript Scenario: Assigning tag area to tag collection And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" And I should not see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" @@ -69,15 +67,13 @@ Feature: Managers can create and manage tag collections And I should see "Hobbies" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" And I log out - @javascript Scenario: Disabling tag areas When I click on "Disable" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" - And I should see "User interests" in the "table.tag-collections-table" "css_element" + And I should not see "User interests" in the "table.tag-collections-table" "css_element" And I click on "Enable" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" And I log out - @javascript Scenario: Deleting non-empty tag collections When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" And I set the field "Change tag collection of area User interests" to "Hobbies" @@ -85,10 +81,9 @@ Feature: Managers can create and manage tag collections Then I should see "Are you sure you want to delete tag collection \"Hobbies\"?" And I press "Yes" And I should not see "Hobbies" - And "User interests" "text" should exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" + And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element" And I log out - @javascript Scenario: Moving tags when changing tag collections And I follow "Preferences" in the user menu And I follow "Edit profile" @@ -115,23 +110,19 @@ Feature: Managers can create and manage tag collections And I should see "Tag2" And I log out - @javascript Scenario: Creating searchable and non-searchable tag collections And I follow "Add tag collection" And I set the following fields to these values: | Name | Hiddencoll | | Searchable | 0 | - And I press "Save changes" + And I press "Create" And "Yes" "text" should not exist in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hiddencoll')]" "xpath_element" And I navigate to "Tags" node in "Site pages" Then the "Select tag collection" select box should contain "Default collection" And the "Select tag collection" select box should contain "Hobbies" And the "Select tag collection" select box should not contain "Hiddencoll" And I navigate to "Manage tags" node in "Site administration > Appearance" - And I click on "Edit" "link" in the "Hobbies" "table_row" - And I set the following fields to these values: - | Searchable | 0 | - And I press "Save changes" + And I click on "Change searchable" "link" in the "Hobbies" "table_row" And I navigate to "Tags" node in "Site pages" And "Select tag collection" "select" should not exist And I log out From 21d9596cca49def89d33bef54a1eb0426a0e3741 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Sat, 27 Feb 2016 15:55:26 +0800 Subject: [PATCH 3/4] MDL-53254 tags: tags management inplace editable --- lib/amd/build/tag.min.js | 2 +- lib/amd/src/tag.js | 92 +++++---------------------- tag/classes/collections_table.php | 1 - tag/classes/external.php | 5 +- tag/classes/manage_table.php | 10 +-- tag/classes/output/tag.php | 11 ---- tag/classes/output/tagflag.php | 89 ++++++++++++++++++++++++++ tag/classes/output/tagisstandard.php | 84 ++++++++++++++++++++++++ tag/lib.php | 6 +- tag/manage.php | 31 +-------- tag/templates/tagflag.mustache | 48 -------------- tag/templates/tagisstandard.mustache | 47 -------------- tag/tests/behat/flag_tags.feature | 22 +------ tag/tests/behat/standard_tags.feature | 22 +------ 14 files changed, 205 insertions(+), 265 deletions(-) create mode 100644 tag/classes/output/tagflag.php create mode 100644 tag/classes/output/tagisstandard.php delete mode 100644 tag/templates/tagflag.mustache delete mode 100644 tag/templates/tagisstandard.mustache diff --git a/lib/amd/build/tag.min.js b/lib/amd/build/tag.min.js index d5fa9fb66a4..e3d5053f6a3 100644 --- a/lib/amd/build/tag.min.js +++ b/lib/amd/build/tag.min.js @@ -1 +1 @@ -define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){var f=function(b){var c=b.closest("tr").get(0);if(c){var d=a(c).find("td.col-timemodified").get(0);e.get_string("now").done(function(b){a(d).html(b)})}};a(".tag-management-table").delegate(".tagisstandard","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="1"===h?0:1,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,isstandard:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagisstandard",b.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagisstandard").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),g=e.attr("data-id"),h=e.attr("data-value"),i="0"===h?1:0,j=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:g,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:g}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var g=e.closest("tr").get(0);g&&(d.tags[0].flag?a(g).addClass("flagged-tag"):a(g).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){f(e);var b=e.parent();e.replaceWith(a),b.find(".tagflag").get(0).focus()})}})}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c,d,e,f=b.ajaxreturn;b.oldvalue;"core_tag"===f.component&&"tagareaenable"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),e=f.value,"1"===e?(a(this).closest("tr").removeClass("dimmed_text"),d=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value"),a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden")):a(this).closest("tr").addClass("dimmed_text")),"core_tag"===f.component&&"tagareacollection"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),d=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value"),"1"===e&&a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden"))}),a("body").on("click",".addtagcoll > a",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"addtagcoll",component:"tag"},{key:"name"},{key:"searchable",component:"tag"},{key:"create"},{key:"cancel"}]).done(function(b){var d=a('

    :
    :

    ');d.find('label[for="addtagcoll_name"]').html(b[1]),d.find('label[for="addtagcoll_searchable"]').html(b[2]),d.find("#addtagcoll_submit").attr("value",b[3]),d.find("#addtagcoll_cancel").attr("value",b[4]);var e=new M.core.dialogue({draggable:!0,modal:!0,closeButton:!0,headerContent:b[0],bodyContent:d.html()});e.show(),a("#addtagcoll_form #addtagcoll_name").focus(),a("#addtagcoll_form #addtagcoll_cancel").on("click",function(){e.destroy()}),a("#addtagcoll_form").on("submit",function(){var b=a("#addtagcoll_form #addtagcoll_name").val(),d=a("#addtagcoll_form #addtagcoll_searchable").prop("checked")?1:0;return String(b).length>0&&(window.location.href=c+"&name="+encodeURIComponent(b)+"&searchable="+d),!1})})}),a("body").on("click",".tag-collections-table .action_delete",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"delete"},{key:"suredeletecoll",component:"tag",param:a(this).attr("data-collname")},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})})}}}); \ No newline at end of file +define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){if(e.get_string("now").done(function(c){a(b.target).closest("tr").find("td.col-timemodified").html(c)}),"tagflag"===b.ajaxreturn.itemtype){var c=a(b.target).closest("tr");"0"===b.ajaxreturn.value?c.removeClass("flagged-tag"):c.addClass("flagged-tag")}}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c,d,e,f=b.ajaxreturn;"core_tag"===f.component&&"tagareaenable"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),e=f.value,"1"===e?(a(this).closest("tr").removeClass("dimmed_text"),d=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value"),a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden")):a(this).closest("tr").addClass("dimmed_text")),"core_tag"===f.component&&"tagareacollection"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),d=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value"),"1"===e&&a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden"))}),a("body").on("click",".addtagcoll > a",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"addtagcoll",component:"tag"},{key:"name"},{key:"searchable",component:"tag"},{key:"create"},{key:"cancel"}]).done(function(b){var d=a('

    :
    :

    ');d.find('label[for="addtagcoll_name"]').html(b[1]),d.find('label[for="addtagcoll_searchable"]').html(b[2]),d.find("#addtagcoll_submit").attr("value",b[3]),d.find("#addtagcoll_cancel").attr("value",b[4]);var e=new M.core.dialogue({draggable:!0,modal:!0,closeButton:!0,headerContent:b[0],bodyContent:d.html()});e.show(),a("#addtagcoll_form #addtagcoll_name").focus(),a("#addtagcoll_form #addtagcoll_cancel").on("click",function(){e.destroy()}),a("#addtagcoll_form").on("submit",function(){var b=a("#addtagcoll_form #addtagcoll_name").val(),d=a("#addtagcoll_form #addtagcoll_searchable").prop("checked")?1:0;return String(b).length>0&&(window.location.href=c+"&name="+encodeURIComponent(b)+"&searchable="+d),!1})})}),a("body").on("click",".tag-collections-table .action_delete",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"delete"},{key:"suredeletecoll",component:"tag",param:a(this).attr("data-collname")},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})})}}}); \ No newline at end of file diff --git a/lib/amd/src/tag.js b/lib/amd/src/tag.js index 08ff1a405f7..3e2e574cfdd 100644 --- a/lib/amd/src/tag.js +++ b/lib/amd/src/tag.js @@ -61,80 +61,19 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' */ initManagePage: function() { - var update_modified = function(el) { - var row = el.closest('tr').get(0); - if (row) { - var td = $(row).find('td.col-timemodified').get(0); - str.get_string('now').done(function(s) { - $(td).html(s); - }); + // Set cell 'time modified' to 'now' when any of the element is updated in this row. + $('body').on('updated', '[data-inplaceeditable]', function(e) { + str.get_string('now').done(function(s) { + $(e.target).closest('tr').find('td.col-timemodified').html(s); + }); + if (e.ajaxreturn.itemtype === 'tagflag') { + var row = $(e.target).closest('tr'); + if (e.ajaxreturn.value === '0') { + row.removeClass('flagged-tag'); + } else { + row.addClass('flagged-tag'); + } } - }; - - // Click handler for changing tag type. - $('.tag-management-table').delegate('.tagisstandard', 'click', function(e) { - e.preventDefault(); - var target = $( this ), - tagid = target.attr('data-id'), - currentvalue = target.attr('data-value'), - isstandard = (currentvalue === "1") ? 0 : 1; - - var promises = ajax.call([{ - methodname: 'core_tag_update_tags', - args: { tags : [ { id : tagid , isstandard : isstandard } ] } - }, { - methodname: 'core_tag_get_tags', - args: { tags : [ { id : tagid } ] } - }], true); - - $.when.apply($, promises) - .done( function(updateresult, data) { - if (updateresult.warnings[0] === undefined && data.tags[0] !== undefined) { - templates.render('core_tag/tagisstandard', data.tags[0]).done(function(html) { - update_modified(target); - var parent = target.parent(); - target.replaceWith(html); - parent.find('.tagisstandard').get(0).focus(); - }); - } - }); - }); - - // Click handler for flagging/resetting tag flag. - $('.tag-management-table').delegate('.tagflag', 'click', function(e) { - e.preventDefault(); - var target = $( this ), - tagid = target.attr('data-id'), - currentvalue = target.attr('data-value'), - flag = (currentvalue === "0") ? 1 : 0; - - var promises = ajax.call([{ - methodname: 'core_tag_update_tags', - args: { tags : [ { id : tagid , flag : flag } ] } - }, { - methodname: 'core_tag_get_tags', - args: { tags : [ { id : tagid } ] } - }], true); - - $.when.apply($, promises) - .done( function(updateresult, data) { - if (updateresult.warnings[0] === undefined && data.tags[0] !== undefined) { - var row = target.closest('tr').get(0); - if (row) { - if (data.tags[0].flag) { - $(row).addClass('flagged-tag'); - } else { - $(row).removeClass('flagged-tag'); - } - } - templates.render('core_tag/tagflag', data.tags[0]).done(function(html) { - update_modified(target); - var parent = target.parent(); - target.replaceWith(html); - parent.find('.tagflag').get(0).focus(); - }); - } - }); }); // Confirmation for single tag delete link. @@ -184,7 +123,6 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' initManageCollectionsPage: function() { $('body').on('updated', '[data-inplaceeditable]', function(e) { var ajaxreturn = e.ajaxreturn, - oldvalue = e.oldvalue, areaid, collid, isenabled; if (ajaxreturn.component === 'core_tag' && ajaxreturn.itemtype === 'tagareaenable') { areaid = $(this).attr('data-itemid'); @@ -193,7 +131,8 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' if (isenabled === '1') { $(this).closest('tr').removeClass('dimmed_text'); collid = $(this).closest('tr').find('[data-itemtype="tagareacollection"]').attr("data-value"); - $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]").removeClass('hidden'); + $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]") + .removeClass('hidden'); } else { $(this).closest('tr').addClass('dimmed_text'); } @@ -204,7 +143,8 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' collid = $(this).attr('data-value'); isenabled = $(this).closest('tr').find('[data-itemtype="tagareaenable"]').attr("data-value"); if (isenabled === "1") { - $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]").removeClass('hidden'); + $(".tag-collections-table ul[data-collectionid="+collid+"] li[data-areaid="+areaid+"]") + .removeClass('hidden'); } } }); diff --git a/tag/classes/collections_table.php b/tag/classes/collections_table.php index 78cdaca9d56..90028edb594 100644 --- a/tag/classes/collections_table.php +++ b/tag/classes/collections_table.php @@ -35,7 +35,6 @@ class core_tag_collections_table extends html_table { /** * Constructor - * @global \core_renderer $OUTPUT * @param string|moodle_url $pageurl */ public function __construct($pageurl) { diff --git a/tag/classes/external.php b/tag/classes/external.php index 7999c383503..c8fa037f0a0 100644 --- a/tag/classes/external.php +++ b/tag/classes/external.php @@ -224,8 +224,6 @@ class core_tag_external extends external_api { unset($rv->official); } unset($rv->flag); - unset($rv->changetypeurl); - unset($rv->changeflagurl); } $return[] = $rv; } @@ -253,8 +251,6 @@ class core_tag_external extends external_api { 'whether this flag is standard (deprecated, use isstandard)', VALUE_OPTIONAL), 'isstandard' => new external_value(PARAM_INT, 'whether this flag is standard', VALUE_OPTIONAL), 'viewurl' => new external_value(PARAM_URL, 'URL to view'), - 'changetypeurl' => new external_value(PARAM_URL, 'URL to change type (standard or not)', VALUE_OPTIONAL), - 'changeflagurl' => new external_value(PARAM_URL, 'URL to set or reset flag', VALUE_OPTIONAL), ), 'information about one tag') ), 'warnings' => new external_warnings() @@ -306,6 +302,7 @@ class core_tag_external extends external_api { $context = $params['ctx'] ? context::instance_by_id($params['ctx']) : context_system::instance(); require_login(null, false, null, false, true); self::validate_context($context); + $PAGE->set_context(null); $tag = core_tag_tag::get_by_name($params['tc'], $params['tag'], '*', MUST_EXIST); $tagareas = core_tag_collection::get_areas($params['tc']); diff --git a/tag/classes/manage_table.php b/tag/classes/manage_table.php index 809d74d2a43..b01e2c6dcba 100644 --- a/tag/classes/manage_table.php +++ b/tag/classes/manage_table.php @@ -180,7 +180,7 @@ class core_tag_manage_table extends table_sql { public function col_name($tag) { global $OUTPUT; $tagoutput = new core_tag\output\tagname($tag); - return $OUTPUT->render_from_template('core/inplace_editable', $tagoutput->export_for_template($OUTPUT)); + return $tagoutput->render($OUTPUT); } /** @@ -191,8 +191,8 @@ class core_tag_manage_table extends table_sql { */ public function col_flag($tag) { global $OUTPUT; - $tagoutput = new core_tag\output\tag($tag); - return $OUTPUT->render_from_template('core_tag/tagflag', $tagoutput->export_for_template($OUTPUT)); + $tagoutput = new core_tag\output\tagflag($tag); + return $tagoutput->render($OUTPUT); } /** @@ -226,8 +226,8 @@ class core_tag_manage_table extends table_sql { */ public function col_isstandard($tag) { global $OUTPUT; - $tagoutput = new core_tag\output\tag($tag); - return $OUTPUT->render_from_template('core_tag/tagisstandard', $tagoutput->export_for_template($OUTPUT)); + $tagoutput = new core_tag\output\tagisstandard($tag); + return $tagoutput->render($OUTPUT); } /** diff --git a/tag/classes/output/tag.php b/tag/classes/output/tag.php index 4016a615dc4..f965399a04e 100644 --- a/tag/classes/output/tag.php +++ b/tag/classes/output/tag.php @@ -94,17 +94,6 @@ class tag implements renderable, templatable { $url = core_tag_tag::make_url($r->tagcollid, $r->rawname); $r->viewurl = $url->out(false); - $manageurl = new moodle_url('/tag/manage.php', array('sesskey' => sesskey(), - 'tagid' => $this->record->id)); - $url = new moodle_url($manageurl); - $url->param('action', 'changetype'); - $url->param('isstandard', $r->isstandard ? 0 : 1); - $r->changetypeurl = $url->out(false); - - $url = new moodle_url($manageurl); - $url->param('action', $this->record->flag ? 'resetflag' : 'setflag'); - $r->changeflagurl = $url->out(false); - return $r; } } diff --git a/tag/classes/output/tagflag.php b/tag/classes/output/tagflag.php new file mode 100644 index 00000000000..068307bab07 --- /dev/null +++ b/tag/classes/output/tagflag.php @@ -0,0 +1,89 @@ +. + +/** + * Contains class core_tag\output\tagflag + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; +use core_tag_tag; + +/** + * Class to display tag flag toggle + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagflag extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass|core_tag_tag $tag + */ + public function __construct($tag) { + $editable = has_capability('moodle/tag:manage', context_system::instance()); + $value = (int)$tag->flag; + + parent::__construct('core_tag', 'tagflag', $tag->id, $editable, $value, $value); + $this->set_type_toggle(array(0, $value ? $value : 1)); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output + * @return \stdClass + */ + public function export_for_template(\renderer_base $output) { + if ($this->value) { + $this->edithint = get_string('resetflag', 'core_tag'); + $this->displayvalue = $output->pix_icon('i/flagged', $this->edithint) . + " ({$this->value})"; + } else { + $this->edithint = get_string('flagasinappropriate', 'core_tag'); + $this->displayvalue = $output->pix_icon('i/unflagged', $this->edithint); + } + + return parent::export_for_template($output); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + require_capability('moodle/tag:manage', context_system::instance()); + $tag = core_tag_tag::get($itemid, '*', MUST_EXIST); + $newvalue = (int)clean_param($newvalue, PARAM_BOOL); + if ($newvalue) { + $tag->flag(); + } else { + $tag->reset_flag(); + } + return new self($tag); + } +} diff --git a/tag/classes/output/tagisstandard.php b/tag/classes/output/tagisstandard.php new file mode 100644 index 00000000000..ab56d4e7deb --- /dev/null +++ b/tag/classes/output/tagisstandard.php @@ -0,0 +1,84 @@ +. + +/** + * Contains class core_tag\output\tagisstandard + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_tag\output; + +use context_system; +use core_tag_tag; + +/** + * Class to display/toggle tag isstandard attribute + * + * @package core_tag + * @copyright 2016 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tagisstandard extends \core\output\inplace_editable { + + /** + * Constructor. + * + * @param \stdClass|core_tag_tag $tag + */ + public function __construct($tag) { + $editable = has_capability('moodle/tag:manage', context_system::instance()); + $value = (int)(bool)$tag->isstandard; + + parent::__construct('core_tag', 'tagisstandard', $tag->id, $editable, $value, $value); + $this->set_type_toggle(); + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param \renderer_base $output + * @return \stdClass + */ + public function export_for_template(\renderer_base $output) { + if ($this->value) { + $this->edithint = get_string('settypedefault', 'core_tag'); + $this->displayvalue = $output->pix_icon('i/checked', $this->edithint); + } else { + $this->edithint = get_string('settypestandard', 'core_tag'); + $this->displayvalue = $output->pix_icon('i/unchecked', $this->edithint); + } + + return parent::export_for_template($output); + } + + /** + * Updates the value in database and returns itself, called from inplace_editable callback + * + * @param int $itemid + * @param mixed $newvalue + * @return \self + */ + public static function update($itemid, $newvalue) { + require_capability('moodle/tag:manage', context_system::instance()); + $tag = core_tag_tag::get($itemid, '*', MUST_EXIST); + $newvalue = (int)clean_param($newvalue, PARAM_BOOL); + $tag->update(array('isstandard' => $newvalue)); + return new self($tag); + } +} diff --git a/tag/lib.php b/tag/lib.php index e438f8a1a99..77f1a79f0a3 100644 --- a/tag/lib.php +++ b/tag/lib.php @@ -44,8 +44,6 @@ function tag_page_type_list($pagetype, $parentcontext, $currentcontext) { /** * Implements callback inplace_editable() allowing to edit values in-place * - * @global moodle_database $DB - * * @param string $itemtype * @param int $itemid * @param mixed $newvalue @@ -64,5 +62,9 @@ function core_tag_inplace_editable($itemtype, $itemid, $newvalue) { return \core_tag\output\tagcollname::update($itemid, $newvalue); } else if ($itemtype === 'tagcollsearchable') { return \core_tag\output\tagcollsearchable::update($itemid, $newvalue); + } else if ($itemtype === 'tagflag') { + return \core_tag\output\tagflag::update($itemid, $newvalue); + } else if ($itemtype === 'tagisstandard') { + return \core_tag\output\tagisstandard::update($itemid, $newvalue); } } diff --git a/tag/manage.php b/tag/manage.php index 8cbbd744cc1..bb016d2e294 100644 --- a/tag/manage.php +++ b/tag/manage.php @@ -77,7 +77,7 @@ switch($action) { $name = required_param('name', PARAM_NOTAGS); $searchable = required_param('searchable', PARAM_BOOL); core_tag_collection::create(array('name' => $name, 'searchable' => $searchable)); - redirect($manageurl); // TODO message + redirect($manageurl); break; case 'colldelete': @@ -120,36 +120,9 @@ switch($action) { } break; - case 'setflag': - require_sesskey(); - if ($tagid) { - $tagobject->flag(); - redirect($PAGE->url, get_string('flagged', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); - } - redirect($PAGE->url); - break; - - case 'resetflag': - require_sesskey(); - if ($tagid) { - $tagobject->reset_flag(); - redirect($PAGE->url, get_string('resetflag', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); - } - redirect($PAGE->url); - break; - - case 'changetype': - require_sesskey(); - if ($tagid && $tagobject->update( - array('isstandard' => $isstandard ? 1 : 0))) { - redirect($PAGE->url, get_string('typechanged', 'core_tag'), null, \core\output\notification::NOTIFY_SUCCESS); - } - redirect($PAGE->url); - break; - case 'addstandardtag': require_sesskey(); - $tagobjects = null; + $tagobjects = array(); if ($tagcoll) { $otagsadd = optional_param('otagsadd', '', PARAM_RAW); $newtags = preg_split('/\s*,\s*/', trim($otagsadd), -1, PREG_SPLIT_NO_EMPTY); diff --git a/tag/templates/tagflag.mustache b/tag/templates/tagflag.mustache deleted file mode 100644 index d30988b4c40..00000000000 --- a/tag/templates/tagflag.mustache +++ /dev/null @@ -1,48 +0,0 @@ -{{! - 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 . -}} -{{! - @template core_tag/tagflag - - Displays the tag flag in the tag management table - - Classes required for JS: - * tagflag - - Data attributes required for JS: - * data-id, data-value - - Context variables required for this template: - * none - - Example context (json): - { - "id" : "1", - "flag" : "1", - "changeflagurl" : "http://moodle.com/" - } - -}} -{{#flag}} - - {{#pix}}i/flagged,core,{{#str}}resetflag,tag{{/str}}{{/pix}} ({{flag}}) - -{{/flag}} -{{^flag}} - - {{#pix}}i/unflagged,core,{{#str}}flagasinappropriate,tag{{/str}}{{/pix}} - -{{/flag}} diff --git a/tag/templates/tagisstandard.mustache b/tag/templates/tagisstandard.mustache deleted file mode 100644 index 4deb8f0a4cf..00000000000 --- a/tag/templates/tagisstandard.mustache +++ /dev/null @@ -1,47 +0,0 @@ -{{! - 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 . -}} -{{! - @template core_tag/tagisstandard - - Displays the tag type (standard or not) in the tag management table - - Classes required for JS: - * tagisstandard - - Data attributes required for JS: - * data-id, data-value - - Context variables required for this template: - * none - - Example context (json): - { - "id" : "1", - "isstandard" : "1", - "changetypeurl" : "http://moodle.com/" - } -}} -{{#isstandard}} - - {{#pix}}i/checked,core,{{#str}}settypedefault,core_tag{{/str}}{{/pix}} - -{{/isstandard}} -{{^isstandard}} - - {{#pix}}i/unchecked,core,{{#str}}settypestandard,core_tag{{/str}}{{/pix}} - -{{/isstandard}} diff --git a/tag/tests/behat/flag_tags.feature b/tag/tests/behat/flag_tags.feature index 74231bedd92..93fdc61e3f1 100644 --- a/tag/tests/behat/flag_tags.feature +++ b/tag/tests/behat/flag_tags.feature @@ -43,28 +43,8 @@ Feature: Users can flag tags and manager can reset flags And I should see "The person responsible will be notified" And I log out - Scenario: Managing tag flags with javascript disabled - When I log in as "manager1" - And I navigate to "Manage tags" node in "Site administration > Appearance" - And I follow "Default collection" - Then "Sweartag" "link" should appear before "Badtag" "link" - And "Badtag" "link" should appear before "Nicetag" "link" - And "(2)" "text" should exist in the "//tr[contains(.,'Sweartag')]//td[contains(@class,'col-flag')]" "xpath_element" - And "(1)" "text" should exist in the "//tr[contains(.,'Badtag')]//td[contains(@class,'col-flag')]" "xpath_element" - And "(" "text" should not exist in the "//tr[contains(.,'Nicetag')]//td[contains(@class,'col-flag')]" "xpath_element" - And "(" "text" should not exist in the "//tr[contains(.,'Neverusedtag')]//td[contains(@class,'col-flag')]" "xpath_element" - And I click on "Reset flag" "link" in the "Sweartag" "table_row" - And I click on "Reset flag" "link" in the "Badtag" "table_row" - And I click on "Flag as inappropriate" "link" in the "Sweartag" "table_row" - And I click on "Flag as inappropriate" "link" in the "Nicetag" "table_row" - And "(1)" "text" should exist in the "//tr[contains(.,'Sweartag')]//td[contains(@class,'col-flag')]" "xpath_element" - And "(1)" "text" should exist in the "//tr[contains(.,'Nicetag')]//td[contains(@class,'col-flag')]" "xpath_element" - And "(" "text" should not exist in the "//tr[contains(.,'Badtag')]//td[contains(@class,'col-flag')]" "xpath_element" - And "(" "text" should not exist in the "//tr[contains(.,'Neverusedtag')]//td[contains(@class,'col-flag')]" "xpath_element" - And I log out - @javascript - Scenario: Managing tag flags with javascript enabled + Scenario: Managing tag flags When I log in as "manager1" And I navigate to "Manage tags" node in "Site administration > Appearance" And I follow "Default collection" diff --git a/tag/tests/behat/standard_tags.feature b/tag/tests/behat/standard_tags.feature index 310faf2096e..e3da2988652 100644 --- a/tag/tests/behat/standard_tags.feature +++ b/tag/tests/behat/standard_tags.feature @@ -45,26 +45,8 @@ Feature: Manager can add standard tags and change the tag type of existing tags And "Remove from standard tags" "link" should exist in the "Tag5" "table_row" And I log out - Scenario: Changing tag type with javascript disabled - When I log in as "manager1" - And I navigate to "Manage tags" node in "Site administration > Appearance" - And I follow "Default collection" - And I click on "Make standard" "link" in the "Tag0" "table_row" - And I should see "Tag type changed" - And I click on "Make standard" "link" in the "Tag1" "table_row" - And I should see "Tag type changed" - And I click on "Remove from standard tags" "link" in the "Tag0" "table_row" - And I should see "Tag type changed" - And I click on "Remove from standard tags" "link" in the "Tag3" "table_row" - And I should see "Tag type changed" - Then "Make standard" "link" should exist in the "Tag0" "table_row" - And "Remove from standard tags" "link" should exist in the "Tag1" "table_row" - And "Make standard" "link" should exist in the "Tag2" "table_row" - And "Make standard" "link" should exist in the "Tag3" "table_row" - And I log out - @javascript - Scenario: Changing tag type with javascript enabled + Scenario: Changing tag isstandard When I log in as "manager1" And I navigate to "Manage tags" node in "Site administration > Appearance" And I follow "Default collection" @@ -87,7 +69,7 @@ Feature: Manager can add standard tags and change the tag type of existing tags And "Make standard" "link" should exist in the "Tag3" "table_row" And I log out - Scenario: Changing tag type in edit form + Scenario: Changing tag isstandard in edit form When I log in as "manager1" And I navigate to "Manage tags" node in "Site administration > Appearance" And I follow "Default collection" From cbecc3c35a8ea8615b74d4eb04cddcde0bf71a11 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Tue, 22 Mar 2016 17:10:34 +0800 Subject: [PATCH 4/4] MDL-53254 tags: little fixes after review --- lib/amd/build/tag.min.js | 2 +- lib/amd/src/tag.js | 4 ++-- tag/classes/output/tagcollsearchable.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/amd/build/tag.min.js b/lib/amd/build/tag.min.js index e3d5053f6a3..e5cfa40f8c6 100644 --- a/lib/amd/build/tag.min.js +++ b/lib/amd/build/tag.min.js @@ -1 +1 @@ -define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){if(e.get_string("now").done(function(c){a(b.target).closest("tr").find("td.col-timemodified").html(c)}),"tagflag"===b.ajaxreturn.itemtype){var c=a(b.target).closest("tr");"0"===b.ajaxreturn.value?c.removeClass("flagged-tag"):c.addClass("flagged-tag")}}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c,d,e,f=b.ajaxreturn;"core_tag"===f.component&&"tagareaenable"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),e=f.value,"1"===e?(a(this).closest("tr").removeClass("dimmed_text"),d=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value"),a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden")):a(this).closest("tr").addClass("dimmed_text")),"core_tag"===f.component&&"tagareacollection"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),d=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value"),"1"===e&&a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden"))}),a("body").on("click",".addtagcoll > a",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"addtagcoll",component:"tag"},{key:"name"},{key:"searchable",component:"tag"},{key:"create"},{key:"cancel"}]).done(function(b){var d=a('

    :
    :

    ');d.find('label[for="addtagcoll_name"]').html(b[1]),d.find('label[for="addtagcoll_searchable"]').html(b[2]),d.find("#addtagcoll_submit").attr("value",b[3]),d.find("#addtagcoll_cancel").attr("value",b[4]);var e=new M.core.dialogue({draggable:!0,modal:!0,closeButton:!0,headerContent:b[0],bodyContent:d.html()});e.show(),a("#addtagcoll_form #addtagcoll_name").focus(),a("#addtagcoll_form #addtagcoll_cancel").on("click",function(){e.destroy()}),a("#addtagcoll_form").on("submit",function(){var b=a("#addtagcoll_form #addtagcoll_name").val(),d=a("#addtagcoll_form #addtagcoll_searchable").prop("checked")?1:0;return String(b).length>0&&(window.location.href=c+"&name="+encodeURIComponent(b)+"&searchable="+d),!1})})}),a("body").on("click",".tag-collections-table .action_delete",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"delete"},{key:"suredeletecoll",component:"tag",param:a(this).attr("data-collname")},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})})}}}); \ No newline at end of file +define(["jquery","core/ajax","core/templates","core/notification","core/str"],function(a,b,c,d,e){return{initTagindexPage:function(){a("body").delegate(".tagarea[data-ta] a[data-quickload=1]","click",function(d){d.preventDefault();var e=a(this),f=e.context.search.replace(/^\?/,""),g=e.closest(".tagarea[data-ta]"),h=f.split("&").reduce(function(a,b){var c=b.split("=");return a[c[0]]=decodeURIComponent(c[1]),a},{}),i=b.call([{methodname:"core_tag_get_tagindex",args:{tagindex:h}}],!0);a.when.apply(a,i).done(function(a){c.render("core_tag/index",a).done(function(a){g.replaceWith(a)})})})},initManagePage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){if(e.get_string("now").done(function(c){a(b.target).closest("tr").find("td.col-timemodified").html(c)}),"tagflag"===b.ajaxreturn.itemtype){var c=a(b.target).closest("tr");"0"===b.ajaxreturn.value?c.removeClass("flagged-tag"):c.addClass("flagged-tag")}}),a(".tag-management-table").delegate("a.tagdelete","click",function(b){b.preventDefault();var c=a(this).attr("href");e.get_strings([{key:"delete"},{key:"confirmdeletetag",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})}),a("#tag-management-delete").click(function(b){var c=a(this).closest("form").get(0),f=a(c).find("input[type=checkbox]:checked").length;return f?(b.preventDefault(),void e.get_strings([{key:"delete"},{key:"confirmdeletetags",component:"tag"},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){c.submit()})})):!1})},initManageCollectionsPage:function(){a("body").on("updated","[data-inplaceeditable]",function(b){var c,d,e,f=b.ajaxreturn;"core_tag"===f.component&&"tagareaenable"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),e=f.value,"1"===e?(a(this).closest("tr").removeClass("dimmed_text"),d=a(this).closest("tr").find('[data-itemtype="tagareacollection"]').attr("data-value"),a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden")):a(this).closest("tr").addClass("dimmed_text")),"core_tag"===f.component&&"tagareacollection"===f.itemtype&&(c=a(this).attr("data-itemid"),a(".tag-collections-table ul[data-collectionid] li[data-areaid="+c+"]").addClass("hidden"),d=a(this).attr("data-value"),e=a(this).closest("tr").find('[data-itemtype="tagareaenable"]').attr("data-value"),"1"===e&&a(".tag-collections-table ul[data-collectionid="+d+"] li[data-areaid="+c+"]").removeClass("hidden"))}),a("body").on("click",".addtagcoll > a",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"addtagcoll",component:"tag"},{key:"name"},{key:"searchable",component:"tag"},{key:"create"},{key:"cancel"}]).done(function(b){var d=a('

    :

    :

    ');d.find('label[for="addtagcoll_name"]').html(b[1]),d.find('label[for="addtagcoll_searchable"]').html(b[2]),d.find("#addtagcoll_submit").attr("value",b[3]),d.find("#addtagcoll_cancel").attr("value",b[4]);var e=new M.core.dialogue({draggable:!0,modal:!0,closeButton:!0,headerContent:b[0],bodyContent:d.html()});e.show(),a("#addtagcoll_form #addtagcoll_name").focus(),a("#addtagcoll_form #addtagcoll_cancel").on("click",function(){e.destroy()}),a("#addtagcoll_form").on("submit",function(){var b=a("#addtagcoll_form #addtagcoll_name").val(),d=a("#addtagcoll_form #addtagcoll_searchable").prop("checked")?1:0;return String(b).length>0&&(window.location.href=c+"&name="+encodeURIComponent(b)+"&searchable="+d),!1})})}),a("body").on("click",".tag-collections-table .action_delete",function(b){b.preventDefault();var c=a(this).attr("data-url")+"&sesskey="+M.cfg.sesskey;e.get_strings([{key:"delete"},{key:"suredeletecoll",component:"tag",param:a(this).attr("data-collname")},{key:"yes"},{key:"no"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],function(){window.location.href=c})})})}}}); \ No newline at end of file diff --git a/lib/amd/src/tag.js b/lib/amd/src/tag.js index 3e2e574cfdd..65af5f5a8a9 100644 --- a/lib/amd/src/tag.js +++ b/lib/amd/src/tag.js @@ -161,8 +161,8 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str' ]).done(function(s) { var el = $('
    '+ '

    : ' + - '
    ' + - ': ' + + '

    ' + + '

    : ' + '

    ' + '

    '+ '

    ' + diff --git a/tag/classes/output/tagcollsearchable.php b/tag/classes/output/tagcollsearchable.php index 87c4ce6f22c..f3c6e060e38 100644 --- a/tag/classes/output/tagcollsearchable.php +++ b/tag/classes/output/tagcollsearchable.php @@ -61,9 +61,9 @@ class tagcollsearchable extends \core\output\inplace_editable { */ public function export_for_template(\renderer_base $output) { if ($this->value) { - $this->displayvalue = get_string('yes'); + $this->displayvalue = $output->pix_icon('i/checked', get_string('yes')); } else { - $this->displayvalue = get_string('no'); + $this->displayvalue = $output->pix_icon('i/unchecked', get_string('no')); } return parent::export_for_template($output);