Merge branch 'wip-MDL-50851-master' of git://github.com/marinaglancy/moodle
This commit is contained in:
@@ -659,6 +659,10 @@ class tool_uploadcourse_course {
|
||||
$this->data = $coursedata;
|
||||
$this->enrolmentdata = tool_uploadcourse_helper::get_enrolment_data($this->rawdata);
|
||||
|
||||
if (isset($this->rawdata['tags']) && strval($this->rawdata['tags']) !== '') {
|
||||
$this->data['tags'] = preg_split('/\s*,\s*/', trim($this->rawdata['tags']), -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
// Restore data.
|
||||
// TODO Speed up things by not really extracting the backup just yet, but checking that
|
||||
// the backup file or shortname passed are valid. Extraction should happen in proceed().
|
||||
|
||||
@@ -261,6 +261,7 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
|
||||
'groupmode' => '2',
|
||||
'groupmodeforce' => '1',
|
||||
'enablecompletion' => '1',
|
||||
'tags' => 'Cat, Dog',
|
||||
|
||||
'role_teacher' => 'Knight',
|
||||
'role_manager' => 'Jedi',
|
||||
@@ -297,6 +298,7 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
|
||||
$this->assertEquals($data['groupmode'], $course->groupmode);
|
||||
$this->assertEquals($data['groupmodeforce'], $course->groupmodeforce);
|
||||
$this->assertEquals($data['enablecompletion'], $course->enablecompletion);
|
||||
$this->assertEquals($data['tags'], join(', ', core_tag_tag::get_item_tags_array('core', 'course', $course->id)));
|
||||
|
||||
// Roles.
|
||||
$roleids = array();
|
||||
|
||||
@@ -96,6 +96,7 @@ $STD_FIELDS = array('id', 'username', 'email',
|
||||
'suspended', // 1 means suspend user account, 0 means activate user account, nothing means keep as is for existing users
|
||||
'deleted', // 1 means delete user
|
||||
'mnethostid', // Can not be used for adding, updating or deleting of users - only for enrolments, groups, cohorts and suspending.
|
||||
'interests',
|
||||
);
|
||||
// Include all name fields.
|
||||
$STD_FIELDS = array_merge($STD_FIELDS, get_all_user_name_fields());
|
||||
@@ -836,6 +837,10 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
}
|
||||
}
|
||||
|
||||
// Update user interests.
|
||||
if (isset($user->interests) && strval($user->interests) !== '') {
|
||||
useredit_update_interests($user, preg_split('/\s*,\s*/', $user->interests, -1, PREG_SPLIT_NO_EMPTY));
|
||||
}
|
||||
|
||||
// add to cohort first, it might trigger enrolments indirectly - do NOT create cohorts here!
|
||||
foreach ($filecolumns as $column) {
|
||||
|
||||
@@ -1778,22 +1778,8 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
|
||||
$data = (object)$data;
|
||||
|
||||
if (!empty($CFG->usetags)) { // if enabled in server
|
||||
// TODO: This is highly inneficient. Each time we add one tag
|
||||
// we fetch all the existing because tag_set() deletes them
|
||||
// so everything must be reinserted on each call
|
||||
$tags = array();
|
||||
$existingtags = tag_get_tags('course', $this->get_courseid());
|
||||
// Re-add all the existitng tags
|
||||
foreach ($existingtags as $existingtag) {
|
||||
$tags[] = $existingtag->rawname;
|
||||
}
|
||||
// Add the one being restored
|
||||
$tags[] = $data->rawname;
|
||||
// Send all the tags back to the course
|
||||
tag_set('course', $this->get_courseid(), $tags, 'core',
|
||||
context_course::instance($this->get_courseid())->id);
|
||||
}
|
||||
core_tag_tag::add_item_tag('core', 'course', $this->get_courseid(),
|
||||
context_course::instance($this->get_courseid()), $data->rawname);
|
||||
}
|
||||
|
||||
public function process_allowed_module($data) {
|
||||
@@ -4078,25 +4064,17 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($CFG->usetags)) { // if enabled in server
|
||||
// TODO: This is highly inefficient. Each time we add one tag
|
||||
// we fetch all the existing because tag_set() deletes them
|
||||
// so everything must be reinserted on each call
|
||||
$tags = array();
|
||||
$existingtags = tag_get_tags('question', $newquestion);
|
||||
// Re-add all the existitng tags
|
||||
foreach ($existingtags as $existingtag) {
|
||||
$tags[] = $existingtag->rawname;
|
||||
}
|
||||
// Add the one being restored
|
||||
$tags[] = $data->rawname;
|
||||
if (core_tag_tag::is_enabled('core_question', 'question')) {
|
||||
$tagname = $data->rawname;
|
||||
// Get the category, so we can then later get the context.
|
||||
$categoryid = $this->get_new_parentid('question_category');
|
||||
if (empty($this->cachedcategory) || $this->cachedcategory->id != $categoryid) {
|
||||
$this->cachedcategory = $DB->get_record('question_categories', array('id' => $categoryid));
|
||||
}
|
||||
// Send all the tags back to the question
|
||||
tag_set('question', $newquestion, $tags, 'core_question', $this->cachedcategory->contextid);
|
||||
// Add the tag to the question.
|
||||
core_tag_tag::add_item_tag('core_question', 'question', $newquestion,
|
||||
context::instance_by_id($this->cachedcategory->contextid),
|
||||
$tagname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1209,16 +1209,14 @@ abstract class restore_dbops {
|
||||
}
|
||||
|
||||
// Process tags
|
||||
if (!empty($CFG->usetags) && isset($user->tags)) { // if enabled in server and present in backup
|
||||
if (core_tag_tag::is_enabled('core', 'user') && isset($user->tags)) { // If enabled in server and present in backup.
|
||||
$tags = array();
|
||||
foreach($user->tags['tag'] as $usertag) {
|
||||
$usertag = (object)$usertag;
|
||||
$tags[] = $usertag->rawname;
|
||||
}
|
||||
if (empty($newuserctxid)) {
|
||||
$newuserctxid = null; // Tag apis expect a null contextid not 0.
|
||||
}
|
||||
tag_set('user', $newuserid, $tags, 'core', $newuserctxid);
|
||||
core_tag_tag::set_item_tags('core', 'user', $newuserid,
|
||||
context_user::instance($newuserid), $tags);
|
||||
}
|
||||
|
||||
// Process preferences
|
||||
|
||||
@@ -75,7 +75,7 @@ class block_blog_tags extends block_base {
|
||||
}
|
||||
return $this->content;
|
||||
|
||||
} else if (empty($CFG->usetags)) {
|
||||
} else if (!core_tag_tag::is_enabled('core', 'post')) {
|
||||
$this->content = new stdClass();
|
||||
$this->content->text = '';
|
||||
if ($this->page->user_is_editing()) {
|
||||
@@ -126,6 +126,7 @@ class block_blog_tags extends block_base {
|
||||
WHERE t.id = ti.tagid AND p.id = ti.itemid
|
||||
$type
|
||||
AND ti.itemtype = 'post'
|
||||
AND ti.component = 'core'
|
||||
AND ti.timemodified > $timewithin";
|
||||
|
||||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
@@ -195,7 +196,9 @@ class block_blog_tags extends block_base {
|
||||
}
|
||||
|
||||
$blogurl->param('tagid', $tag->id);
|
||||
$link = html_writer::link($blogurl, tag_display_name($tag), array('class'=>$tag->class, 'title'=>get_string('numberofentries','blog',$tag->ct)));
|
||||
$link = html_writer::link($blogurl, core_tag_tag::make_display_name($tag),
|
||||
array('class' => $tag->class,
|
||||
'title' => get_string('numberofentries', 'blog', $tag->ct)));
|
||||
$this->content->text .= '<li>' . $link . '</li> ';
|
||||
}
|
||||
$this->content->text .= "\n</ul>\n";
|
||||
|
||||
@@ -47,7 +47,6 @@ class block_tag_flickr extends block_base {
|
||||
global $CFG, $USER;
|
||||
|
||||
//note: do NOT include files at the top of this file
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
if ($this->content !== NULL) {
|
||||
@@ -56,11 +55,12 @@ class block_tag_flickr extends block_base {
|
||||
|
||||
$tagid = optional_param('id', 0, PARAM_INT); // tag id - for backware compatibility
|
||||
$tag = optional_param('tag', '', PARAM_TAG); // tag
|
||||
$tc = optional_param('tc', 0, PARAM_INT); // Tag collection id.
|
||||
|
||||
if ($tag) {
|
||||
$tagobject = tag_get('name', $tag);
|
||||
} else if ($tagid) {
|
||||
$tagobject = tag_get('id', $tagid);
|
||||
if ($tagid) {
|
||||
$tagobject = core_tag_tag::get($tagid);
|
||||
} else if ($tag) {
|
||||
$tagobject = core_tag_tag::get_by_name($tc, $tag);
|
||||
}
|
||||
|
||||
if (empty($tagobject)) {
|
||||
@@ -73,7 +73,9 @@ class block_tag_flickr extends block_base {
|
||||
//include related tags in the photo query ?
|
||||
$tagscsv = $tagobject->name;
|
||||
if (!empty($this->config->includerelatedtags)) {
|
||||
$tagscsv .= ',' . tag_get_related_tags_csv(tag_get_related_tags($tagobject->id), TAG_RETURN_TEXT);
|
||||
foreach ($tagobject->get_related_tags() as $t) {
|
||||
$tagscsv .= ',' . $t->get_display_name(false);
|
||||
}
|
||||
}
|
||||
$tagscsv = urlencode($tagscsv);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class block_tag_flickr_edit_form extends block_edit_form {
|
||||
$mform->setType('config_title', PARAM_TEXT);
|
||||
|
||||
$mform->addElement('text', 'config_numberofphotos', get_string('numberofphotos', 'block_tag_flickr'), array('size' => 5));
|
||||
$mform->setType('config_numberofvideos', PARAM_INT);
|
||||
$mform->setType('config_numberofphotos', PARAM_INT);
|
||||
|
||||
$mform->addElement('selectyesno', 'config_includerelatedtags', get_string('includerelatedtags', 'block_tag_flickr'));
|
||||
$mform->setDefault('config_includerelatedtags', 0);
|
||||
|
||||
@@ -64,7 +64,6 @@ class block_tag_youtube extends block_base {
|
||||
global $CFG;
|
||||
|
||||
//note: do NOT include files at the top of this file
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
if ($this->content !== NULL) {
|
||||
@@ -132,11 +131,12 @@ class block_tag_youtube extends block_base {
|
||||
|
||||
$tagid = optional_param('id', 0, PARAM_INT); // tag id - for backware compatibility
|
||||
$tag = optional_param('tag', '', PARAM_TAG); // tag
|
||||
$tc = optional_param('tc', 0, PARAM_INT); // Tag collection id.
|
||||
|
||||
if ($tag) {
|
||||
$tagobject = tag_get('name', $tag);
|
||||
} else if ($tagid) {
|
||||
$tagobject = tag_get('id', $tagid);
|
||||
if ($tagid) {
|
||||
$tagobject = core_tag_tag::get($tagid);
|
||||
} else if ($tag) {
|
||||
$tagobject = core_tag_tag::get_by_name($tc, $tag);
|
||||
}
|
||||
|
||||
if (empty($tagobject)) {
|
||||
@@ -172,11 +172,12 @@ class block_tag_youtube extends block_base {
|
||||
|
||||
$tagid = optional_param('id', 0, PARAM_INT); // tag id - for backware compatibility
|
||||
$tag = optional_param('tag', '', PARAM_TAG); // tag
|
||||
$tc = optional_param('tc', 0, PARAM_INT); // Tag collection id.
|
||||
|
||||
if ($tag) {
|
||||
$tagobject = tag_get('name', $tag);
|
||||
} else if ($tagid) {
|
||||
$tagobject = tag_get('id', $tagid);
|
||||
if ($tagid) {
|
||||
$tagobject = core_tag_tag::get($tagid);
|
||||
} else if ($tag) {
|
||||
$tagobject = core_tag_tag::get_by_name($tc, $tag);
|
||||
}
|
||||
|
||||
if (empty($tagobject)) {
|
||||
|
||||
@@ -70,6 +70,22 @@ class block_tags extends block_base {
|
||||
$this->config->numberoftags = 80;
|
||||
}
|
||||
|
||||
if (empty($this->config->tagtype)) {
|
||||
$this->config->tagtype = '';
|
||||
}
|
||||
|
||||
if (empty($this->config->ctx)) {
|
||||
$this->config->ctx = 0;
|
||||
}
|
||||
|
||||
if (empty($this->config->rec)) {
|
||||
$this->config->rec = 1;
|
||||
}
|
||||
|
||||
if (empty($this->config->tagcoll)) {
|
||||
$this->config->tagcoll = 0;
|
||||
}
|
||||
|
||||
if ($this->content !== NULL) {
|
||||
return $this->content;
|
||||
}
|
||||
@@ -85,9 +101,11 @@ class block_tags extends block_base {
|
||||
|
||||
// Get a list of tags.
|
||||
|
||||
require_once($CFG->dirroot.'/tag/locallib.php');
|
||||
|
||||
$this->content->text = tag_print_cloud(null, $this->config->numberoftags, true);
|
||||
$tagcloud = core_tag_collection::get_tag_cloud($this->config->tagcoll,
|
||||
$this->config->tagtype,
|
||||
$this->config->numberoftags,
|
||||
'name', '', $this->page->context->id, $this->config->ctx, $this->config->rec);
|
||||
$this->content->text = $OUTPUT->render_from_template('core_tag/tagcloud', $tagcloud->export_for_template($OUTPUT));
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
class block_tags_edit_form extends block_edit_form {
|
||||
protected function specific_definition($mform) {
|
||||
global $CFG;
|
||||
// Fields for editing HTML block title and contents.
|
||||
$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
|
||||
|
||||
@@ -37,11 +38,63 @@ class block_tags_edit_form extends block_edit_form {
|
||||
$mform->setType('config_title', PARAM_TEXT);
|
||||
$mform->setDefault('config_title', get_string('pluginname', 'block_tags'));
|
||||
|
||||
$this->add_collection_selector($mform);
|
||||
|
||||
$numberoftags = array();
|
||||
for ($i = 1; $i <= 200; $i++) {
|
||||
$numberoftags[$i] = $i;
|
||||
}
|
||||
$mform->addElement('select', 'config_numberoftags', get_string('numberoftags', 'blog'), $numberoftags);
|
||||
$mform->setDefault('config_numberoftags', 80);
|
||||
|
||||
$defaults = array(
|
||||
'official' => get_string('officialonly', 'block_tags'),
|
||||
'' => get_string('anytype', 'block_tags'));
|
||||
$mform->addElement('select', 'config_tagtype', get_string('defaultdisplay', 'block_tags'), $defaults);
|
||||
$mform->setDefault('config_tagtype', '');
|
||||
|
||||
$defaults = array(0 => context_system::instance()->get_context_name());
|
||||
$parentcontext = context::instance_by_id($this->block->instance->parentcontextid);
|
||||
if ($parentcontext->contextlevel > CONTEXT_COURSE) {
|
||||
$coursecontext = $parentcontext->get_course_context();
|
||||
$defaults[$coursecontext->id] = $coursecontext->get_context_name();
|
||||
}
|
||||
if ($parentcontext->contextlevel != CONTEXT_SYSTEM) {
|
||||
$defaults[$parentcontext->id] = $parentcontext->get_context_name();
|
||||
}
|
||||
$mform->addElement('select', 'config_ctx', get_string('taggeditemscontext', 'block_tags'), $defaults);
|
||||
$mform->addHelpButton('config_ctx', 'taggeditemscontext', 'block_tags');
|
||||
$mform->setDefault('config_ctx', 0);
|
||||
|
||||
$mform->addElement('advcheckbox', 'config_rec', get_string('recursivecontext', 'block_tags'));
|
||||
$mform->addHelpButton('config_rec', 'recursivecontext', 'block_tags');
|
||||
$mform->setDefault('config_rec', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the tag collection selector
|
||||
*
|
||||
* @param object $mform the form being built.
|
||||
*/
|
||||
protected function add_collection_selector($mform) {
|
||||
$tagcolls = core_tag_collection::get_collections_menu(false, false, get_string('anycollection', 'block_tags'));
|
||||
if (count($tagcolls) <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tagcollssearchable = core_tag_collection::get_collections_menu(false, true);
|
||||
$hasunsearchable = false;
|
||||
foreach ($tagcolls as $id => $name) {
|
||||
if ($id && !array_key_exists($id, $tagcollssearchable)) {
|
||||
$hasunsearchable = true;
|
||||
$tagcolls[$id] = $name . '*';
|
||||
}
|
||||
}
|
||||
|
||||
$mform->addElement('select', 'config_tagcoll', get_string('tagcollection', 'block_tags'), $tagcolls);
|
||||
if ($hasunsearchable) {
|
||||
$mform->addHelpButton('config_tagcoll', 'tagcollection', 'block_tags');
|
||||
}
|
||||
$mform->setDefault('config_tagcoll', 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,24 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['anycollection'] = 'Any';
|
||||
$string['anytype'] = 'All';
|
||||
$string['configtitle'] = 'Block title';
|
||||
$string['disabledtags'] = 'Tags are disabled';
|
||||
$string['defaultdisplay'] = 'Tag type to display';
|
||||
$string['officialonly'] = 'Only official';
|
||||
$string['pluginname'] = 'Tags';
|
||||
$string['recursivecontext'] = 'Include child contexts';
|
||||
$string['recursivecontext_help'] = 'If unchecked, tags of items in the context specified above will be displayed excluding underlying contexts, for example, you can search on course level only without searching inside course activities';
|
||||
$string['tagcollection'] = 'Tag collection';
|
||||
$string['tagcollection_help'] = 'Select tag collection to display tags from. If you choose "Any" '
|
||||
. 'the tags from all collections except for those marked with * will be displayed';
|
||||
$string['taggeditemscontext'] = 'Tagged items context';
|
||||
$string['taggeditemscontext_help'] = 'You can limit the tag cloud to the tags that are present in the current course category, course or module';
|
||||
$string['tags:addinstance'] = 'Add a new tags block';
|
||||
$string['tags:myaddinstance'] = 'Add a new tags block to Dashboard';
|
||||
|
||||
// Deprecated since 3.0
|
||||
// Deprecated since 3.0.
|
||||
|
||||
$string['add'] = 'Add';
|
||||
$string['alltags'] = 'All tags:';
|
||||
|
||||
@@ -45,6 +45,6 @@ Feature: Block tags displaying tag cloud
|
||||
And I should see "Cats" in the "Tags" "block"
|
||||
And I should not see "Neverusedtag" in the "Tags" "block"
|
||||
And I click on "Dogs" "link" in the "Tags" "block"
|
||||
And I should see "Users tagged with \"Dogs\": 1"
|
||||
And I should see "User interests" in the ".tag-index-items h3" "css_element"
|
||||
And I should see "Teacher 1"
|
||||
And I log out
|
||||
|
||||
+6
-8
@@ -24,9 +24,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once(dirname(dirname(__FILE__)).'/config.php');
|
||||
require_once('lib.php');
|
||||
require_once('locallib.php');
|
||||
require_once($CFG->dirroot .'/comment/lib.php');
|
||||
require_once($CFG->dirroot . '/blog/lib.php');
|
||||
require_once($CFG->dirroot . '/blog/locallib.php');
|
||||
require_once($CFG->dirroot . '/comment/lib.php');
|
||||
require_once($CFG->dirroot . '/blog/edit_form.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHA);
|
||||
$id = optional_param('entryid', 0, PARAM_INT);
|
||||
@@ -185,7 +186,6 @@ if (!empty($entry->id)) {
|
||||
}
|
||||
}
|
||||
|
||||
require_once('edit_form.php');
|
||||
$summaryoptions = array('maxfiles' => 99, 'maxbytes' => $CFG->maxbytes, 'trusttext' => true, 'context' => $sitecontext,
|
||||
'subdirs' => file_area_contains_subdirs($sitecontext, 'blog', 'post', $entry->id));
|
||||
$attachmentoptions = array('subdirs' => false, 'maxfiles' => 99, 'maxbytes' => $CFG->maxbytes);
|
||||
@@ -206,9 +206,8 @@ $entry = file_prepare_standard_filemanager($entry,
|
||||
'attachment',
|
||||
$entry->id);
|
||||
|
||||
if (!empty($CFG->usetags) && !empty($entry->id)) {
|
||||
include_once($CFG->dirroot.'/tag/lib.php');
|
||||
$entry->tags = tag_get_tags_array('post', $entry->id);
|
||||
if (!empty($entry->id)) {
|
||||
$entry->tags = core_tag_tag::get_item_tags_array('core', 'post', $entry->id);
|
||||
}
|
||||
|
||||
$entry->action = $action;
|
||||
@@ -271,7 +270,6 @@ switch ($action) {
|
||||
if (empty($entry->id)) {
|
||||
print_error('wrongentryid', 'blog');
|
||||
}
|
||||
$entry->tags = tag_get_tags_array('post', $entry->id);
|
||||
$strformheading = get_string('updateentrywithid', 'blog');
|
||||
|
||||
break;
|
||||
|
||||
+3
-2
@@ -65,10 +65,11 @@ class blog_edit_form extends moodleform {
|
||||
$mform->addHelpButton('publishstate', 'publishto', 'blog');
|
||||
$mform->setDefault('publishstate', 0);
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
if (core_tag_tag::is_enabled('core', 'post')) {
|
||||
$mform->addElement('header', 'tagshdr', get_string('tags', 'tag'));
|
||||
$mform->addElement('tags', 'tags', get_string('tags'));
|
||||
}
|
||||
$mform->addElement('tags', 'tags', get_string('tags'),
|
||||
array('itemtype' => 'post', 'component' => 'core'));
|
||||
|
||||
$allmodnames = array();
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ require_once('../config.php');
|
||||
require_once('lib.php');
|
||||
require_once('external_blog_edit_form.php');
|
||||
require_once($CFG->libdir . '/simplepie/moodle_simplepie.php');
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
require_login();
|
||||
$context = context_system::instance();
|
||||
@@ -58,6 +57,7 @@ if (!empty($id) && !$DB->record_exists('blog_external', array('id' => $id))) {
|
||||
print_error('wrongexternalid', 'blog');
|
||||
} else if (!empty($id)) {
|
||||
$external = $DB->get_record('blog_external', array('id' => $id));
|
||||
$external->autotags = core_tag_tag::get_item_tags_array('core', 'blog_external', $id);
|
||||
}
|
||||
|
||||
$strformheading = ($action == 'edit') ? get_string('editexternalblog', 'blog') : get_string('addnewexternalblog', 'blog');
|
||||
@@ -84,12 +84,9 @@ if ($externalblogform->is_cancelled()) {
|
||||
$newexternal->timemodified = time();
|
||||
|
||||
$newexternal->id = $DB->insert_record('blog_external', $newexternal);
|
||||
core_tag_tag::set_item_tags('core', 'blog_external', $newexternal->id,
|
||||
context_user::instance($newexternal->userid), $data->autotags);
|
||||
blog_sync_external_entries($newexternal);
|
||||
if ($CFG->usetags) {
|
||||
$autotags = (!empty($data->autotags)) ? $data->autotags : null;
|
||||
tag_set('blog_external', $newexternal->id, explode(',', $autotags), 'core',
|
||||
context_user::instance($newexternal->userid)->id);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -107,11 +104,8 @@ if ($externalblogform->is_cancelled()) {
|
||||
$external->timemodified = time();
|
||||
|
||||
$DB->update_record('blog_external', $external);
|
||||
if ($CFG->usetags) {
|
||||
$autotags = (!empty($data->autotags)) ? $data->autotags : null;
|
||||
tag_set('blog_external', $external->id, explode(',', $autotags), 'core',
|
||||
context_user::instance($external->userid)->id);
|
||||
}
|
||||
core_tag_tag::set_item_tags('core', 'blog_external', $external->id,
|
||||
context_user::instance($external->userid), $data->autotags);
|
||||
} else {
|
||||
print_error('wrongexternalid', 'blog');
|
||||
}
|
||||
@@ -125,6 +119,9 @@ if ($externalblogform->is_cancelled()) {
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
navigation_node::override_active_url(new moodle_url('/blog/external_blogs.php'));
|
||||
$PAGE->navbar->add(get_string('addnewexternalblog', 'blog'));
|
||||
|
||||
$PAGE->set_heading(fullname($USER));
|
||||
$PAGE->set_title("$SITE->shortname: $strblogs: $strexternalblogs");
|
||||
|
||||
|
||||
@@ -48,14 +48,14 @@ class blog_edit_external_form extends moodleform {
|
||||
$mform->addElement('textarea', 'description', get_string('description', 'blog'), array('cols' => 50, 'rows' => 7));
|
||||
$mform->addHelpButton('description', 'description', 'blog');
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
$mform->addElement('text', 'filtertags', get_string('filtertags', 'blog'), array('size' => 50));
|
||||
$mform->setType('filtertags', PARAM_TAGLIST);
|
||||
$mform->addHelpButton('filtertags', 'filtertags', 'blog');
|
||||
$mform->addElement('text', 'autotags', get_string('autotags', 'blog'), array('size' => 50));
|
||||
$mform->setType('autotags', PARAM_TAGLIST);
|
||||
$mform->addHelpButton('autotags', 'autotags', 'blog');
|
||||
}
|
||||
// To filter external blogs by their tags we do not need to check if tags in moodle are enabled.
|
||||
$mform->addElement('text', 'filtertags', get_string('filtertags', 'blog'), array('size' => 50));
|
||||
$mform->setType('filtertags', PARAM_TAGLIST);
|
||||
$mform->addHelpButton('filtertags', 'filtertags', 'blog');
|
||||
|
||||
$mform->addElement('tags', 'autotags', get_string('autotags', 'blog'),
|
||||
array('itemtype' => 'blog_external', 'component' => 'core'));
|
||||
$mform->addHelpButton('autotags', 'autotags', 'blog');
|
||||
|
||||
$this->add_action_buttons();
|
||||
|
||||
@@ -115,7 +115,6 @@ class blog_edit_external_form extends moodleform {
|
||||
}
|
||||
|
||||
if ($id = $mform->getElementValue('id')) {
|
||||
$mform->setDefault('autotags', implode(',', tag_get_tags_array('blog_external', $id)));
|
||||
$mform->freeze('url');
|
||||
if ($mform->elementExists('filtertags')) {
|
||||
$mform->freeze('filtertags');
|
||||
|
||||
@@ -24,7 +24,6 @@ require_once(dirname(dirname(__FILE__)).'/config.php');
|
||||
require_once($CFG->dirroot .'/blog/lib.php');
|
||||
require_once($CFG->dirroot .'/blog/locallib.php');
|
||||
require_once($CFG->dirroot .'/course/lib.php');
|
||||
require_once($CFG->dirroot .'/tag/lib.php');
|
||||
require_once($CFG->dirroot .'/comment/lib.php');
|
||||
|
||||
$id = optional_param('id', null, PARAM_INT);
|
||||
|
||||
+104
-3
@@ -29,7 +29,6 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* Library of functions and constants for blog
|
||||
*/
|
||||
require_once($CFG->dirroot .'/blog/rsslib.php');
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
/**
|
||||
* User can edit a blog entry if this is their own blog entry and they have
|
||||
@@ -254,8 +253,8 @@ function blog_sync_external_entries($externalblog) {
|
||||
$id = $DB->insert_record('post', $newentry);
|
||||
|
||||
// Set tags.
|
||||
if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) {
|
||||
tag_set('post', $id, $tags, 'core', context_user::instance($externalblog->userid)->id);
|
||||
if ($tags = core_tag_tag::get_item_tags_array('core', 'blog_external', $externalblog->id)) {
|
||||
core_tag_tag::set_item_tags('core', 'post', $id, context_user::instance($externalblog->userid), $tags);
|
||||
}
|
||||
} else {
|
||||
$newentry->id = $postid;
|
||||
@@ -1046,3 +1045,105 @@ function core_blog_myprofile_navigation(core_user\output\myprofile\tree $tree, $
|
||||
$tree->add_node($blognode);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns posts tagged with a specified tag.
|
||||
*
|
||||
* @param core_tag_tag $tag
|
||||
* @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
|
||||
* are displayed on the page and the per-page limit may be bigger
|
||||
* @param int $fromctx context id where the link was displayed, may be used by callbacks
|
||||
* to display items in the same context first
|
||||
* @param int $ctx context id where to search for records
|
||||
* @param bool $rec search in subcontexts as well
|
||||
* @param int $page 0-based number of page being displayed
|
||||
* @return \core_tag\output\tagindex
|
||||
*/
|
||||
function blog_get_tagged_posts($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = true, $page = 0) {
|
||||
global $CFG, $OUTPUT;
|
||||
require_once($CFG->dirroot.'/user/lib.php');
|
||||
|
||||
$systemcontext = context_system::instance();
|
||||
$perpage = $exclusivemode ? 20 : 5;
|
||||
$context = $ctx ? context::instance_by_id($ctx) : context_system::instance();
|
||||
|
||||
$content = '';
|
||||
if (empty($CFG->enableblogs) || !has_capability('moodle/blog:view', $systemcontext)) {
|
||||
// Blogs are not enabled or are not visible to the current user.
|
||||
$totalpages = 0;
|
||||
} else if ($context->contextlevel != CONTEXT_SYSTEM && empty($CFG->useblogassociations)) {
|
||||
// No blog entries can be associated to the non-system context.
|
||||
$totalpages = 0;
|
||||
} else if (!$rec && $context->contextlevel != CONTEXT_COURSE && $context->contextlevel != CONTEXT_MODULE) {
|
||||
// No blog entries can be associated with category or block context.
|
||||
$totalpages = 0;
|
||||
} else {
|
||||
require_once($CFG->dirroot.'/blog/locallib.php');
|
||||
|
||||
$filters = array('tag' => $tag->id);
|
||||
if ($rec) {
|
||||
if ($context->contextlevel != CONTEXT_SYSTEM) {
|
||||
$filters['context'] = $context->id;
|
||||
}
|
||||
} else if ($context->contextlevel == CONTEXT_COURSE) {
|
||||
$filters['course'] = $context->instanceid;
|
||||
} else if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
$filters['module'] = $context->instanceid;
|
||||
}
|
||||
$bloglisting = new blog_listing($filters);
|
||||
$blogs = $bloglisting->get_entries($page * $perpage, $perpage);
|
||||
$totalcount = $bloglisting->count_entries();
|
||||
$totalpages = ceil($totalcount / $perpage);
|
||||
if (!empty($blogs)) {
|
||||
$tagfeed = new core_tag\output\tagfeed();
|
||||
foreach ($blogs as $blog) {
|
||||
$user = fullclone($blog);
|
||||
$user->id = $blog->userid;
|
||||
$user->deleted = 0;
|
||||
$img = $OUTPUT->user_picture($user, array('size' => 35));
|
||||
$subject = format_string($blog->subject);
|
||||
|
||||
if ($blog->publishstate == 'draft') {
|
||||
$class = 'dimmed';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
|
||||
$url = new moodle_url('/blog/index.php', array('entryid' => $blog->id));
|
||||
$subject = html_writer::link($url, $subject, array('class' => $class));
|
||||
|
||||
$fullname = fullname($user);
|
||||
if (user_can_view_profile($user)) {
|
||||
$profilelink = new moodle_url('/user/view.php', array('id' => $blog->userid));
|
||||
$fullname = html_writer::link($profilelink, $fullname);
|
||||
}
|
||||
$details = $fullname . ', ' . userdate($blog->created);
|
||||
|
||||
$tagfeed->add($img, $subject, $details);
|
||||
}
|
||||
|
||||
$items = $tagfeed->export_for_template($OUTPUT);
|
||||
$content = $OUTPUT->render_from_template('core_tag/tagfeed', $items);
|
||||
|
||||
$urlparams = array('tagid' => $tag->id);
|
||||
if ($context->contextlevel == CONTEXT_COURSE) {
|
||||
$urlparams['courseid'] = $context->instanceid;
|
||||
} else if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
$urlparams['modid'] = $context->instanceid;
|
||||
}
|
||||
$allblogsurl = new moodle_url('/blog/index.php', $urlparams);
|
||||
|
||||
$rv = new core_tag\output\tagindex($tag, 'core', 'post',
|
||||
$content,
|
||||
$exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);
|
||||
$rv->exclusiveurl = $allblogsurl;
|
||||
return $rv;
|
||||
}
|
||||
}
|
||||
|
||||
$rv = new core_tag\output\tagindex($tag, 'core', 'post',
|
||||
$content,
|
||||
$exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);
|
||||
$rv->exclusiveurl = null;
|
||||
return $rv;
|
||||
}
|
||||
|
||||
+51
-38
@@ -256,14 +256,11 @@ class blog_entry implements renderable {
|
||||
// Insert the new blog entry.
|
||||
$this->id = $DB->insert_record('post', $this);
|
||||
|
||||
// Update tags.
|
||||
$this->add_tags_info();
|
||||
|
||||
if (!empty($CFG->useblogassociations)) {
|
||||
$this->add_associations();
|
||||
}
|
||||
|
||||
tag_set('post', $this->id, $this->tags, 'core', context_user::instance($this->userid)->id);
|
||||
core_tag_tag::set_item_tags('core', 'post', $this->id, context_user::instance($this->userid), $this->tags);
|
||||
|
||||
// Trigger an event for the new entry.
|
||||
$event = \core\event\blog_entry_created::create(array(
|
||||
@@ -312,7 +309,7 @@ class blog_entry implements renderable {
|
||||
|
||||
// Update record.
|
||||
$DB->update_record('post', $entry);
|
||||
tag_set('post', $entry->id, $entry->tags, 'core', context_user::instance($this->userid)->id);
|
||||
core_tag_tag::set_item_tags('core', 'post', $entry->id, context_user::instance($this->userid), $entry->tags);
|
||||
|
||||
$event = \core\event\blog_entry_updated::create(array(
|
||||
'objectid' => $entry->id,
|
||||
@@ -336,7 +333,7 @@ class blog_entry implements renderable {
|
||||
// Get record to pass onto the event.
|
||||
$record = $DB->get_record('post', array('id' => $this->id));
|
||||
$DB->delete_records('post', array('id' => $this->id));
|
||||
tag_set('post', $this->id, array(), 'core', context_user::instance($this->userid)->id);
|
||||
core_tag_tag::remove_all_item_tags('core', 'post', $this->id);
|
||||
|
||||
$event = \core\event\blog_entry_deleted::create(array(
|
||||
'objectid' => $this->id,
|
||||
@@ -424,26 +421,6 @@ class blog_entry implements renderable {
|
||||
$fs->delete_area_files(SYSCONTEXTID, 'blog', 'post', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* function to attach tags into an entry
|
||||
* @return void
|
||||
*/
|
||||
public function add_tags_info() {
|
||||
|
||||
$tags = array();
|
||||
|
||||
if ($otags = optional_param('otags', '', PARAM_INT)) {
|
||||
foreach ($otags as $tagid) {
|
||||
// TODO : make this use the tag name in the form.
|
||||
if ($tag = tag_get('id', $tagid)) {
|
||||
$tags[] = $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tag_set('post', $this->id, $tags, 'core', context_user::instance($this->userid)->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* User can edit a blog entry if this is their own blog entry and they have
|
||||
* the capability moodle/blog:create, or if they have the capability
|
||||
@@ -570,7 +547,13 @@ class blog_listing {
|
||||
* Array of blog_entry objects.
|
||||
* @var array $entries
|
||||
*/
|
||||
public $entries = array();
|
||||
public $entries = null;
|
||||
|
||||
/**
|
||||
* Caches the total number of the entries.
|
||||
* @var int
|
||||
*/
|
||||
public $totalentries = null;
|
||||
|
||||
/**
|
||||
* An array of blog_filter_* objects
|
||||
@@ -608,9 +591,12 @@ class blog_listing {
|
||||
public function get_entries($start=0, $limit=10) {
|
||||
global $DB;
|
||||
|
||||
if (empty($this->entries)) {
|
||||
if ($this->entries === null) {
|
||||
if ($sqlarray = $this->get_entry_fetch_sql(false, 'created DESC')) {
|
||||
$this->entries = $DB->get_records_sql($sqlarray['sql'], $sqlarray['params'], $start, $limit);
|
||||
if (!$start && count($this->entries) < $limit) {
|
||||
$this->totalentries = count($this->entries);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -619,6 +605,23 @@ class blog_listing {
|
||||
return $this->entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds total number of blog entries
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count_entries() {
|
||||
global $DB;
|
||||
if ($this->totalentries === null) {
|
||||
if ($sqlarray = $this->get_entry_fetch_sql(true)) {
|
||||
$this->totalentries = $DB->count_records_sql($sqlarray['sql'], $sqlarray['params']);
|
||||
} else {
|
||||
$this->totalentries = 0;
|
||||
}
|
||||
}
|
||||
return $this->totalentries;
|
||||
}
|
||||
|
||||
public function get_entry_fetch_sql($count=false, $sort='lastmodified DESC', $userid = false) {
|
||||
global $DB, $USER, $CFG;
|
||||
|
||||
@@ -626,7 +629,7 @@ class blog_listing {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
|
||||
$allnamefields = get_all_user_name_fields(true, 'u');
|
||||
$allnamefields = \user_picture::fields('u', null, 'useridalias');
|
||||
// The query used to locate blog entries is complicated. It will be built from the following components:
|
||||
$requiredfields = "p.*, $allnamefields, u.email"; // The SELECT clause.
|
||||
$tables = array('p' => 'post', 'u' => 'user'); // Components of the FROM clause (table_id => table_name).
|
||||
@@ -707,13 +710,8 @@ class blog_listing {
|
||||
|
||||
$morelink = '<br /> ';
|
||||
|
||||
if ($sqlarray = $this->get_entry_fetch_sql(true)) {
|
||||
$totalentries = $DB->count_records_sql($sqlarray['sql'], $sqlarray['params']);
|
||||
} else {
|
||||
$totalentries = 0;
|
||||
}
|
||||
|
||||
$entries = $this->get_entries($start, $limit);
|
||||
$totalentries = $this->count_entries();
|
||||
$pagingbar = new paging_bar($totalentries, $page, $limit, $this->get_baseurl());
|
||||
$pagingbar->pagevar = 'blogpage';
|
||||
$blogheaders = blog_get_headers();
|
||||
@@ -909,13 +907,14 @@ class blog_filter_context extends blog_filter {
|
||||
|
||||
$this->availabletypes = array('site' => get_string('site'),
|
||||
'course' => get_string('course'),
|
||||
'module' => get_string('activity'));
|
||||
'module' => get_string('activity'),
|
||||
'context' => get_string('coresystem'));
|
||||
|
||||
switch ($this->type) {
|
||||
case 'course': // Careful of site course!
|
||||
// Ignore course filter if blog associations are not enabled.
|
||||
if ($this->id != $SITE->id && !empty($CFG->useblogassociations)) {
|
||||
$this->overrides = array('site');
|
||||
$this->overrides = array('site', 'context');
|
||||
$context = context_course::instance($this->id);
|
||||
$this->tables['ba'] = 'blog_association';
|
||||
$this->conditions[] = 'p.id = ba.blogid';
|
||||
@@ -930,7 +929,7 @@ class blog_filter_context extends blog_filter {
|
||||
break;
|
||||
case 'module':
|
||||
if (!empty($CFG->useblogassociations)) {
|
||||
$this->overrides = array('course', 'site');
|
||||
$this->overrides = array('course', 'site', 'context');
|
||||
|
||||
$context = context_module::instance($this->id);
|
||||
$this->tables['ba'] = 'blog_association';
|
||||
@@ -939,6 +938,19 @@ class blog_filter_context extends blog_filter {
|
||||
$this->params = array($context->id);
|
||||
}
|
||||
break;
|
||||
case 'context':
|
||||
if ($id != context_system::instance()->id && !empty($CFG->useblogassociations)) {
|
||||
$this->overrides = array('site');
|
||||
$context = context::instance_by_id($this->id);
|
||||
$this->tables['ba'] = 'blog_association';
|
||||
$this->tables['ctx'] = 'context';
|
||||
$this->conditions[] = 'p.id = ba.blogid';
|
||||
$this->conditions[] = 'ctx.id = ba.contextid';
|
||||
$this->conditions[] = 'ctx.path LIKE ?';
|
||||
$this->params = array($context->path . '%');
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1012,6 +1024,7 @@ class blog_filter_tag extends blog_filter {
|
||||
|
||||
$this->conditions = array('ti.tagid = t.id',
|
||||
"ti.itemtype = 'post'",
|
||||
"ti.component = 'core'",
|
||||
'ti.itemid = p.id',
|
||||
't.id = ?');
|
||||
$this->params = array($this->id);
|
||||
|
||||
+1
-15
@@ -132,21 +132,7 @@ class core_blog_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
// Links to tags.
|
||||
$officialtags = tag_get_tags_csv('post', $entry->id, TAG_RETURN_HTML, 'official');
|
||||
$defaulttags = tag_get_tags_csv('post', $entry->id, TAG_RETURN_HTML, 'default');
|
||||
|
||||
if (!empty($CFG->usetags) && ($officialtags || $defaulttags) ) {
|
||||
$o .= $this->output->container_start('tags');
|
||||
|
||||
if ($officialtags) {
|
||||
$o .= get_string('tags', 'tag') .': '. $this->output->container($officialtags, 'officialblogtags');
|
||||
if ($defaulttags) {
|
||||
$o .= ', ';
|
||||
}
|
||||
}
|
||||
$o .= $defaulttags;
|
||||
$o .= $this->output->container_end();
|
||||
}
|
||||
$o .= $this->output->tag_list(core_tag_tag::get_item_tags('core', 'post', $entry->id));
|
||||
|
||||
// Add associations.
|
||||
if (!empty($CFG->useblogassociations) && !empty($entry->renderable->blogassociations)) {
|
||||
|
||||
+2
-4
@@ -217,10 +217,8 @@ function blog_rss_get_feed($context, $args) {
|
||||
$summary = file_rewrite_pluginfile_urls($blogentry->summary, 'pluginfile.php',
|
||||
$sitecontext->id, 'blog', 'post', $blogentry->id);
|
||||
$item->description = format_text($summary, $blogentry->format);
|
||||
if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blogentry->id)) ) {
|
||||
if ($blogtags) {
|
||||
$item->tags = $blogtags;
|
||||
}
|
||||
if ($blogtags = core_tag_tag::get_item_tags_array('core', 'post', $blogentry->id)) {
|
||||
$item->tags = $blogtags;
|
||||
$item->tagscheme = $CFG->wwwroot . '/tag';
|
||||
}
|
||||
$items[] = $item;
|
||||
|
||||
+64
-6
@@ -65,18 +65,15 @@ class core_blog_lib_testcase extends advanced_testcase {
|
||||
));
|
||||
|
||||
// Create default tag.
|
||||
$tag = new stdClass();
|
||||
$tag->userid = $user->id;
|
||||
$tag->name = 'testtagname';
|
||||
$tag->rawname = 'Testtagname';
|
||||
$tag->tagtype = 'official';
|
||||
$tag->id = $DB->insert_record('tag', $tag);
|
||||
$tag = $this->getDataGenerator()->create_tag(array('userid' => $user->id,
|
||||
'rawname' => 'Testtagname', 'tagtype' => 'official'));
|
||||
|
||||
// Create default post.
|
||||
$post = new stdClass();
|
||||
$post->userid = $user->id;
|
||||
$post->groupid = $group->id;
|
||||
$post->content = 'test post content text';
|
||||
$post->module = 'blog';
|
||||
$post->id = $DB->insert_record('post', $post);
|
||||
|
||||
// Grab important ids.
|
||||
@@ -544,5 +541,66 @@ class core_blog_lib_testcase extends advanced_testcase {
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayNotHasKey('blogs', $nodes->getValue($tree));
|
||||
}
|
||||
|
||||
public function test_blog_get_listing_course() {
|
||||
$this->setAdminUser();
|
||||
$coursecontext = context_course::instance($this->courseid);
|
||||
$anothercourse = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Add blog associations with a course.
|
||||
$blog = new blog_entry($this->postid);
|
||||
$blog->add_association($coursecontext->id);
|
||||
|
||||
// There is one entry associated with a course.
|
||||
$bloglisting = new blog_listing(array('course' => $this->courseid));
|
||||
$this->assertCount(1, $bloglisting->get_entries());
|
||||
|
||||
// There is no entry associated with a wrong course.
|
||||
$bloglisting = new blog_listing(array('course' => $anothercourse->id));
|
||||
$this->assertCount(0, $bloglisting->get_entries());
|
||||
|
||||
// There is no entry associated with a module.
|
||||
$bloglisting = new blog_listing(array('module' => $this->cmid));
|
||||
$this->assertCount(0, $bloglisting->get_entries());
|
||||
|
||||
// There is one entry associated with a site (id is ignored).
|
||||
$bloglisting = new blog_listing(array('site' => 12345));
|
||||
$this->assertCount(1, $bloglisting->get_entries());
|
||||
|
||||
// There is one entry associated with course context.
|
||||
$bloglisting = new blog_listing(array('context' => $coursecontext->id));
|
||||
$this->assertCount(1, $bloglisting->get_entries());
|
||||
}
|
||||
|
||||
public function test_blog_get_listing_module() {
|
||||
$this->setAdminUser();
|
||||
$coursecontext = context_course::instance($this->courseid);
|
||||
$contextmodule = context_module::instance($this->cmid);
|
||||
$anothermodule = $this->getDataGenerator()->create_module('page', array('course' => $this->courseid));
|
||||
|
||||
// Add blog associations with a course.
|
||||
$blog = new blog_entry($this->postid);
|
||||
$blog->add_association($contextmodule->id);
|
||||
|
||||
// There is no entry associated with a course.
|
||||
$bloglisting = new blog_listing(array('course' => $this->courseid));
|
||||
$this->assertCount(0, $bloglisting->get_entries());
|
||||
|
||||
// There is one entry associated with a module.
|
||||
$bloglisting = new blog_listing(array('module' => $this->cmid));
|
||||
$this->assertCount(1, $bloglisting->get_entries());
|
||||
|
||||
// There is no entry associated with a wrong module.
|
||||
$bloglisting = new blog_listing(array('module' => $anothermodule->cmid));
|
||||
$this->assertCount(0, $bloglisting->get_entries());
|
||||
|
||||
// There is one entry associated with a site (id is ignored).
|
||||
$bloglisting = new blog_listing(array('site' => 12345));
|
||||
$this->assertCount(1, $bloglisting->get_entries());
|
||||
|
||||
// There is one entry associated with course context (module is a subcontext of a course).
|
||||
$bloglisting = new blog_listing(array('context' => $coursecontext->id));
|
||||
$this->assertCount(1, $bloglisting->get_entries());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -123,10 +123,7 @@ if (!empty($course)) {
|
||||
}
|
||||
|
||||
// Populate course tags.
|
||||
if (!empty($CFG->usetags)) {
|
||||
include_once($CFG->dirroot.'/tag/lib.php');
|
||||
$course->tags = tag_get_tags_array('course', $course->id);
|
||||
}
|
||||
$course->tags = core_tag_tag::get_item_tags_array('core', 'course', $course->id);
|
||||
|
||||
} else {
|
||||
// Editor should respect category context if course context is not set.
|
||||
|
||||
@@ -304,11 +304,12 @@ class course_edit_form extends moodleform {
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($CFG->usetags) &&
|
||||
if (core_tag_tag::is_enabled('core', 'course') &&
|
||||
((empty($course->id) && guess_if_creator_will_have_course_capability('moodle/course:tag', $categorycontext))
|
||||
|| (!empty($course->id) && has_capability('moodle/course:tag', $coursecontext)))) {
|
||||
$mform->addElement('header', 'tagshdr', get_string('tags', 'tag'));
|
||||
$mform->addElement('tags', 'tags', get_string('tags'));
|
||||
$mform->addElement('tags', 'tags', get_string('tags'),
|
||||
array('itemtype' => 'course', 'component' => 'core'));
|
||||
}
|
||||
|
||||
// When two elements we need a group.
|
||||
|
||||
+38
-8
@@ -1648,7 +1648,6 @@ function course_delete_module($cmid) {
|
||||
require_once($CFG->libdir.'/questionlib.php');
|
||||
require_once($CFG->dirroot.'/blog/lib.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
// Get the course module.
|
||||
if (!$cm = $DB->get_record('course_modules', array('id' => $cmid))) {
|
||||
@@ -1717,7 +1716,7 @@ function course_delete_module($cmid) {
|
||||
'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY));
|
||||
|
||||
// Delete all tag instances associated with the instance of this module.
|
||||
tag_delete_instances('mod_' . $modulename, $modcontext->id);
|
||||
core_tag_tag::delete_instances('mod_' . $modulename, null, $modcontext->id);
|
||||
|
||||
// Delete the context.
|
||||
context_helper::delete_instance(CONTEXT_MODULE, $cm->id);
|
||||
@@ -2583,7 +2582,6 @@ function course_overviewfiles_options($course) {
|
||||
*/
|
||||
function create_course($data, $editoroptions = NULL) {
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
//check the categoryid - must be given for all new courses
|
||||
$category = $DB->get_record('course_categories', array('id'=>$data->category), '*', MUST_EXIST);
|
||||
@@ -2669,8 +2667,8 @@ function create_course($data, $editoroptions = NULL) {
|
||||
enrol_course_updated(true, $course, $data);
|
||||
|
||||
// Update course tags.
|
||||
if ($CFG->usetags && isset($data->tags)) {
|
||||
tag_set('course', $course->id, $data->tags, 'core', context_course::instance($course->id)->id);
|
||||
if (isset($data->tags)) {
|
||||
core_tag_tag::set_item_tags('core', 'course', $course->id, context_course::instance($course->id), $data->tags);
|
||||
}
|
||||
|
||||
return $course;
|
||||
@@ -2688,7 +2686,6 @@ function create_course($data, $editoroptions = NULL) {
|
||||
*/
|
||||
function update_course($data, $editoroptions = NULL) {
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
$data->timemodified = time();
|
||||
|
||||
@@ -2776,8 +2773,8 @@ function update_course($data, $editoroptions = NULL) {
|
||||
enrol_course_updated(false, $course, $data);
|
||||
|
||||
// Update course tags.
|
||||
if ($CFG->usetags && isset($data->tags)) {
|
||||
tag_set('course', $course->id, $data->tags, 'core', context_course::instance($course->id)->id);
|
||||
if (isset($data->tags)) {
|
||||
core_tag_tag::set_item_tags('core', 'course', $course->id, context_course::instance($course->id), $data->tags);
|
||||
}
|
||||
|
||||
// Trigger a course updated event.
|
||||
@@ -3829,3 +3826,36 @@ function course_view($context, $sectionnumber = 0) {
|
||||
$event = \core\event\course_viewed::create($eventdata);
|
||||
$event->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns courses tagged with a specified tag.
|
||||
*
|
||||
* @param core_tag_tag $tag
|
||||
* @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
|
||||
* are displayed on the page and the per-page limit may be bigger
|
||||
* @param int $fromctx context id where the link was displayed, may be used by callbacks
|
||||
* to display items in the same context first
|
||||
* @param int $ctx context id where to search for records
|
||||
* @param bool $rec search in subcontexts as well
|
||||
* @param int $page 0-based number of page being displayed
|
||||
* @return \core_tag\output\tagindex
|
||||
*/
|
||||
function course_get_tagged_courses($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0) {
|
||||
global $CFG, $PAGE;
|
||||
require_once($CFG->libdir . '/coursecatlib.php');
|
||||
|
||||
$perpage = $exclusivemode ? $CFG->coursesperpage : 5;
|
||||
$displayoptions = array(
|
||||
'limit' => $perpage,
|
||||
'offset' => $page * $perpage,
|
||||
'viewmoreurl' => null,
|
||||
);
|
||||
|
||||
$courserenderer = $PAGE->get_renderer('core', 'course');
|
||||
$totalcount = coursecat::search_courses_count(array('tagid' => $tag->id, 'ctx' => $ctx, 'rec' => $rec));
|
||||
$content = $courserenderer->tagged_courses($tag->id, $exclusivemode, $ctx, $rec, $displayoptions);
|
||||
$totalpages = ceil($totalcount / $perpage);
|
||||
|
||||
return new core_tag\output\tagindex($tag, 'core', 'course', $content,
|
||||
$exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);
|
||||
}
|
||||
|
||||
+39
-16
@@ -1896,29 +1896,52 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
* Renders html to print list of courses tagged with particular tag
|
||||
*
|
||||
* @param int $tagid id of the tag
|
||||
* @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
|
||||
* are displayed on the page and the per-page limit may be bigger
|
||||
* @param int $fromctx context id where the link was displayed, may be used by callbacks
|
||||
* to display items in the same context first
|
||||
* @param int $ctx context id where to search for records
|
||||
* @param bool $rec search in subcontexts as well
|
||||
* @param array $displayoptions
|
||||
* @return string empty string if no courses are marked with this tag or rendered list of courses
|
||||
*/
|
||||
public function tagged_courses($tagid) {
|
||||
public function tagged_courses($tagid, $exclusivemode = true, $ctx = 0, $rec = true, $displayoptions = null) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir. '/coursecatlib.php');
|
||||
$displayoptions = array('limit' => $CFG->coursesperpage);
|
||||
$displayoptions['viewmoreurl'] = new moodle_url('/course/search.php',
|
||||
array('tagid' => $tagid, 'page' => 1, 'perpage' => $CFG->coursesperpage));
|
||||
$displayoptions['viewmoretext'] = new lang_string('findmorecourses');
|
||||
require_once($CFG->libdir . '/coursecatlib.php');
|
||||
if (empty($displayoptions)) {
|
||||
$displayoptions = array();
|
||||
}
|
||||
$showcategories = coursecat::count_all() > 1;
|
||||
$displayoptions += array('limit' => $CFG->coursesperpage, 'offset' => 0);
|
||||
$chelper = new coursecat_helper();
|
||||
$searchcriteria = array('tagid' => $tagid);
|
||||
$chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT)->
|
||||
set_search_criteria(array('tagid' => $tagid))->
|
||||
$searchcriteria = array('tagid' => $tagid, 'ctx' => $ctx, 'rec' => $rec);
|
||||
$chelper->set_show_courses($showcategories ? self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT :
|
||||
self::COURSECAT_SHOW_COURSES_EXPANDED)->
|
||||
set_search_criteria($searchcriteria)->
|
||||
set_courses_display_options($displayoptions)->
|
||||
set_attributes(array('class' => 'course-search-result course-search-result-tagid'));
|
||||
// (we set the same css class as in search results by tagid)
|
||||
$courses = coursecat::search_courses($searchcriteria, $chelper->get_courses_display_options());
|
||||
$totalcount = coursecat::search_courses_count($searchcriteria);
|
||||
$content = $this->coursecat_courses($chelper, $courses, $totalcount);
|
||||
if ($totalcount) {
|
||||
require_once $CFG->dirroot.'/tag/lib.php';
|
||||
$heading = get_string('courses') . ' ' . get_string('taggedwith', 'tag', tag_get_name($tagid)) .': '. $totalcount;
|
||||
return $this->heading($heading, 3). $content;
|
||||
if ($totalcount = coursecat::search_courses_count($searchcriteria)) {
|
||||
$courses = coursecat::search_courses($searchcriteria, $chelper->get_courses_display_options());
|
||||
if ($exclusivemode) {
|
||||
return $this->coursecat_courses($chelper, $courses, $totalcount);
|
||||
} else {
|
||||
$tagfeed = new core_tag\output\tagfeed();
|
||||
$img = $this->output->pix_icon('i/course', '');
|
||||
foreach ($courses as $course) {
|
||||
$url = course_get_url($course);
|
||||
$imgwithlink = html_writer::link($url, $img);
|
||||
$coursename = html_writer::link($url, $course->get_formatted_name());
|
||||
$details = '';
|
||||
if ($showcategories && ($cat = coursecat::get($course->category, IGNORE_MISSING))) {
|
||||
$details = get_string('category').': '.
|
||||
html_writer::link(new moodle_url('/course/index.php', array('categoryid' => $cat->id)),
|
||||
$cat->get_formatted_name(), array('class' => $cat->visible ? '' : 'dimmed'));
|
||||
}
|
||||
$tagfeed->add($imgwithlink, $coursename, $details);
|
||||
}
|
||||
return $this->output->render_from_template('core_tag/tagfeed', $tagfeed->export_for_template($this->output));
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
+3
-4
@@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
require_once($CFG->dirroot . '/course/tags_form.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT); // Course id.
|
||||
@@ -38,7 +37,7 @@ if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $co
|
||||
print_error('coursehidden', '', $CFG->wwwroot .'/');
|
||||
}
|
||||
require_capability('moodle/course:tag', $context);
|
||||
if (empty($CFG->usetags)) {
|
||||
if (!core_tag_tag::is_enabled('core', 'course')) {
|
||||
print_error('tagsaredisabled', 'tag');
|
||||
}
|
||||
|
||||
@@ -49,14 +48,14 @@ $PAGE->set_title(get_string('coursetags', 'tag'));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
|
||||
$form = new coursetags_form();
|
||||
$data = array('id' => $course->id, 'tags' => tag_get_tags_array('course', $course->id));
|
||||
$data = array('id' => $course->id, 'tags' => core_tag_tag::get_item_tags_array('core', 'course', $course->id));
|
||||
$form->set_data($data);
|
||||
|
||||
$redirecturl = $returnurl ? new moodle_url($returnurl) : course_get_url($course);
|
||||
if ($form->is_cancelled()) {
|
||||
redirect($redirecturl);
|
||||
} else if ($data = $form->get_data()) {
|
||||
tag_set('course', $course->id, $data->tags, 'core', context_course::instance($course->id)->id);
|
||||
core_tag_tag::set_item_tags('core', 'course', $course->id, context_course::instance($course->id), $data->tags);
|
||||
redirect($redirecturl);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ class coursetags_form extends moodleform {
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('tags', 'tags', get_string('tags'));
|
||||
$mform->addElement('tags', 'tags', get_string('tags'),
|
||||
array('itemtype' => 'course', 'component' => 'core'));
|
||||
|
||||
$mform->addElement('hidden', 'id', null);
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
||||
@@ -29,7 +29,6 @@ global $CFG;
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
require_once($CFG->dirroot . '/course/tests/fixtures/course_capability_assignment.php');
|
||||
require_once($CFG->dirroot . '/enrol/imsenterprise/tests/imsenterprise_test.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
class core_course_courselib_testcase extends advanced_testcase {
|
||||
|
||||
@@ -1501,6 +1500,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_course_delete_module($type, $options) {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
@@ -1521,7 +1521,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
switch ($type) {
|
||||
case 'assign':
|
||||
// Add some tags to this assignment.
|
||||
tag_set('assign', $module->id, array('Tag 1', 'Tag 2', 'Tag 3'), 'mod_assign', $modcontext->id);
|
||||
core_tag_tag::set_item_tags('mod_assign', 'assign', $module->id, $modcontext, array('Tag 1', 'Tag 2', 'Tag 3'));
|
||||
|
||||
// Confirm the tag instances were added.
|
||||
$criteria = array('component' => 'mod_assign', 'contextid' => $modcontext->id);
|
||||
|
||||
@@ -605,8 +605,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
*/
|
||||
public function test_search_courses () {
|
||||
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
@@ -636,8 +635,10 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
// Enable coursetag option.
|
||||
set_config('block_tags_showcoursetags', true);
|
||||
// Add tag 'TAG-LABEL ON SECOND COURSE' to Course2.
|
||||
tag_set('course', $course2->id, array('TAG-LABEL ON SECOND COURSE'), 'core', context_course::instance($course2->id)->id);
|
||||
$taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course2->id), '*', MUST_EXIST);
|
||||
core_tag_tag::set_item_tags('core', 'course', $course2->id, context_course::instance($course2->id),
|
||||
array('TAG-LABEL ON SECOND COURSE'));
|
||||
$taginstance = $DB->get_record('tag_instance',
|
||||
array('itemtype' => 'course', 'itemid' => $course2->id), '*', MUST_EXIST);
|
||||
// Search by tagid.
|
||||
$results = core_course_external::search_courses('tagid', $taginstance->tagid);
|
||||
$results = external_api::clean_returnvalue(core_course_external::search_courses_returns(), $results);
|
||||
|
||||
@@ -60,6 +60,7 @@ $string['cachedef_plugin_manager'] = 'Plugin info manager';
|
||||
$string['cachedef_questiondata'] = 'Question definitions';
|
||||
$string['cachedef_repositories'] = 'Repositories instances data';
|
||||
$string['cachedef_string'] = 'Language string cache';
|
||||
$string['cachedef_tags'] = 'Tags collections and areas';
|
||||
$string['cachedef_userselections'] = 'Data used to persist user selections throughout Moodle';
|
||||
$string['cachedef_yuimodules'] = 'YUI Module definitions';
|
||||
$string['cachelock_file_default'] = 'Default file locking';
|
||||
|
||||
@@ -20,3 +20,4 @@ updated,core_tag
|
||||
withselectedtags,core_tag
|
||||
tag:create,core_role
|
||||
categoriesanditems,core_grades
|
||||
taggedwith,core_tag
|
||||
|
||||
@@ -421,6 +421,7 @@ $string['submissionoutofsequencefriendlymessage'] = "You have entered data outsi
|
||||
$string['submit'] = 'Submit';
|
||||
$string['submitandfinish'] = 'Submit and finish';
|
||||
$string['submitted'] = 'Submit: {$a}';
|
||||
$string['tagarea_question'] = 'Questions';
|
||||
$string['technicalinfo'] = 'Technical information';
|
||||
$string['technicalinfo_help'] = 'This technical information is probably only useful for developers working on new question types. It may also be helpful when trying to diagnose problems with questions.';
|
||||
$string['technicalinfominfraction'] = 'Minimum fraction: {$a}';
|
||||
|
||||
+39
-2
@@ -24,12 +24,19 @@
|
||||
|
||||
$string['added'] = 'Official tag(s) added';
|
||||
$string['addotags'] = 'Add official tags';
|
||||
$string['addtagcoll'] = 'Add tag collection';
|
||||
$string['addtagtomyinterests'] = 'Add "{$a}" to my interests';
|
||||
$string['alltagpages'] = 'All tag pages';
|
||||
$string['backtoallitems'] = 'Back to all items tagged with "{$a}"';
|
||||
$string['changessaved'] = 'Changes saved';
|
||||
$string['changetagcoll'] = 'Change tag collection of area {$a}';
|
||||
$string['collnameexplained'] = 'Leave the field empty to use the default value: {$a}';
|
||||
$string['component'] = 'Component';
|
||||
$string['confirmdeletetag'] = 'Are you sure you want to delete this tag?';
|
||||
$string['confirmdeletetags'] = 'Are you sure you want to delete selected tags?';
|
||||
$string['count'] = 'Count';
|
||||
$string['coursetags'] = 'Course tags';
|
||||
$string['defautltagcoll'] = 'Default collection';
|
||||
$string['delete'] = 'Delete';
|
||||
$string['deleteselected'] = 'Delete selected';
|
||||
$string['deleted'] = 'Tag(s) deleted';
|
||||
@@ -38,15 +45,20 @@ $string['description'] = 'Description';
|
||||
$string['editname'] = 'Edit tag name';
|
||||
$string['edittag'] = 'Edit this tag';
|
||||
$string['entertags'] = 'Enter tags...';
|
||||
$string['edittagcoll'] = 'Edit tag collection {$a}';
|
||||
$string['errortagfrontpage'] = 'Tagging the site main page is not allowed';
|
||||
$string['errorupdatingrecord'] = 'Error updating tag record';
|
||||
$string['eventtagadded'] = 'Tag added to an item';
|
||||
$string['eventtagcolldeleted'] = 'Tag collection deleted';
|
||||
$string['eventtagcollcreated'] = 'Tag collection created';
|
||||
$string['eventtagcollupdated'] = 'Tag collection updatedhp ';
|
||||
$string['eventtagcreated'] = 'Tag created';
|
||||
$string['eventtagdeleted'] = 'Tag deleted';
|
||||
$string['eventtagflagged'] = 'Tag flagged';
|
||||
$string['eventtagremoved'] = 'Tag removed from an item';
|
||||
$string['eventtagunflagged'] = 'Tag unflagged';
|
||||
$string['eventtagupdated'] = 'Tag updated';
|
||||
$string['exclusivemode'] = 'Show only tagged {$a->tagarea}';
|
||||
$string['flag'] = 'Flag';
|
||||
$string['flagged'] = 'Tag flagged';
|
||||
$string['flagasinappropriate'] = 'Flag as inappropriate';
|
||||
@@ -54,17 +66,25 @@ $string['helprelatedtags'] = 'Comma separated related tags';
|
||||
$string['changename'] = 'Change tag name';
|
||||
$string['changetype'] = 'Change tag type';
|
||||
$string['id'] = 'id';
|
||||
$string['inalltagcoll'] = 'Everywhere';
|
||||
$string['itemstaggedwith'] = '{$a->tagarea} tagged with "{$a->tag}"';
|
||||
$string['lesstags'] = 'less...';
|
||||
$string['manageofficialtags'] = 'Manage official tags';
|
||||
$string['managetags'] = 'Manage tags';
|
||||
$string['managetagcolls'] = 'Manage tag collections';
|
||||
$string['moretags'] = 'more...';
|
||||
$string['name'] = 'Tag name';
|
||||
$string['namesalreadybeeingused'] = 'Tag names already being used';
|
||||
$string['newnamefor'] = 'New name for tag {$a}';
|
||||
$string['nextpage'] = 'More';
|
||||
$string['notagsfound'] = 'No tags matching "{$a}" found';
|
||||
$string['noresultsfor'] = 'No results for "{$a}"';
|
||||
$string['nothingtoupdate'] = 'Nothing to update';
|
||||
$string['officialtag'] = 'Official';
|
||||
$string['otags'] = 'Official tags';
|
||||
$string['othertags'] = 'Other tags';
|
||||
$string['owner'] = 'Owner';
|
||||
$string['prevpage'] = 'Back';
|
||||
$string['ptags'] = 'User defined tags (Comma separated)';
|
||||
$string['relatedblogs'] = 'Most recent blog entries';
|
||||
$string['relatedtags'] = 'Related tags';
|
||||
@@ -75,16 +95,29 @@ $string['responsiblewillbenotified'] = 'The person responsible will be notified'
|
||||
$string['rssdesc'] = 'This RSS feed was automatically generated by Moodle and contains user generated tags for courses.';
|
||||
$string['rsstitle'] = 'Course tags RSS feed for user: {$a}';
|
||||
$string['search'] = 'Search';
|
||||
$string['searchable'] = 'Searchable';
|
||||
$string['searchable_help'] = 'Tags in this tag collection can be searched for on "Search tags" page. If unchecked, tags can still be accessed by clicking on them or via different search interfaces.';
|
||||
$string['searchresultsfor'] = 'Search results for "{$a}"';
|
||||
$string['searchtags'] = 'Search tags';
|
||||
$string['seeallblogs'] = 'See all blog entries tagged with "{$a}"...';
|
||||
$string['seeallblogs'] = 'See all blog entries tagged with "{$a}"';
|
||||
$string['select'] = 'Select';
|
||||
$string['selectcoll'] = 'Select tag collection';
|
||||
$string['selecttag'] = 'Select tag {$a}';
|
||||
$string['settypedefault'] = 'Remove from official tags';
|
||||
$string['settypeofficial'] = 'Make official';
|
||||
$string['showingfirsttags'] = 'Showing {$a} most popular tags';
|
||||
$string['suredeletecoll'] = 'Are you sure you want to delete tag collection "{$a}"?';
|
||||
$string['tag'] = 'Tag';
|
||||
$string['tagarea_blog_external'] = 'External blog posts';
|
||||
$string['tagarea_post'] = 'Blog posts';
|
||||
$string['tagarea_user'] = 'User interests';
|
||||
$string['tagarea_course'] = 'Courses';
|
||||
$string['tagareaenabled'] = 'Enabled';
|
||||
$string['tagareaname'] = 'Name';
|
||||
$string['tagareas'] = 'Tag areas';
|
||||
$string['tagcollection'] = 'Tag collection';
|
||||
$string['tagcollections'] = 'Tag collections';
|
||||
$string['tagdescription'] = 'Tag description';
|
||||
$string['taggedwith'] = 'tagged with "{$a}"';
|
||||
$string['tags'] = 'Tags';
|
||||
$string['tagsaredisabled'] = 'Tags are disabled';
|
||||
$string['tagtype'] = 'Tag type';
|
||||
@@ -107,3 +140,7 @@ $string['tagtype_official'] = 'Official';
|
||||
$string['thistaghasnodesc'] = 'This tag currently has no description.';
|
||||
$string['updated'] = 'Updated';
|
||||
$string['withselectedtags'] = 'With selected tags...';
|
||||
|
||||
// Deprecated since 3.1 .
|
||||
|
||||
$string['taggedwith'] = 'tagged with "{$a}"';
|
||||
|
||||
+2
-3
@@ -166,9 +166,8 @@ function uninstall_plugin($type, $name) {
|
||||
|
||||
echo $OUTPUT->heading($pluginname);
|
||||
|
||||
// Delete all tag instances associated with this plugin.
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
tag_delete_instances($component);
|
||||
// Delete all tag areas, collections and instances associated with this plugin.
|
||||
core_tag_area::uninstall($component);
|
||||
|
||||
// Custom plugin uninstall.
|
||||
$plugindirectory = core_component::get_plugin_directory($type, $name);
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config"],function(a,b,c,d,e,f){return{init_manage_page:function(){var g=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(".tagtype","click",function(d){d.preventDefault();var e=a(this),f=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:f,official:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagtype",b.tags[0]).done(function(a){g(e);var b=e.parent();e.replaceWith(a),b.find(".tagtype").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),f=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:f,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var f=e.closest("tr").get(0);f&&(d.tags[0].flag?a(f).addClass("flagged-tag"):a(f).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){g(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}),a(".tag-management-table").delegate(".tagnameedit","click keypress",function(h){if("keypress"!==h.type||13===h.keyCode){h.stopImmediatePropagation(),h.preventDefault();var i=a(this),j=a(i.closest("td").get(0)),k=a(j.find("input").get(0)),l=i.attr("data-id"),m=function(f,h){var i=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:f,rawname:h}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,i).done(function(b,f){void 0!==b.warnings[0]?e.get_string("error").done(function(a){d.alert(a,b.warnings[0].message)}):void 0!==f.tags[0]&&c.render("core_tag/tagname",f.tags[0]).done(function(b){g(j),j.html(b),a(j.find(".tagnameedit").get(0)).focus()})})},n=function(){a(".tag-management-table td.tageditingon").each(function(){var b=a(this),c=a(b.find("input").get(0));c.off(),b.removeClass("tageditingon"),c.val(b.attr("data-value"))})};n(),j.addClass("tageditingon"),j.attr("data-value",k.val()),k.select(),k.on("keypress focusout",function(a){f.behatsiterunning&&"focusout"===a.type||("keypress"===a.type&&13===a.keyCode&&(m(l,k.val()),n()),("keypress"===a.type&&27===a.keyCode||"focusout"===a.type)&&n())})}})}}});
|
||||
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config"],function(a,b,c,d,e,f){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 g=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(".tagtype","click",function(d){d.preventDefault();var e=a(this),f=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:f,official:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,j).done(function(a,b){void 0===a.warnings[0]&&void 0!==b.tags[0]&&c.render("core_tag/tagtype",b.tags[0]).done(function(a){g(e);var b=e.parent();e.replaceWith(a),b.find(".tagtype").get(0).focus()})})}),a(".tag-management-table").delegate(".tagflag","click",function(d){d.preventDefault();var e=a(this),f=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:f,flag:i}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,j).done(function(b,d){if(void 0===b.warnings[0]&&void 0!==d.tags[0]){var f=e.closest("tr").get(0);f&&(d.tags[0].flag?a(f).addClass("flagged-tag"):a(f).removeClass("flagged-tag")),c.render("core_tag/tagflag",d.tags[0]).done(function(a){g(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}),a(".tag-management-table").delegate(".tagnameedit","click keypress",function(h){if("keypress"!==h.type||13===h.keyCode){h.stopImmediatePropagation(),h.preventDefault();var i=a(this),j=a(i.closest("td").get(0)),k=a(j.find("input").get(0)),l=i.attr("data-id"),m=function(f,h){var i=b.call([{methodname:"core_tag_update_tags",args:{tags:[{id:f,rawname:h}]}},{methodname:"core_tag_get_tags",args:{tags:[{id:f}]}}],!0);a.when.apply(a,i).done(function(b,f){void 0!==b.warnings[0]?e.get_string("error").done(function(a){d.alert(a,b.warnings[0].message)}):void 0!==f.tags[0]&&c.render("core_tag/tagname",f.tags[0]).done(function(b){g(j),j.html(b),a(j.find(".tagnameedit").get(0)).focus()})})},n=function(){a(".tag-management-table td.tageditingon").each(function(){var b=a(this),c=a(b.find("input").get(0));c.off(),b.removeClass("tageditingon"),c.val(b.attr("data-value"))})};n(),j.addClass("tageditingon"),j.attr("data-value",k.val()),k.select(),k.on("keypress focusout",function(a){f.behatsiterunning&&"focusout"===a.type||("keypress"===a.type&&13===a.keyCode&&(m(l,k.val()),n()),("keypress"===a.type&&27===a.keyCode||"focusout"===a.type)&&n())})}})}}});
|
||||
+30
-2
@@ -27,9 +27,37 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
|
||||
return /** @alias module:core/tag */ {
|
||||
|
||||
/**
|
||||
* Initialises handlers for AJAX methods.
|
||||
* Initialises tag index page.
|
||||
*
|
||||
* @method init
|
||||
* @method init_tagindex_page
|
||||
*/
|
||||
init_tagindex_page: function() {
|
||||
// Click handler for changing tag type.
|
||||
$('body').delegate('.tagarea[data-ta] a[data-quickload=1]', 'click', function(e) {
|
||||
e.preventDefault();
|
||||
var target = $( this ),
|
||||
query = target.context.search.replace(/^\?/, ''),
|
||||
tagarea = target.closest('.tagarea[data-ta]'),
|
||||
args = query.split('&').reduce(function(s,c){var t=c.split('=');s[t[0]]=decodeURIComponent(t[1]);return s;},{});
|
||||
|
||||
var promises = ajax.call([{
|
||||
methodname: 'core_tag_get_tagindex',
|
||||
args: { tagindex: args }
|
||||
}], true);
|
||||
|
||||
$.when.apply($, promises)
|
||||
.done( function(data) {
|
||||
templates.render('core_tag/index', data).done(function(html) {
|
||||
tagarea.replaceWith(html);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialises tag management page.
|
||||
*
|
||||
* @method init_manage_page
|
||||
*/
|
||||
init_manage_page: function() {
|
||||
|
||||
|
||||
+2
-2
@@ -1497,10 +1497,10 @@ class block_manager {
|
||||
if ($bits[0] == 'tag' && !empty($this->page->subpage)) {
|
||||
// better navbar for tag pages
|
||||
$editpage->navbar->add(get_string('tags'), new moodle_url('/tag/'));
|
||||
$tag = tag_get('id', $this->page->subpage, '*');
|
||||
$tag = core_tag_tag::get($this->page->subpage);
|
||||
// tag search page doesn't have subpageid
|
||||
if ($tag) {
|
||||
$editpage->navbar->add($tag->name, new moodle_url('/tag/index.php', array('id'=>$tag->id)));
|
||||
$editpage->navbar->add($tag->get_display_name(), $tag->get_view_url());
|
||||
}
|
||||
}
|
||||
$editpage->navbar->add($block->get_title());
|
||||
|
||||
@@ -74,6 +74,34 @@ class tag_added extends base {
|
||||
s($this->other['itemtype']) . "' with id '{$this->other['itemid']}'.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event from taginstance object
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
* @param stdClass $taginstance
|
||||
* @param string $tagname
|
||||
* @param string $tagrawname
|
||||
* @param bool $addsnapshot trust that $taginstance has all necessary fields and add it as a record snapshot
|
||||
* @return tag_added
|
||||
*/
|
||||
public static function create_from_tag_instance($taginstance, $tagname, $tagrawname, $addsnapshot = false) {
|
||||
$event = self::create(array(
|
||||
'objectid' => $taginstance->id,
|
||||
'contextid' => $taginstance->contextid,
|
||||
'other' => array(
|
||||
'tagid' => $taginstance->tagid,
|
||||
'tagname' => $tagname,
|
||||
'tagrawname' => $tagrawname,
|
||||
'itemid' => $taginstance->itemid,
|
||||
'itemtype' => $taginstance->itemtype
|
||||
)
|
||||
));
|
||||
if ($addsnapshot) {
|
||||
$event->add_record_snapshot('tag_instance', $taginstance);
|
||||
}
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return legacy data for add_to_log().
|
||||
*
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tag collection created event.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Tag collection created event class.
|
||||
*
|
||||
* @package core
|
||||
* @since Moodle 3.0
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tag_collection_created extends base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tag_coll';
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create new event.
|
||||
*
|
||||
* @param object $tagcoll
|
||||
* @return user_graded
|
||||
*/
|
||||
public static function create_from_record($tagcoll) {
|
||||
$event = self::create(array(
|
||||
'objectid' => $tagcoll->id,
|
||||
'context' => \context_system::instance(),
|
||||
));
|
||||
$event->add_record_snapshot('tag_coll', $tagcoll);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventtagcollcreated', 'core_tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' created the tag collection with id '$this->objectid'";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tag collection deleted event.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Tag collection deleted event class.
|
||||
*
|
||||
* @package core
|
||||
* @since Moodle 3.0
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tag_collection_deleted extends base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tag_coll';
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create new event.
|
||||
*
|
||||
* @param object $tagcoll
|
||||
* @return user_graded
|
||||
*/
|
||||
public static function create_from_record($tagcoll) {
|
||||
$event = self::create(array(
|
||||
'objectid' => $tagcoll->id,
|
||||
'context' => \context_system::instance(),
|
||||
));
|
||||
$event->add_record_snapshot('tag_coll', $tagcoll);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventtagcolldeleted', 'core_tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' deleted the tag collection with id '$this->objectid'";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tag collection updated event.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Tag collection updated event class.
|
||||
*
|
||||
* @package core
|
||||
* @since Moodle 3.0
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tag_collection_updated extends base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tag_coll';
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create new event.
|
||||
*
|
||||
* @param object $tagcoll
|
||||
* @return user_graded
|
||||
*/
|
||||
public static function create_from_record($tagcoll) {
|
||||
$event = self::create(array(
|
||||
'objectid' => $tagcoll->id,
|
||||
'context' => \context_system::instance(),
|
||||
));
|
||||
$event->add_record_snapshot('tag_coll', $tagcoll);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventtagcollupdated', 'core_tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' updated the tag collection with id '$this->objectid'";
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,26 @@ class tag_created extends base {
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event from tag object
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
* @param \core_tag_tag|\stdClass $tag
|
||||
* @return tag_created
|
||||
*/
|
||||
public static function create_from_tag($tag) {
|
||||
$event = self::create(array(
|
||||
'objectid' => $tag->id,
|
||||
'relateduserid' => $tag->userid,
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'name' => $tag->name,
|
||||
'rawname' => $tag->rawname
|
||||
)
|
||||
));
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns localised general event name.
|
||||
*
|
||||
|
||||
@@ -74,6 +74,34 @@ class tag_removed extends base {
|
||||
s($this->other['itemtype']) . "' with id '{$this->other['itemid']}'.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event from taginstance object
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
* @param stdClass $taginstance
|
||||
* @param string $tagname
|
||||
* @param string $tagrawname
|
||||
* @param bool $addsnapshot trust that $taginstance has all necessary fields and add it as a record snapshot
|
||||
* @return tag_removed
|
||||
*/
|
||||
public static function create_from_tag_instance($taginstance, $tagname, $tagrawname, $addsnapshot = false) {
|
||||
$event = self::create(array(
|
||||
'objectid' => $taginstance->id,
|
||||
'contextid' => $taginstance->contextid,
|
||||
'other' => array(
|
||||
'tagid' => $taginstance->tagid,
|
||||
'tagname' => $tagname,
|
||||
'tagrawname' => $tagrawname,
|
||||
'itemid' => $taginstance->itemid,
|
||||
'itemtype' => $taginstance->itemtype
|
||||
)
|
||||
));
|
||||
if ($addsnapshot) {
|
||||
$event->add_record_snapshot('tag_instance', $taginstance);
|
||||
}
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
namespace core\task;
|
||||
|
||||
use core_tag_collection, core_tag_tag, core_tag_area, stdClass;
|
||||
|
||||
/**
|
||||
* Simple task to run the tag cron.
|
||||
*/
|
||||
@@ -45,9 +47,224 @@ class tag_cron_task extends scheduled_task {
|
||||
global $CFG;
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
tag_cron();
|
||||
$this->compute_correlations();
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates and stores the correlated tags of all tags.
|
||||
*
|
||||
* The correlations are stored in the 'tag_correlation' table.
|
||||
*
|
||||
* Two tags are correlated if they appear together a lot. Ex.: Users tagged with "computers"
|
||||
* will probably also be tagged with "algorithms".
|
||||
*
|
||||
* The rationale for the 'tag_correlation' table is performance. It works as a cache
|
||||
* for a potentially heavy load query done at the 'tag_instance' table. So, the
|
||||
* 'tag_correlation' table stores redundant information derived from the 'tag_instance' table.
|
||||
*
|
||||
* @param int $mincorrelation Only tags with more than $mincorrelation correlations will be identified.
|
||||
*/
|
||||
public function compute_correlations($mincorrelation = 2) {
|
||||
global $DB;
|
||||
|
||||
// This mighty one line query fetches a row from the database for every
|
||||
// individual tag correlation. We then need to process the rows collecting
|
||||
// the correlations for each tag id.
|
||||
// The fields used by this query are as follows:
|
||||
// tagid : This is the tag id, there should be at least $mincorrelation
|
||||
// rows for each tag id.
|
||||
// correlation : This is the tag id that correlates to the above tagid field.
|
||||
// correlationid : This is the id of the row in the tag_correlation table that
|
||||
// relates to the tagid field and will be NULL if there are no
|
||||
// existing correlations.
|
||||
$sql = 'SELECT pairs.tagid, pairs.correlation, pairs.ocurrences, co.id AS correlationid
|
||||
FROM (
|
||||
SELECT ta.tagid, tb.tagid AS correlation, COUNT(*) AS ocurrences
|
||||
FROM {tag_instance} ta
|
||||
JOIN {tag} tga ON ta.tagid = tga.id
|
||||
JOIN {tag_instance} tb ON (ta.itemtype = tb.itemtype AND ta.component = tb.component
|
||||
AND ta.itemid = tb.itemid AND ta.tagid <> tb.tagid)
|
||||
JOIN {tag} tgb ON tb.tagid = tgb.id AND tgb.tagcollid = tga.tagcollid
|
||||
GROUP BY ta.tagid, tb.tagid
|
||||
HAVING COUNT(*) > :mincorrelation
|
||||
) pairs
|
||||
LEFT JOIN {tag_correlation} co ON co.tagid = pairs.tagid
|
||||
ORDER BY pairs.tagid ASC, pairs.ocurrences DESC, pairs.correlation ASC';
|
||||
$rs = $DB->get_recordset_sql($sql, array('mincorrelation' => $mincorrelation));
|
||||
|
||||
// Set up an empty tag correlation object.
|
||||
$tagcorrelation = new stdClass;
|
||||
$tagcorrelation->id = null;
|
||||
$tagcorrelation->tagid = null;
|
||||
$tagcorrelation->correlatedtags = array();
|
||||
|
||||
// We store each correlation id in this array so we can remove any correlations
|
||||
// that no longer exist.
|
||||
$correlations = array();
|
||||
|
||||
// Iterate each row of the result set and build them into tag correlations.
|
||||
// We add all of a tag's correlations to $tagcorrelation->correlatedtags[]
|
||||
// then save the $tagcorrelation object.
|
||||
foreach ($rs as $row) {
|
||||
if ($row->tagid != $tagcorrelation->tagid) {
|
||||
// The tag id has changed so we have all of the correlations for this tag.
|
||||
$tagcorrelationid = $this->process_computed_correlation($tagcorrelation);
|
||||
if ($tagcorrelationid) {
|
||||
$correlations[] = $tagcorrelationid;
|
||||
}
|
||||
// Now we reset the tag correlation object so we can reuse it and set it
|
||||
// up for the current record.
|
||||
$tagcorrelation = new stdClass;
|
||||
$tagcorrelation->id = $row->correlationid;
|
||||
$tagcorrelation->tagid = $row->tagid;
|
||||
$tagcorrelation->correlatedtags = array();
|
||||
}
|
||||
// Save the correlation on the tag correlation object.
|
||||
$tagcorrelation->correlatedtags[] = $row->correlation;
|
||||
}
|
||||
// Update the current correlation after the last record.
|
||||
$tagcorrelationid = $this->process_computed_correlation($tagcorrelation);
|
||||
if ($tagcorrelationid) {
|
||||
$correlations[] = $tagcorrelationid;
|
||||
}
|
||||
|
||||
// Close the recordset.
|
||||
$rs->close();
|
||||
|
||||
// Remove any correlations that weren't just identified.
|
||||
if (empty($correlations)) {
|
||||
// There are no tag correlations.
|
||||
$DB->delete_records('tag_correlation');
|
||||
} else {
|
||||
list($sql, $params) = $DB->get_in_or_equal($correlations,
|
||||
SQL_PARAMS_NAMED, 'param0000', false);
|
||||
$DB->delete_records_select('tag_correlation', 'id '.$sql, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the tag tables, making sure all tagged object still exists.
|
||||
*
|
||||
* This method is called from cron.
|
||||
*
|
||||
* This should normally not be necessary, but in case related tags are not deleted
|
||||
* when the tagged record is removed, this should be done once in a while, perhaps
|
||||
* on an occasional cron run. On a site with lots of tags, this could become an
|
||||
* expensive function to call.
|
||||
*/
|
||||
public function cleanup() {
|
||||
global $DB;
|
||||
|
||||
// Get ids to delete from instances where the tag has been deleted. This should never happen apparently.
|
||||
$sql = "SELECT ti.id
|
||||
FROM {tag_instance} ti
|
||||
LEFT JOIN {tag} t ON t.id = ti.tagid
|
||||
WHERE t.id IS null";
|
||||
$tagids = $DB->get_records_sql($sql);
|
||||
$tagarray = array();
|
||||
foreach ($tagids as $tagid) {
|
||||
$tagarray[] = $tagid->id;
|
||||
}
|
||||
|
||||
// Next get ids from instances that have an owner that has been deleted.
|
||||
$sql = "SELECT ti.id
|
||||
FROM {tag_instance} ti, {user} u
|
||||
WHERE ti.itemid = u.id
|
||||
AND ti.itemtype = 'user'
|
||||
AND ti.component = 'core'
|
||||
AND u.deleted = 1";
|
||||
$tagids = $DB->get_records_sql($sql);
|
||||
foreach ($tagids as $tagid) {
|
||||
$tagarray[] = $tagid->id;
|
||||
}
|
||||
|
||||
// Get the other itemtypes.
|
||||
$sql = "SELECT DISTINCT component, itemtype
|
||||
FROM {tag_instance}
|
||||
WHERE itemtype <> 'user' or component <> 'core'";
|
||||
$tagareas = $DB->get_records_sql($sql);
|
||||
foreach ($tagareas as $tagarea) {
|
||||
$sql = 'SELECT ti.id
|
||||
FROM {tag_instance} ti
|
||||
LEFT JOIN {' . $tagarea->itemtype . '} it ON it.id = ti.itemid
|
||||
WHERE it.id IS null
|
||||
AND ti.itemtype = ? AND ti.component = ?';
|
||||
$tagids = $DB->get_records_sql($sql, array($tagarea->itemtype, $tagarea->component));
|
||||
foreach ($tagids as $tagid) {
|
||||
$tagarray[] = $tagid->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Get instances for each of the ids to be deleted.
|
||||
if (count($tagarray) > 0) {
|
||||
list($sqlin, $params) = $DB->get_in_or_equal($tagarray);
|
||||
$sql = "SELECT ti.*, COALESCE(t.name, 'deleted') AS name, COALESCE(t.rawname, 'deleted') AS rawname
|
||||
FROM {tag_instance} ti
|
||||
LEFT JOIN {tag} t ON t.id = ti.tagid
|
||||
WHERE ti.id $sqlin";
|
||||
$instances = $DB->get_records_sql($sql, $params);
|
||||
$this->bulk_delete_instances($instances);
|
||||
}
|
||||
|
||||
core_tag_collection::cleanup_unused_tags();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function processes a tag correlation and makes changes in the database as required.
|
||||
*
|
||||
* The tag correlation object needs have both a tagid property and a correlatedtags property that is an array.
|
||||
*
|
||||
* @param stdClass $tagcorrelation
|
||||
* @return int/bool The id of the tag correlation that was just processed or false.
|
||||
*/
|
||||
public function process_computed_correlation(stdClass $tagcorrelation) {
|
||||
global $DB;
|
||||
|
||||
// You must provide a tagid and correlatedtags must be set and be an array.
|
||||
if (empty($tagcorrelation->tagid) || !isset($tagcorrelation->correlatedtags) ||
|
||||
!is_array($tagcorrelation->correlatedtags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tagcorrelation->correlatedtags = join(',', $tagcorrelation->correlatedtags);
|
||||
if (!empty($tagcorrelation->id)) {
|
||||
// The tag correlation already exists so update it.
|
||||
$DB->update_record('tag_correlation', $tagcorrelation);
|
||||
} else {
|
||||
// This is a new correlation to insert.
|
||||
$tagcorrelation->id = $DB->insert_record('tag_correlation', $tagcorrelation);
|
||||
}
|
||||
return $tagcorrelation->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will delete numerous tag instances efficiently.
|
||||
* This removes tag instances only. It doesn't check to see if it is the last use of a tag.
|
||||
*
|
||||
* @param array $instances An array of tag instance objects with the addition of the tagname and tagrawname
|
||||
* (used for recording a delete event).
|
||||
*/
|
||||
public function bulk_delete_instances($instances) {
|
||||
global $DB;
|
||||
|
||||
$instanceids = array();
|
||||
foreach ($instances as $instance) {
|
||||
$instanceids[] = $instance->id;
|
||||
}
|
||||
|
||||
// This is a multi db compatible method of creating the correct sql when using the 'IN' value.
|
||||
// $insql is the sql statement, $params are the id numbers.
|
||||
list($insql, $params) = $DB->get_in_or_equal($instanceids);
|
||||
$sql = 'id ' . $insql;
|
||||
$DB->delete_records_select('tag_instance', $sql, $params);
|
||||
|
||||
// Now go through and record each tag individually with the event system.
|
||||
foreach ($instances as $instance) {
|
||||
// Trigger tag removed event (i.e. The tag instance has been removed).
|
||||
\core\event\tag_removed::create_from_tag_instance($instance, $instance->name,
|
||||
$instance->rawname, true)->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-2
@@ -1339,8 +1339,27 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
|
||||
} else if (!empty($search['tagid'])) {
|
||||
// Search courses that are tagged with the specified tag.
|
||||
$where = "c.id IN (SELECT t.itemid ".
|
||||
"FROM {tag_instance} t WHERE t.tagid = :tagid AND t.itemtype = :itemtype)";
|
||||
$params = array('tagid' => $search['tagid'], 'itemtype' => 'course');
|
||||
"FROM {tag_instance} t WHERE t.tagid = :tagid AND t.itemtype = :itemtype AND t.component = :component)";
|
||||
$params = array('tagid' => $search['tagid'], 'itemtype' => 'course', 'component' => 'core');
|
||||
if (!empty($search['ctx'])) {
|
||||
$rec = isset($search['rec']) ? $search['rec'] : true;
|
||||
$parentcontext = context::instance_by_id($search['ctx']);
|
||||
if ($parentcontext->contextlevel == CONTEXT_SYSTEM && $rec) {
|
||||
// Parent context is system context and recursive is set to yes.
|
||||
// Nothing to filter - all courses fall into this condition.
|
||||
} else if ($rec) {
|
||||
// Filter all courses in the parent context at any level.
|
||||
$where .= ' AND ctx.path LIKE :contextpath';
|
||||
$params['contextpath'] = $parentcontext->path . '%';
|
||||
} else if ($parentcontext->contextlevel == CONTEXT_COURSECAT) {
|
||||
// All courses in the given course category.
|
||||
$where .= ' AND c.category = :category';
|
||||
$params['category'] = $parentcontext->instanceid;
|
||||
} else {
|
||||
// No courses will satisfy the context criterion, do not bother searching.
|
||||
$where = '1=0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugging('No criteria is specified while searching courses', DEBUG_DEVELOPER);
|
||||
return array();
|
||||
|
||||
@@ -252,6 +252,12 @@ $definitions = array(
|
||||
'simpledata' => true,
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 5
|
||||
),
|
||||
|
||||
// Caches data about tag collections and areas.
|
||||
'tags' => array(
|
||||
'mode' => cache_store::MODE_REQUEST,
|
||||
'simplekeys' => true,
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
+41
-5
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20150922" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20160111" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@@ -1958,10 +1958,43 @@
|
||||
<KEY NAME="importer" TYPE="foreign" FIELDS="importer" REFTABLE="user" REFFIELDS="id" COMMENT="user who is importing"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="tag_coll" COMMENT="Defines different set of tags">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="isdefault" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="sortorder" TYPE="int" LENGTH="5" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="searchable" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Whether the tag collection is searchable"/>
|
||||
<FIELD NAME="customurl" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Custom URL for the tag page instead of /tag/index.php"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="tag_area" COMMENT="Defines various tag areas, one area is identified by component and itemtype">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="itemtype" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="enabled" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
|
||||
<FIELD NAME="tagcollid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="callback" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="callbackfile" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="tagcollid" TYPE="foreign" FIELDS="tagcollid" REFTABLE="tag_coll" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="compitemtype" UNIQUE="true" FIELDS="component, itemtype"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="tag" COMMENT="Tag table - this generic table will replace the old "tags" table.">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="tagcollid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="rawname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The raw, unnormalised name for the tag as entered by users"/>
|
||||
<FIELD NAME="tagtype" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
|
||||
@@ -1973,9 +2006,11 @@
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
|
||||
<KEY NAME="tagcollid" TYPE="foreign" FIELDS="tagcollid" REFTABLE="tag_coll" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="name" UNIQUE="true" FIELDS="name" COMMENT="tag names are unique"/>
|
||||
<INDEX NAME="tagcollname" UNIQUE="true" FIELDS="tagcollid, name"/>
|
||||
<INDEX NAME="tagcolltype" UNIQUE="false" FIELDS="tagcollid, tagtype"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="tag_correlation" COMMENT="The rationale for the 'tag_correlation' table is performance. It works as a cache for a potentially heavy load query done at the 'tag_instance' table. So, the 'tag_correlation' table stores redundant information derived from the 'tag_instance' table">
|
||||
@@ -1993,8 +2028,8 @@
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="tagid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="Defines the Moodle component which the tag was added to"/>
|
||||
<FIELD NAME="itemtype" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" COMMENT="Defines the Moodle component which the tag was added to"/>
|
||||
<FIELD NAME="itemtype" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The context id of the item that was tagged"/>
|
||||
<FIELD NAME="tiuserid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
@@ -2008,7 +2043,8 @@
|
||||
<KEY NAME="contextid" TYPE="foreign" FIELDS="contextid" REFTABLE="context" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="itemtype-itemid-tagid-tiuserid" UNIQUE="true" FIELDS="itemtype, itemid, tagid, tiuserid"/>
|
||||
<INDEX NAME="taggeditem" UNIQUE="true" FIELDS="component, itemtype, itemid, tiuserid, tagid"/>
|
||||
<INDEX NAME="taglookup" UNIQUE="false" FIELDS="itemtype, component, tagid, contextid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="groups" COMMENT="Each record represents a group.">
|
||||
|
||||
@@ -1148,6 +1148,14 @@ $functions = array(
|
||||
'ajax' => true
|
||||
),
|
||||
|
||||
'core_tag_get_tagindex' => array(
|
||||
'classname' => 'core_tag_external',
|
||||
'methodname' => 'get_tagindex',
|
||||
'description' => 'Gets tag index page for one tag and one tag area',
|
||||
'type' => 'read',
|
||||
'ajax' => true
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
$services = array(
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tag area definitions
|
||||
*
|
||||
* File db/tag.php lists all available tag areas in core or a plugin.
|
||||
*
|
||||
* Each tag area may have the following attributes:
|
||||
* - itemtype (required) - what is tagged. Must be name of the existing DB table
|
||||
* - component - component responsible for tagging, if the tag area is inside a
|
||||
* plugin the component must be the full frankenstyle name of the plugin
|
||||
* - collection - name of the custom tag collection that will be used to store
|
||||
* tags in this area. If specified aministrator will be able to neither add
|
||||
* any other tag areas to this collection nor move this tag area elsewhere
|
||||
* - searchable (only if collection is specified) - wether the tag collection
|
||||
* should be searchable on /tag/search.php
|
||||
* - customurl (only if collection is specified) - custom url to use instead of
|
||||
* /tag/search.php to display information about one tag
|
||||
* - callback - name of the function that returns items tagged with this tag,
|
||||
* see core_tag_tag::get_tag_index() and existing callbacks for more details,
|
||||
* callback should return instance of core_tag\output\tagindex
|
||||
* - callbackfile - file where callback is located (if not an autoloaded location)
|
||||
*
|
||||
* Language file must contain the human-readable names of the tag areas and
|
||||
* collections (either in plugin language file or in component language file or
|
||||
* lang/en/tag.php in case of core):
|
||||
* - for item type "user":
|
||||
* $string['tagarea_user'] = 'Users';
|
||||
* - for tag collection "mycollection":
|
||||
* $string['tagcollection_mycollection'] = 'My tag collection';
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$tagareas = array(
|
||||
array(
|
||||
'itemtype' => 'user', // Users.
|
||||
'component' => 'core',
|
||||
'callback' => 'user_get_tagged_users',
|
||||
'callbackfile' => '/user/lib.php',
|
||||
),
|
||||
array(
|
||||
'itemtype' => 'course', // Courses.
|
||||
'component' => 'core',
|
||||
'callback' => 'course_get_tagged_courses',
|
||||
'callbackfile' => '/course/lib.php',
|
||||
),
|
||||
array(
|
||||
'itemtype' => 'question', // Questions.
|
||||
'component' => 'core_question',
|
||||
),
|
||||
array(
|
||||
'itemtype' => 'post', // Blog posts.
|
||||
'component' => 'core',
|
||||
'callback' => 'blog_get_tagged_posts',
|
||||
'callbackfile' => '/blog/lib.php',
|
||||
),
|
||||
array(
|
||||
'itemtype' => 'blog_external', // External blogs.
|
||||
'component' => 'core',
|
||||
),
|
||||
);
|
||||
+2
-2
@@ -71,8 +71,8 @@ $tasks = array(
|
||||
array(
|
||||
'classname' => 'core\task\tag_cron_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '20',
|
||||
'hour' => '*',
|
||||
'minute' => 'R',
|
||||
'hour' => '3',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
|
||||
@@ -4620,5 +4620,191 @@ function xmldb_main_upgrade($oldversion) {
|
||||
// Moodle v3.0.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2016011100.00) {
|
||||
|
||||
// This is a big upgrade script. We create new table tag_coll and the field
|
||||
// tag.tagcollid pointing to it.
|
||||
|
||||
// Define table tag_coll to be created.
|
||||
$table = new xmldb_table('tag_coll');
|
||||
|
||||
// Adding fields to table tagcloud.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
|
||||
$table->add_field('isdefault', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null);
|
||||
$table->add_field('sortorder', XMLDB_TYPE_INTEGER, '5', null, XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('searchable', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
|
||||
$table->add_field('customurl', XMLDB_TYPE_CHAR, '255', null, null, null, null);
|
||||
|
||||
// Adding keys to table tagcloud.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
|
||||
// Conditionally launch create table for tagcloud.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Table {tag}.
|
||||
// Define index name (unique) to be dropped form tag - we will replace it with index on (tagcollid,name) later.
|
||||
$table = new xmldb_table('tag');
|
||||
$index = new xmldb_index('name', XMLDB_INDEX_UNIQUE, array('name'));
|
||||
|
||||
// Conditionally launch drop index name.
|
||||
if ($dbman->index_exists($table, $index)) {
|
||||
$dbman->drop_index($table, $index);
|
||||
}
|
||||
|
||||
// Define field tagcollid to be added to tag, we create it as null first and will change to notnull later.
|
||||
$table = new xmldb_table('tag');
|
||||
$field = new xmldb_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'userid');
|
||||
|
||||
// Conditionally launch add field tagcloudid.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016011100.02) {
|
||||
// Create a default tag collection if not exists and update the field tag.tagcollid to point to it.
|
||||
if (!$tcid = $DB->get_field_sql('SELECT id FROM {tag_coll} ORDER BY isdefault DESC, sortorder, id', null,
|
||||
IGNORE_MULTIPLE)) {
|
||||
$tcid = $DB->insert_record('tag_coll', array('isdefault' => 1, 'sortorder' => 0));
|
||||
}
|
||||
$DB->execute('UPDATE {tag} SET tagcollid = ? WHERE tagcollid IS NULL', array($tcid));
|
||||
|
||||
// Define index tagcollname (unique) to be added to tag.
|
||||
$table = new xmldb_table('tag');
|
||||
$index = new xmldb_index('tagcollname', XMLDB_INDEX_UNIQUE, array('tagcollid', 'name'));
|
||||
$field = new xmldb_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
|
||||
|
||||
// Conditionally launch add index tagcollname.
|
||||
if (!$dbman->index_exists($table, $index)) {
|
||||
// Launch change of nullability for field tagcollid.
|
||||
$dbman->change_field_notnull($table, $field);
|
||||
$dbman->add_index($table, $index);
|
||||
}
|
||||
|
||||
// Define key tagcollid (foreign) to be added to tag.
|
||||
$table = new xmldb_table('tag');
|
||||
$key = new xmldb_key('tagcollid', XMLDB_KEY_FOREIGN, array('tagcollid'), 'tag_coll', array('id'));
|
||||
|
||||
// Launch add key tagcloudid.
|
||||
$dbman->add_key($table, $key);
|
||||
|
||||
// Define index tagcolltype (not unique) to be added to tag.
|
||||
$table = new xmldb_table('tag');
|
||||
$index = new xmldb_index('tagcolltype', XMLDB_INDEX_NOTUNIQUE, array('tagcollid', 'tagtype'));
|
||||
|
||||
// Conditionally launch add index tagcolltype.
|
||||
if (!$dbman->index_exists($table, $index)) {
|
||||
$dbman->add_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.02);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016011100.03) {
|
||||
|
||||
// Define table tag_area to be created.
|
||||
$table = new xmldb_table('tag_area');
|
||||
|
||||
// Adding fields to table tag_area.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('enabled', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
|
||||
$table->add_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('callback', XMLDB_TYPE_CHAR, '100', null, null, null, null);
|
||||
$table->add_field('callbackfile', XMLDB_TYPE_CHAR, '100', null, null, null, null);
|
||||
|
||||
// Adding keys to table tag_area.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('tagcollid', XMLDB_KEY_FOREIGN, array('tagcollid'), 'tag_coll', array('id'));
|
||||
|
||||
// Adding indexes to table tag_area.
|
||||
$table->add_index('compitemtype', XMLDB_INDEX_UNIQUE, array('component', 'itemtype'));
|
||||
|
||||
// Conditionally launch create table for tag_area.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.03);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016011100.12) {
|
||||
|
||||
// Define index itemtype-itemid-tagid-tiuserid (unique) to be dropped form tag_instance.
|
||||
$table = new xmldb_table('tag_instance');
|
||||
$index = new xmldb_index('itemtype-itemid-tagid-tiuserid', XMLDB_INDEX_UNIQUE,
|
||||
array('itemtype', 'itemid', 'tagid', 'tiuserid'));
|
||||
|
||||
// Conditionally launch drop index itemtype-itemid-tagid-tiuserid.
|
||||
if ($dbman->index_exists($table, $index)) {
|
||||
$dbman->drop_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.12);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016011100.13) {
|
||||
|
||||
$DB->execute("UPDATE {tag_instance} SET component = ? WHERE component IS NULL", array(''));
|
||||
|
||||
// Changing nullability of field component on table tag_instance to not null.
|
||||
$table = new xmldb_table('tag_instance');
|
||||
$field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'tagid');
|
||||
|
||||
// Launch change of nullability for field component.
|
||||
$dbman->change_field_notnull($table, $field);
|
||||
|
||||
// Changing type of field itemtype on table tag_instance to char.
|
||||
$table = new xmldb_table('tag_instance');
|
||||
$field = new xmldb_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'component');
|
||||
|
||||
// Launch change of type for field itemtype.
|
||||
$dbman->change_field_type($table, $field);
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.13);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016011100.14) {
|
||||
|
||||
// Define index taggeditem (unique) to be added to tag_instance.
|
||||
$table = new xmldb_table('tag_instance');
|
||||
$index = new xmldb_index('taggeditem', XMLDB_INDEX_UNIQUE, array('component', 'itemtype', 'itemid', 'tiuserid', 'tagid'));
|
||||
|
||||
// Conditionally launch add index taggeditem.
|
||||
if (!$dbman->index_exists($table, $index)) {
|
||||
$dbman->add_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.14);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016011100.15) {
|
||||
|
||||
// Define index taglookup (not unique) to be added to tag_instance.
|
||||
$table = new xmldb_table('tag_instance');
|
||||
$index = new xmldb_index('taglookup', XMLDB_INDEX_NOTUNIQUE, array('itemtype', 'component', 'tagid', 'contextid'));
|
||||
|
||||
// Conditionally launch add index taglookup.
|
||||
if (!$dbman->index_exists($table, $index)) {
|
||||
$dbman->add_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016011100.15);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+1261
-31
File diff suppressed because it is too large
Load Diff
+122
-33
@@ -63,6 +63,12 @@ class MoodleQuickForm_tags extends MoodleQuickForm_autocomplete {
|
||||
*/
|
||||
protected $showingofficial = false;
|
||||
|
||||
/**
|
||||
* Options passed when creating an element.
|
||||
* @var array
|
||||
*/
|
||||
protected $tagsoptions = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -72,29 +78,66 @@ class MoodleQuickForm_tags extends MoodleQuickForm_autocomplete {
|
||||
* @param mixed $attributes Either a typical HTML attribute string or an associative array.
|
||||
*/
|
||||
public function __construct($elementName = null, $elementLabel = null, $options = array(), $attributes = null) {
|
||||
if (!isset($options['display'])) {
|
||||
$options['display'] = self::DEFAULTUI;
|
||||
}
|
||||
|
||||
$this->showingofficial = $options['display'] != MoodleQuickForm_tags::NOOFFICIAL;
|
||||
|
||||
$validoptions = array();
|
||||
if ($this->showingofficial) {
|
||||
$validoptions = $this->load_official_tags();
|
||||
|
||||
if (!empty($options)) {
|
||||
// Only execute it when the element was created and $options has values set by user.
|
||||
// In onQuickFormEvent() we make sure that $options is not empty even if developer left it empty.
|
||||
if (empty($options['display'])) {
|
||||
$options['display'] = self::DEFAULTUI;
|
||||
}
|
||||
$this->tagsoptions = $options;
|
||||
|
||||
$this->showingofficial = $options['display'] != self::NOOFFICIAL;
|
||||
|
||||
if ($this->showingofficial) {
|
||||
$validoptions = $this->load_official_tags();
|
||||
}
|
||||
// Option 'tags' allows us to type new tags.
|
||||
if ($options['display'] == self::ONLYOFFICIAL) {
|
||||
$attributes['tags'] = false;
|
||||
} else {
|
||||
$attributes['tags'] = true;
|
||||
}
|
||||
$attributes['multiple'] = 'multiple';
|
||||
$attributes['placeholder'] = get_string('entertags', 'tag');
|
||||
$attributes['showsuggestions'] = $this->showingofficial;
|
||||
}
|
||||
// 'tags' option allows us to type new tags.
|
||||
if ($options['display'] == MoodleQuickForm_tags::ONLYOFFICIAL) {
|
||||
$attributes['tags'] = false;
|
||||
} else {
|
||||
$attributes['tags'] = true;
|
||||
}
|
||||
$attributes['multiple'] = 'multiple';
|
||||
$attributes['placeholder'] = get_string('entertags', 'tag');
|
||||
$attributes['showsuggestions'] = $this->showingofficial;
|
||||
|
||||
parent::__construct($elementName, $elementLabel, $validoptions, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by HTML_QuickForm whenever form event is made on this element
|
||||
*
|
||||
* @param string $event Name of event
|
||||
* @param mixed $arg event arguments
|
||||
* @param object $caller calling object
|
||||
* @return bool
|
||||
*/
|
||||
public function onQuickFormEvent($event, $arg, &$caller) {
|
||||
if ($event === 'createElement') {
|
||||
$arg[2] += array('itemtype' => '', 'component' => '');
|
||||
}
|
||||
return parent::onQuickFormEvent($event, $arg, $caller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if tagging is enabled for this itemtype
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function is_tagging_enabled() {
|
||||
if (!empty($this->tagsoptions['itemtype']) && !empty($this->tagsoptions['component'])) {
|
||||
$enabled = core_tag_tag::is_enabled($this->tagsoptions['component'], $this->tagsoptions['itemtype']);
|
||||
if ($enabled === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Backward compatibility with code developed before Moodle 3.0 where itemtype/component were not specified.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Old syntax of class constructor. Deprecated in PHP7.
|
||||
*
|
||||
@@ -105,21 +148,41 @@ class MoodleQuickForm_tags extends MoodleQuickForm_autocomplete {
|
||||
self::__construct($elementName, $elementLabel, $options, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the tag collection to use for official tag selector
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_tag_collection() {
|
||||
if (empty($this->tagsoptions['tagcollid']) && (empty($this->tagsoptions['itemtype']) ||
|
||||
empty($this->tagsoptions['component']))) {
|
||||
debugging('You need to specify \'itemtype\' and \'component\' of the tagged '
|
||||
. 'area in the tags form element options',
|
||||
DEBUG_DEVELOPER);
|
||||
}
|
||||
if (!empty($this->tagsoptions['tagcollid'])) {
|
||||
return $this->tagsoptions['tagcollid'];
|
||||
}
|
||||
if ($this->tagsoptions['itemtype']) {
|
||||
$this->tagsoptions['tagcollid'] = core_tag_area::get_collection($this->tagsoptions['component'],
|
||||
$this->tagsoptions['itemtype']);
|
||||
} else {
|
||||
$this->tagsoptions['tagcollid'] = core_tag_collection::get_default();
|
||||
}
|
||||
return $this->tagsoptions['tagcollid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for select form element.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function toHtml(){
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
if (empty($CFG->usetags)) {
|
||||
debugging('A tags formslib field has been created even thought $CFG->usetags is false.', DEBUG_DEVELOPER);
|
||||
}
|
||||
global $OUTPUT;
|
||||
|
||||
$managelink = '';
|
||||
if (has_capability('moodle/tag:manage', context_system::instance()) && $this->showingofficial) {
|
||||
$url = $CFG->wwwroot .'/tag/manage.php';
|
||||
$url = new moodle_url('/tag/manage.php', array('tc' => $this->get_tag_collection()));
|
||||
$managelink = ' ' . $OUTPUT->action_link($url, get_string('manageofficialtags', 'tag'));
|
||||
}
|
||||
|
||||
@@ -127,21 +190,47 @@ class MoodleQuickForm_tags extends MoodleQuickForm_autocomplete {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to load official tags
|
||||
* Accepts a renderer
|
||||
*
|
||||
* @access protected
|
||||
* @param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
|
||||
* @param bool $required Whether a group is required
|
||||
* @param string $error An error message associated with a group
|
||||
*/
|
||||
public function accept(&$renderer, $required = false, $error = null) {
|
||||
if ($this->is_tagging_enabled()) {
|
||||
$renderer->renderElement($this, $required, $error);
|
||||
} else {
|
||||
$renderer->renderHidden($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to load official tags
|
||||
*/
|
||||
protected function load_official_tags() {
|
||||
global $CFG, $DB;
|
||||
|
||||
$namefield = empty($CFG->keeptagnamecase) ? 'name' : 'rawname';
|
||||
$records = $DB->get_records('tag', array('tagtype' => 'official'), $namefield, 'id,' . $namefield);
|
||||
$tags = array();
|
||||
|
||||
foreach ($records as $record) {
|
||||
$tags[$record->$namefield] = $record->$namefield;
|
||||
if (!$this->is_tagging_enabled()) {
|
||||
return array();
|
||||
}
|
||||
return $tags;
|
||||
$namefield = empty($CFG->keeptagnamecase) ? 'name' : 'rawname';
|
||||
$tags = $DB->get_records_menu('tag',
|
||||
array('tagtype' => 'official', 'tagcollid' => $this->get_tag_collection()),
|
||||
$namefield, 'id,' . $namefield);
|
||||
return array_combine($tags, $tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a 'safe' element's value
|
||||
*
|
||||
* @param array $submitValues array of submitted values to search
|
||||
* @param bool $assoc whether to return the value as associative array
|
||||
* @return mixed
|
||||
*/
|
||||
public function exportValue(&$submitValues, $assoc = false) {
|
||||
if (!$this->is_tagging_enabled()) {
|
||||
return $assoc ? array($this->getName() => array()) : array();
|
||||
}
|
||||
|
||||
return parent::exportValue($submitValues, $assoc);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -3901,7 +3901,6 @@ function delete_user(stdClass $user) {
|
||||
require_once($CFG->libdir.'/grouplib.php');
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
require_once($CFG->dirroot.'/message/lib.php');
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
require_once($CFG->dirroot.'/user/lib.php');
|
||||
|
||||
// Make sure nobody sends bogus record type as parameter.
|
||||
@@ -3944,7 +3943,7 @@ function delete_user(stdClass $user) {
|
||||
// TODO: remove from cohorts using standard API here.
|
||||
|
||||
// Remove user tags.
|
||||
tag_set('user', $user->id, array(), 'core', $usercontext->id);
|
||||
core_tag_tag::remove_all_item_tags('core', 'user', $user->id);
|
||||
|
||||
// Unconditionally unenrol from all courses.
|
||||
enrol_user_delete($user);
|
||||
@@ -4735,7 +4734,6 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
|
||||
require_once($CFG->libdir.'/questionlib.php');
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
require_once($CFG->dirroot.'/group/lib.php');
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
require_once($CFG->dirroot.'/comment/lib.php');
|
||||
require_once($CFG->dirroot.'/rating/lib.php');
|
||||
require_once($CFG->dirroot.'/notes/lib.php');
|
||||
@@ -4910,7 +4908,7 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
|
||||
$rm->delete_ratings($delopt);
|
||||
|
||||
// Delete course tags.
|
||||
tag_set('course', $course->id, array(), 'core', $coursecontext->id);
|
||||
core_tag_tag::remove_all_item_tags('core', 'course', $course->id);
|
||||
|
||||
// Delete calendar events.
|
||||
$DB->delete_records('event', array('courseid' => $course->id));
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
/**
|
||||
* Defines core nodes for my profile navigation tree.
|
||||
@@ -36,7 +35,7 @@ require_once($CFG->dirroot . '/tag/lib.php');
|
||||
* @return bool
|
||||
*/
|
||||
function core_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) {
|
||||
global $CFG, $USER, $DB, $PAGE;
|
||||
global $CFG, $USER, $DB, $PAGE, $OUTPUT;
|
||||
|
||||
$usercontext = context_user::instance($user->id, MUST_EXIST);
|
||||
$systemcontext = context_system::instance();
|
||||
@@ -218,11 +217,10 @@ function core_myprofile_navigation(core_user\output\myprofile\tree $tree, $user,
|
||||
}
|
||||
|
||||
// Printing tagged interests. We want this only for full profile.
|
||||
if (!empty($CFG->usetags) && empty($course)) {
|
||||
if ($interests = tag_get_tags_csv('user', $user->id) ) {
|
||||
$node = new core_user\output\myprofile\node('contact', 'interests', get_string('interests'), null, null, $interests);
|
||||
$tree->add_node($node);
|
||||
}
|
||||
if (empty($course) && ($interests = core_tag_tag::get_item_tags('core', 'user', $user->id))) {
|
||||
$node = new core_user\output\myprofile\node('contact', 'interests', get_string('interests'), null, null,
|
||||
$OUTPUT->tag_list($interests, ''));
|
||||
$tree->add_node($node);
|
||||
}
|
||||
|
||||
if (!isset($hiddenfields['mycourses'])) {
|
||||
|
||||
@@ -4103,6 +4103,23 @@ EOD;
|
||||
$html .= html_writer::end_tag('header');
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the list of tags associated with an entry
|
||||
*
|
||||
* @param array $tags list of instances of core_tag or stdClass
|
||||
* @param string $label label to display in front, by default 'Tags' (get_string('tags')), set to null
|
||||
* to use default, set to '' (empty string) to omit the label completely
|
||||
* @param string $classes additional classes for the enclosing div element
|
||||
* @param int $limit limit the number of tags to display, if size of $tags is more than this limit the "more" link
|
||||
* will be appended to the end, JS will toggle the rest of the tags
|
||||
* @param context $pagecontext specify if needed to overwrite the current page context for the view tag link
|
||||
* @return string
|
||||
*/
|
||||
public function tag_list($tags, $label = null, $classes = '', $limit = 10, $pagecontext = null) {
|
||||
$list = new \core_tag\output\taglist($tags, $label, $classes, $limit, $pagecontext);
|
||||
return $this->render_from_template('core_tag/taglist', $list->export_for_template($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-14
@@ -334,7 +334,7 @@ function question_delete_question($questionid) {
|
||||
$questionid, $question->contextid);
|
||||
|
||||
// Delete all tag instances.
|
||||
$DB->delete_records('tag_instance', array('component' => 'core_question', 'itemid' => $question->id));
|
||||
core_tag_tag::remove_all_item_tags('core_question', 'question', $question->id);
|
||||
|
||||
// Now recursively delete all child questions
|
||||
if ($children = $DB->get_records('question',
|
||||
@@ -435,8 +435,7 @@ function question_delete_course_category($category, $newcategory, $feedback=true
|
||||
}
|
||||
|
||||
// Update the contextid for any tag instances for questions in the old context.
|
||||
$DB->set_field('tag_instance', 'contextid', $newcontext->id, array('component' => 'core_question',
|
||||
'contextid' => $context->id));
|
||||
core_tag_tag::move_context('core_question', 'question', $context, $newcontext);
|
||||
|
||||
$DB->set_field('question_categories', 'contextid', $newcontext->id, array('contextid' => $context->id));
|
||||
|
||||
@@ -544,8 +543,7 @@ function question_move_questions_to_category($questionids, $newcategoryid) {
|
||||
"parent $questionidcondition", $params);
|
||||
|
||||
// Update the contextid for any tag instances that may exist for these questions.
|
||||
$DB->set_field_select('tag_instance', 'contextid', $newcontextid,
|
||||
"component = 'core_question' AND itemid $questionidcondition", $params);
|
||||
core_tag_tag::change_items_context('core_question', 'question', $questionids, $newcontextid);
|
||||
|
||||
// TODO Deal with datasets.
|
||||
|
||||
@@ -577,12 +575,8 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
|
||||
question_bank::notify_question_edited($questionid);
|
||||
}
|
||||
|
||||
if ($questionids) {
|
||||
// Update the contextid for any tag instances that may exist for these questions.
|
||||
list($questionids, $params) = $DB->get_in_or_equal(array_keys($questionids));
|
||||
$DB->set_field_select('tag_instance', 'contextid', $newcontextid,
|
||||
"component = 'core_question' AND itemid $questionids", $params);
|
||||
}
|
||||
core_tag_tag::change_items_context('core_question', 'question',
|
||||
array_keys($questionids), $newcontextid);
|
||||
|
||||
$subcatids = $DB->get_records_menu('question_categories',
|
||||
array('parent' => $categoryid), '', 'id,1');
|
||||
@@ -765,9 +759,8 @@ function _tidy_question($question, $loadtags = false) {
|
||||
unset($question->_partiallyloaded);
|
||||
}
|
||||
|
||||
if ($loadtags && !empty($CFG->usetags)) {
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
$question->tags = tag_get_tags_array('question', $question->id);
|
||||
if ($loadtags && core_tag_tag::is_enabled('core_question', 'question')) {
|
||||
$question->tags = core_tag_tag::get_item_tags_array('core_question', 'question', $question->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -847,6 +847,10 @@ EOD;
|
||||
$record['tagtype'] = 'default';
|
||||
}
|
||||
|
||||
if (!isset($record['tagcollid'])) {
|
||||
$record['tagcollid'] = core_tag_collection::get_default();
|
||||
}
|
||||
|
||||
if (!isset($record['description'])) {
|
||||
$record['description'] = 'Tag description';
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ class core_test_generator_testcase extends advanced_testcase {
|
||||
$this->assertEquals($course->id, $section->course);
|
||||
|
||||
$course = $generator->create_course(array('tags' => 'Cat, Dog'));
|
||||
$this->assertEquals('Cat, Dog', tag_get_tags_csv('course', $course->id, TAG_RETURN_TEXT));
|
||||
$this->assertEquals(array('Cat', 'Dog'), array_values(core_tag_tag::get_item_tags_array('core', 'course', $course->id)));
|
||||
|
||||
$scale = $generator->create_scale();
|
||||
$this->assertNotEmpty($scale);
|
||||
|
||||
@@ -29,7 +29,6 @@ global $CFG;
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
// Get the necessary files to perform backup and restore.
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
@@ -164,21 +163,23 @@ class core_questionlib_testcase extends advanced_testcase {
|
||||
$coursecat2 = $this->getDataGenerator()->create_category();
|
||||
|
||||
// Create a couple of categories and questions.
|
||||
$context1 = context_coursecat::instance($coursecat1->id);
|
||||
$context2 = context_coursecat::instance($coursecat2->id);
|
||||
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$questioncat1 = $questiongenerator->create_question_category(array('contextid' =>
|
||||
context_coursecat::instance($coursecat1->id)->id));
|
||||
$context1->id));
|
||||
$questioncat2 = $questiongenerator->create_question_category(array('contextid' =>
|
||||
context_coursecat::instance($coursecat2->id)->id));
|
||||
$context2->id));
|
||||
$question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id));
|
||||
$question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id));
|
||||
$question3 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id));
|
||||
$question4 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id));
|
||||
|
||||
// Now lets tag these questions.
|
||||
tag_set('question', $question1->id, array('tag 1', 'tag 2'), 'core_question', $questioncat1->contextid);
|
||||
tag_set('question', $question2->id, array('tag 3', 'tag 4'), 'core_question', $questioncat1->contextid);
|
||||
tag_set('question', $question3->id, array('tag 5', 'tag 6'), 'core_question', $questioncat2->contextid);
|
||||
tag_set('question', $question4->id, array('tag 7', 'tag 8'), 'core_question', $questioncat2->contextid);
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $context1, array('tag 1', 'tag 2'));
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $context1, array('tag 3', 'tag 4'));
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question3->id, $context2, array('tag 5', 'tag 6'));
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question4->id, $context2, array('tag 7', 'tag 8'));
|
||||
|
||||
// Test moving the questions to another category.
|
||||
question_move_questions_to_category(array($question1->id, $question2->id), $questioncat2->id);
|
||||
@@ -224,14 +225,15 @@ class core_questionlib_testcase extends advanced_testcase {
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create some question categories and questions in this course.
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$questioncat = $questiongenerator->create_question_category(array('contextid' =>
|
||||
context_course::instance($course->id)->id));
|
||||
$coursecontext->id));
|
||||
$question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id));
|
||||
$question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id));
|
||||
|
||||
// Add some tags to these questions.
|
||||
tag_set('question', $question1->id, array('tag 1', 'tag 2'), 'core_question', $questioncat->contextid);
|
||||
tag_set('question', $question2->id, array('tag 1', 'tag 2'), 'core_question', $questioncat->contextid);
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, array('tag 1', 'tag 2'));
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, array('tag 1', 'tag 2'));
|
||||
|
||||
// Create a course that we are going to restore the other course to.
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
|
||||
+3
-2
@@ -31,8 +31,9 @@ information provided here is intended especially for developers.
|
||||
custom user filters. Similar deprecations in existing user_filter_* classes.
|
||||
* table_default_export_format_parent::table_default_export_format_parent() is
|
||||
deprecated, use parent::__construct() in extending classes.
|
||||
* groups_delete_group_members() $showfeedback parameter has been removed and is no longer
|
||||
respected. Users of this function should output their own feedback if required.
|
||||
* groups_delete_group_members() $showfeedback parameter has been removed and is no longer
|
||||
respected. Users of this function should output their own feedback if required.
|
||||
* Number of changes to Tags API, see tag/upgrade.txt for more details
|
||||
|
||||
=== 3.0 ===
|
||||
|
||||
|
||||
@@ -494,6 +494,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
message_update_processors($plug);
|
||||
}
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
$endcallback($component, true, $verbose);
|
||||
}
|
||||
}
|
||||
@@ -532,6 +533,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
message_update_processors($plug);
|
||||
}
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
$endcallback($component, true, $verbose);
|
||||
|
||||
} else if ($installedversion < $plugin->version) { // upgrade
|
||||
@@ -566,6 +568,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
message_update_processors($plug);
|
||||
}
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
$endcallback($component, false, $verbose);
|
||||
|
||||
} else if ($installedversion > $plugin->version) {
|
||||
@@ -669,6 +672,7 @@ function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
|
||||
message_update_providers($component);
|
||||
\core\message\inbound\manager::update_handlers_for_component($component);
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
$endcallback($component, true, $verbose);
|
||||
}
|
||||
}
|
||||
@@ -703,6 +707,7 @@ function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
|
||||
message_update_providers($component);
|
||||
\core\message\inbound\manager::update_handlers_for_component($component);
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
|
||||
$endcallback($component, true, $verbose);
|
||||
|
||||
@@ -739,6 +744,7 @@ function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
|
||||
message_update_providers($component);
|
||||
\core\message\inbound\manager::update_handlers_for_component($component);
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
|
||||
$endcallback($component, false, $verbose);
|
||||
|
||||
@@ -860,6 +866,7 @@ function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
|
||||
message_update_providers($component);
|
||||
\core\message\inbound\manager::update_handlers_for_component($component);
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
$endcallback($component, true, $verbose);
|
||||
}
|
||||
}
|
||||
@@ -899,6 +906,7 @@ function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
|
||||
\core\task\manager::reset_scheduled_tasks_for_component($component);
|
||||
message_update_providers($component);
|
||||
\core\message\inbound\manager::update_handlers_for_component($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
|
||||
$endcallback($component, true, $verbose);
|
||||
@@ -935,6 +943,7 @@ function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
|
||||
message_update_providers($component);
|
||||
\core\message\inbound\manager::update_handlers_for_component($component);
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
core_tag_area::reset_definitions_for_component($component);
|
||||
|
||||
$endcallback($component, false, $verbose);
|
||||
|
||||
@@ -1536,6 +1545,7 @@ function install_core($version, $verbose) {
|
||||
\core\task\manager::reset_scheduled_tasks_for_component('moodle');
|
||||
message_update_providers('moodle');
|
||||
\core\message\inbound\manager::update_handlers_for_component('moodle');
|
||||
core_tag_area::reset_definitions_for_component('moodle');
|
||||
|
||||
// Write default settings unconditionally
|
||||
admin_apply_default_settings(NULL, true);
|
||||
@@ -1603,6 +1613,7 @@ function upgrade_core($version, $verbose) {
|
||||
\core\task\manager::reset_scheduled_tasks_for_component('moodle');
|
||||
message_update_providers('moodle');
|
||||
\core\message\inbound\manager::update_handlers_for_component('moodle');
|
||||
core_tag_area::reset_definitions_for_component('moodle');
|
||||
// Update core definitions.
|
||||
cache_helper::update_definitions(true);
|
||||
|
||||
|
||||
@@ -104,8 +104,10 @@ class backup_wiki_activity_structure_step extends backup_activity_structure_step
|
||||
FROM {tag} t
|
||||
JOIN {tag_instance} ti ON ti.tagid = t.id
|
||||
WHERE ti.itemtype = ?
|
||||
AND ti.component = ?
|
||||
AND ti.itemid = ?', array(
|
||||
backup_helper::is_sqlparam('wiki_pages'),
|
||||
backup_helper::is_sqlparam('mod_wiki'),
|
||||
backup::VAR_PARENTID));
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ class restore_wiki_activity_structure_step extends restore_activity_structure_st
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
if (empty($CFG->usetags)) { // tags disabled in server, nothing to process
|
||||
if (!core_tag_tag::is_enabled('mod_wiki', 'wiki_pages')) { // Tags disabled in server, nothing to process.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,8 +167,8 @@ class restore_wiki_activity_structure_step extends restore_activity_structure_st
|
||||
$itemid = $this->get_new_parentid('wiki_page');
|
||||
$wikiid = $this->get_new_parentid('wiki');
|
||||
|
||||
$cm = get_coursemodule_from_instance('wiki', $wikiid);
|
||||
tag_set_add('wiki_pages', $itemid, $tag, 'mod_wiki', context_module::instance($cm->id)->id);
|
||||
$context = context_module::instance($this->task->get_moduleid());
|
||||
core_tag_tag::add_item_tag('mod_wiki', 'wiki_pages', $itemid, $context, $tag);
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tag areas in component mod_wiki
|
||||
*
|
||||
* @package mod_wiki
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$tagareas = array(
|
||||
array(
|
||||
'itemtype' => 'wiki_pages',
|
||||
'component' => 'mod_wiki',
|
||||
),
|
||||
);
|
||||
@@ -100,11 +100,11 @@ class mod_wiki_edit_form extends moodleform {
|
||||
$mform->addElement('hidden', 'contentformat', $format);
|
||||
$mform->setType('contentformat', PARAM_ALPHANUMEXT);
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
if (core_tag_tag::is_enabled('mod_wiki', 'wiki_pages')) {
|
||||
$mform->addElement('header', 'tagshdr', get_string('tags', 'tag'));
|
||||
$mform->addElement('tags', 'tags', get_string('tags'));
|
||||
$mform->setType('tags', PARAM_TEXT);
|
||||
}
|
||||
$mform->addElement('tags', 'tags', get_string('tags'),
|
||||
array('itemtype' => 'wiki_pages', 'component' => 'mod_wiki'));
|
||||
|
||||
$buttongroup = array();
|
||||
$buttongroup[] = $mform->createElement('submit', 'editoption', get_string('save', 'wiki'), array('id' => 'save'));
|
||||
|
||||
@@ -219,6 +219,7 @@ $string['searchterms'] = 'Search terms';
|
||||
$string['searchwikis'] = 'Search wikis';
|
||||
$string['special'] = 'Special';
|
||||
$string['tableofcontents'] = 'Table of contents';
|
||||
$string['tagarea_wiki_pages'] = 'Wiki pages';
|
||||
$string['tagsdeleted'] = 'Wiki tags have been deleted';
|
||||
$string['tagtitle'] = 'See the "{$a}" tag';
|
||||
$string['teacherrating'] = 'Teacher rating';
|
||||
|
||||
+23
-16
@@ -141,10 +141,15 @@ function wiki_delete_instance($id) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback to reset course
|
||||
*
|
||||
* @param stdClass $data
|
||||
* @return boolean|array
|
||||
*/
|
||||
function wiki_reset_userdata($data) {
|
||||
global $CFG,$DB;
|
||||
require_once($CFG->dirroot . '/mod/wiki/pagelib.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
require_once($CFG->dirroot . "/mod/wiki/locallib.php");
|
||||
|
||||
$componentstr = get_string('modulenameplural', 'wiki');
|
||||
@@ -154,10 +159,12 @@ function wiki_reset_userdata($data) {
|
||||
if (!$wikis = $DB->get_records('wiki', array('course' => $data->courseid))) {
|
||||
return false;
|
||||
}
|
||||
$errors = false;
|
||||
foreach ($wikis as $wiki) {
|
||||
if (empty($data->reset_wiki_comments) && empty($data->reset_wiki_tags) && empty($data->reset_wiki_pages)) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
if (!$cm = get_coursemodule_from_instance('wiki', $wiki->id)) {
|
||||
foreach ($wikis as $wiki) {
|
||||
if (!$cm = get_coursemodule_from_instance('wiki', $wiki->id, $data->courseid)) {
|
||||
continue;
|
||||
}
|
||||
$context = context_module::instance($cm->id);
|
||||
@@ -175,14 +182,7 @@ function wiki_reset_userdata($data) {
|
||||
if (empty($data->reset_wiki_pages)) {
|
||||
// Go through each page and delete the tags.
|
||||
foreach ($pages as $page) {
|
||||
|
||||
$tags = tag_get_tags_array('wiki_pages', $page->id);
|
||||
foreach ($tags as $tagid => $tagname) {
|
||||
// Delete the related tag_instances related to the wiki page.
|
||||
$errors = tag_delete_instance('wiki_pages', $page->id, $tagid);
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('tagsdeleted', 'wiki'),
|
||||
'error' => $errors);
|
||||
}
|
||||
core_tag_tag::remove_all_item_tags('mod_wiki', 'wiki_pages', $page->id);
|
||||
}
|
||||
} else {
|
||||
// Otherwise we are removing pages and tags.
|
||||
@@ -196,17 +196,24 @@ function wiki_reset_userdata($data) {
|
||||
// Delete any attached files.
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($context->id, 'mod_wiki', 'attachments');
|
||||
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('deleteallpages', 'wiki'),
|
||||
'error' => $errors);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data->reset_wiki_pages)) {
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('deleteallpages', 'wiki'),
|
||||
'error' => false);
|
||||
}
|
||||
if (!empty($data->reset_wiki_tags)) {
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('tagsdeleted', 'wiki'), 'error' => false);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all comments.
|
||||
if (!empty($data->reset_wiki_comments) || !empty($data->reset_wiki_pages)) {
|
||||
$DB->delete_records_select('comments', "contextid = ? AND commentarea='wiki_page'", array($context->id));
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('deleteallcomments'), 'error' => false);
|
||||
if (!empty($data->reset_wiki_comments)) {
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('deleteallcomments'), 'error' => false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
|
||||
+3
-18
@@ -1163,8 +1163,6 @@ function wiki_delete_pages($context, $pageids = null, $subwikiid = null) {
|
||||
return;
|
||||
}
|
||||
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
/// Delete page and all it's relevent data
|
||||
foreach ($pageids as $pageid) {
|
||||
if (is_object($pageid)) {
|
||||
@@ -1178,10 +1176,7 @@ function wiki_delete_pages($context, $pageids = null, $subwikiid = null) {
|
||||
}
|
||||
|
||||
//Delete page tags
|
||||
$tags = tag_get_tags_array('wiki_pages', $pageid);
|
||||
foreach ($tags as $tagid => $tagvalue) {
|
||||
tag_delete_instance('wiki_pages', $pageid, $tagid);
|
||||
}
|
||||
core_tag_tag::remove_all_item_tags('mod_wiki', 'wiki_pages', $pageid);
|
||||
|
||||
//Delete Synonym
|
||||
wiki_delete_synonym($subwikiid, $pageid);
|
||||
@@ -1386,18 +1381,8 @@ function wiki_print_page_content($page, $context, $subwikiid) {
|
||||
$html = format_text($html, FORMAT_MOODLE, array('overflowdiv'=>true, 'allowid'=>true));
|
||||
echo $OUTPUT->box($html);
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
$tags = tag_get_tags_array('wiki_pages', $page->id);
|
||||
echo $OUTPUT->container_start('wiki-tags');
|
||||
echo '<span class="wiki-tags-title">'.get_string('tags').': </span>';
|
||||
$links = array();
|
||||
foreach ($tags as $tagid=>$tag) {
|
||||
$url = new moodle_url('/tag/index.php', array('tag'=>$tag));
|
||||
$links[] = html_writer::link($url, $tag, array('title'=>get_string('tagtitle', 'wiki', $tag)));
|
||||
}
|
||||
echo join($links, ", ");
|
||||
echo $OUTPUT->container_end();
|
||||
}
|
||||
echo $OUTPUT->tag_list(core_tag_tag::get_item_tags('mod_wiki', 'wiki_pages', $page->id),
|
||||
null, 'wiki-tags');
|
||||
|
||||
wiki_increment_pageviews($page);
|
||||
}
|
||||
|
||||
+3
-15
@@ -34,7 +34,6 @@
|
||||
*/
|
||||
|
||||
require_once($CFG->dirroot . '/mod/wiki/edit_form.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
/**
|
||||
* Class page_wiki contains the common code between all pages
|
||||
@@ -570,18 +569,9 @@ class page_wiki_edit extends page_wiki {
|
||||
$params['filearea'] = 'attachments';
|
||||
}
|
||||
|
||||
$data->tags = core_tag_tag::get_item_tags_array('mod_wiki', 'wiki_pages', $this->page->id);
|
||||
|
||||
$form = new mod_wiki_edit_form($url, $params);
|
||||
|
||||
if ($formdata = $form->get_data()) {
|
||||
if (!empty($CFG->usetags)) {
|
||||
$data->tags = $formdata->tags;
|
||||
}
|
||||
} else {
|
||||
if (!empty($CFG->usetags)) {
|
||||
$data->tags = tag_get_tags_array('wiki_pages', $this->page->id);
|
||||
}
|
||||
}
|
||||
|
||||
$form->set_data($data);
|
||||
$form->display();
|
||||
}
|
||||
@@ -2060,9 +2050,7 @@ class page_wiki_save extends page_wiki_edit {
|
||||
}
|
||||
|
||||
if ($save && $data) {
|
||||
if (!empty($CFG->usetags)) {
|
||||
tag_set('wiki_pages', $this->page->id, $data->tags, 'mod_wiki', $this->modcontext->id);
|
||||
}
|
||||
core_tag_tag::set_item_tags('mod_wiki', 'wiki_pages', $this->page->id, $this->modcontext, $data->tags);
|
||||
|
||||
$message = '<p>' . get_string('saving', 'wiki') . '</p>';
|
||||
|
||||
|
||||
@@ -128,10 +128,6 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.wiki-tags span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.wiki_modifieduser p {
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ Feature: Edited wiki pages handle tags correctly
|
||||
And I expand "Site administration" node
|
||||
And I expand "Appearance" node
|
||||
And I follow "Manage tags"
|
||||
And I follow "Default collection"
|
||||
And I set the field "otagsadd" to "OT1, OT2, OT3"
|
||||
And I press "Add official tags"
|
||||
And I log out
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111602; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2016011100; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version
|
||||
$plugin->component = 'mod_wiki'; // Full name of the plugin (used for diagnostics)
|
||||
$plugin->cron = 0;
|
||||
|
||||
+2
-3
@@ -425,9 +425,8 @@ class qformat_default {
|
||||
|
||||
$result = question_bank::get_qtype($question->qtype)->save_question_options($question);
|
||||
|
||||
if (!empty($CFG->usetags) && isset($question->tags)) {
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
tag_set('question', $question->id, $question->tags, 'core_question', $question->context->id);
|
||||
if (isset($question->tags)) {
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question->context, $question->id, $question->tags);
|
||||
}
|
||||
|
||||
if (!empty($result->error)) {
|
||||
|
||||
@@ -383,9 +383,9 @@ class qformat_xml extends qformat_default {
|
||||
public function import_question_tags($qo, $questionxml) {
|
||||
global $CFG;
|
||||
|
||||
if (!empty($CFG->usetags) && array_key_exists('tags', $questionxml['#'])
|
||||
if (core_tag_tag::is_enabled('core_question', 'question')
|
||||
&& array_key_exists('tags', $questionxml['#'])
|
||||
&& !empty($questionxml['#']['tags'][0]['#']['tag'])) {
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
$qo->tags = array();
|
||||
foreach ($questionxml['#']['tags'][0]['#']['tag'] as $tagdata) {
|
||||
$qo->tags[] = $this->getpath($tagdata, array('#', 'text', 0, '#'), '', true);
|
||||
@@ -1467,16 +1467,13 @@ class qformat_xml extends qformat_default {
|
||||
$expout .= $this->write_hints($question);
|
||||
|
||||
// Write the question tags.
|
||||
if (!empty($CFG->usetags)) {
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
$tags = tag_get_tags_array('question', $question->id);
|
||||
if (!empty($tags)) {
|
||||
$expout .= " <tags>\n";
|
||||
foreach ($tags as $tag) {
|
||||
$expout .= " <tag>" . $this->writetext($tag, 0, true) . "</tag>\n";
|
||||
}
|
||||
$expout .= " </tags>\n";
|
||||
$tags = core_tag_tag::get_item_tags_array('core_question', 'question', $question->id);
|
||||
if (!empty($tags)) {
|
||||
$expout .= " <tags>\n";
|
||||
foreach ($tags as $tag) {
|
||||
$expout .= " <tag>" . $this->writetext($tag, 0, true) . "</tag>\n";
|
||||
}
|
||||
$expout .= " </tags>\n";
|
||||
}
|
||||
|
||||
// Close the question tag.
|
||||
|
||||
@@ -29,7 +29,6 @@ global $CFG;
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/question/format/xml/format.php');
|
||||
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,11 +262,9 @@ if ($mform->is_cancelled()) {
|
||||
}
|
||||
}
|
||||
$question = $qtypeobj->save_question($question, $fromform);
|
||||
if (!empty($CFG->usetags) && isset($fromform->tags)) {
|
||||
// A wizardpage from multipe pages questiontype like calculated may not
|
||||
// allow editing the question tags, hence the isset($fromform->tags) test.
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
tag_set('question', $question->id, $fromform->tags, 'core_question', $contextid);
|
||||
if (isset($fromform->tags)) {
|
||||
core_tag_tag::set_item_tags('core_question', 'question', $question->id,
|
||||
context::instance_by_id($contextid), $fromform->tags);
|
||||
}
|
||||
|
||||
// Purge this question from the cache.
|
||||
|
||||
@@ -201,10 +201,11 @@ abstract class question_edit_form extends question_wizard_form {
|
||||
// Any questiontype specific fields.
|
||||
$this->definition_inner($mform);
|
||||
|
||||
if (!empty($CFG->usetags)) {
|
||||
if (core_tag_tag::is_enabled('core_question', 'question')) {
|
||||
$mform->addElement('header', 'tagsheader', get_string('tags'));
|
||||
$mform->addElement('tags', 'tags', get_string('tags'));
|
||||
}
|
||||
$mform->addElement('tags', 'tags', get_string('tags'),
|
||||
array('itemtype' => 'question', 'component' => 'core_question'));
|
||||
|
||||
if (!empty($this->question->id)) {
|
||||
$mform->addElement('header', 'createdmodifiedheader',
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class core_tag_area for managing tag areas
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class to manage tag areas
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_tag_area {
|
||||
|
||||
/**
|
||||
* Returns the list of areas indexed by itemtype and component
|
||||
*
|
||||
* @param int $tagcollid return only areas in this tag collection
|
||||
* @param bool $enabledonly return only enabled tag areas
|
||||
* @return array itemtype=>component=>tagarea object
|
||||
*/
|
||||
public static function get_areas($tagcollid = null, $enabledonly = false) {
|
||||
global $DB;
|
||||
$cache = cache::make('core', 'tags');
|
||||
if (($itemtypes = $cache->get('tag_area')) === false) {
|
||||
$colls = core_tag_collection::get_collections();
|
||||
$defaultcoll = reset($colls);
|
||||
$itemtypes = array();
|
||||
$areas = $DB->get_records('tag_area', array(), 'component,itemtype');
|
||||
foreach ($areas as $area) {
|
||||
if ($colls[$area->tagcollid]->component) {
|
||||
$area->locked = true;
|
||||
}
|
||||
$itemtypes[$area->itemtype][$area->component] = $area;
|
||||
}
|
||||
$cache->set('tag_area', $itemtypes);
|
||||
}
|
||||
if ($tagcollid || $enabledonly) {
|
||||
$rv = array();
|
||||
foreach ($itemtypes as $itemtype => $it) {
|
||||
foreach ($it as $component => $v) {
|
||||
if (($v->tagcollid == $tagcollid || !$tagcollid) && (!$enabledonly || $v->enabled)) {
|
||||
$rv[$itemtype][$component] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
return $itemtypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves info about one tag area
|
||||
*
|
||||
* @param int $tagareaid
|
||||
* @return stdClass
|
||||
*/
|
||||
public static function get_by_id($tagareaid) {
|
||||
$tagareas = self::get_areas();
|
||||
foreach ($tagareas as $itemtype => $it) {
|
||||
foreach ($it as $component => $v) {
|
||||
if ($v->id == $tagareaid) {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display name for this area
|
||||
*
|
||||
* @param string $component
|
||||
* @param string $itemtype
|
||||
* @return lang_string
|
||||
*/
|
||||
public static function display_name($component, $itemtype) {
|
||||
$identifier = 'tagarea_' . clean_param($itemtype, PARAM_STRINGID);
|
||||
if ($component === 'core') {
|
||||
$component = 'tag';
|
||||
}
|
||||
return new lang_string($identifier, $component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the tag area is enabled
|
||||
*
|
||||
* @param string $component component responsible for tagging
|
||||
* @param string $itemtype what is being tagged, for example, 'post', 'course', 'user', etc.
|
||||
* @return bool|null
|
||||
*/
|
||||
public static function is_enabled($component, $itemtype) {
|
||||
global $CFG;
|
||||
if (empty($CFG->usetags)) {
|
||||
return false;
|
||||
}
|
||||
$itemtypes = self::get_areas();
|
||||
if (isset($itemtypes[$itemtype][$component])) {
|
||||
return $itemtypes[$itemtype][$component]->enabled ? true : false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the tag collection that should be used for storing tags of this itemtype
|
||||
*
|
||||
* @param string $component component responsible for tagging
|
||||
* @param string $itemtype what is being tagged, for example, 'post', 'course', 'user', etc.
|
||||
* @return int
|
||||
*/
|
||||
public static function get_collection($component, $itemtype) {
|
||||
$itemtypes = self::get_areas();
|
||||
if (array_key_exists($itemtype, $itemtypes)) {
|
||||
if (!array_key_exists($component, $itemtypes[$itemtype])) {
|
||||
$component = key($itemtypes[$itemtype]);
|
||||
}
|
||||
return $itemtypes[$itemtype][$component]->tagcollid;
|
||||
}
|
||||
return core_tag_collection::get_default();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tag areas and collections that are currently cached in DB for this component
|
||||
*
|
||||
* @param string $componentname
|
||||
* @return array first element is the list of areas and the second list of collections
|
||||
*/
|
||||
protected static function get_definitions_for_component($componentname) {
|
||||
global $DB;
|
||||
list($a, $b) = core_component::normalize_component($componentname);
|
||||
$component = $b ? ($a . '_' . $b) : $a;
|
||||
$sql = 'component = :component';
|
||||
$params = array('component' => $component);
|
||||
if ($component === 'core') {
|
||||
$sql .= ' OR component LIKE :coreprefix';
|
||||
$params['coreprefix'] = 'core_%';
|
||||
}
|
||||
$fields = $DB->sql_concat_join("':'", array('itemtype', 'component'));
|
||||
$existingareas = $DB->get_records_sql(
|
||||
"SELECT $fields AS returnkey, a.* FROM {tag_area} a WHERE $sql", $params);
|
||||
$fields = $DB->sql_concat_join("':'", array('name', 'component'));
|
||||
$existingcolls = $DB->get_records_sql(
|
||||
"SELECT $fields AS returnkey, t.* FROM {tag_coll} t WHERE $sql", $params);
|
||||
return array($existingareas, $existingcolls);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely delete a tag area and all instances inside it
|
||||
*
|
||||
* @param stdClass $record
|
||||
*/
|
||||
protected static function delete($record) {
|
||||
global $DB;
|
||||
|
||||
core_tag_tag::delete_instances($record->component, $record->itemtype);
|
||||
|
||||
$DB->delete_records('tag_area',
|
||||
array('itemtype' => $record->itemtype,
|
||||
'component' => $record->component));
|
||||
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_area');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new tag area
|
||||
*
|
||||
* @param stdClass $record
|
||||
*/
|
||||
protected static function create($record) {
|
||||
global $DB;
|
||||
if (empty($record->tagcollid)) {
|
||||
$record->tagcollid = core_tag_collection::get_default();
|
||||
}
|
||||
$DB->insert_record('tag_area', array('component' => $record->component,
|
||||
'itemtype' => $record->itemtype,
|
||||
'tagcollid' => $record->tagcollid,
|
||||
'callback' => $record->callback,
|
||||
'callbackfile' => $record->callbackfile));
|
||||
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_area');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tag area
|
||||
*
|
||||
* @param stdClass $existing current record from DB table tag_area
|
||||
* @param array|stdClass $data fields that need updating
|
||||
*/
|
||||
public static function update($existing, $data) {
|
||||
global $DB;
|
||||
$data = array_intersect_key((array)$data,
|
||||
array('enabled' => 1, 'tagcollid' => 1,
|
||||
'callback' => 1, 'callbackfile' => 1));
|
||||
foreach ($data as $key => $value) {
|
||||
if ($existing->$key == $value) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
if (!$data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($data['tagcollid'])) {
|
||||
self::move_tags($existing->component, $existing->itemtype, $data['tagcollid']);
|
||||
}
|
||||
|
||||
$data['id'] = $existing->id;
|
||||
$DB->update_record('tag_area', $data);
|
||||
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_area');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the database to contain a list of tagged areas for a component.
|
||||
* The list of tagged areas is read from [plugindir]/db/tag.php
|
||||
*
|
||||
* @param string $componentname - The frankenstyle component name.
|
||||
*/
|
||||
public static function reset_definitions_for_component($componentname) {
|
||||
global $DB;
|
||||
$dir = core_component::get_component_directory($componentname);
|
||||
$file = $dir . '/db/tag.php';
|
||||
$tagareas = null;
|
||||
if (file_exists($file)) {
|
||||
require_once($file);
|
||||
}
|
||||
|
||||
list($a, $b) = core_component::normalize_component($componentname);
|
||||
$component = $b ? ($a . '_' . $b) : $a;
|
||||
|
||||
list($existingareas, $existingcolls) = self::get_definitions_for_component($componentname);
|
||||
|
||||
$itemtypes = array();
|
||||
$collections = array();
|
||||
$needcleanup = false;
|
||||
if ($tagareas) {
|
||||
foreach ($tagareas as $tagarea) {
|
||||
$record = (object)$tagarea;
|
||||
if ($component !== 'core' || empty($record->component)) {
|
||||
if (isset($record->component) && $record->component !== $component) {
|
||||
debugging("Item type {$record->itemtype} has illegal component {$record->component}", DEBUG_DEVELOPER);
|
||||
}
|
||||
$record->component = $component;
|
||||
}
|
||||
unset($record->tagcollid);
|
||||
if (!empty($record->collection)) {
|
||||
// Create collection if it does not exist, or update 'searchable' and/or 'customurl' if needed.
|
||||
$key = $record->collection . ':' . $record->component;
|
||||
$collectiondata = array_intersect_key((array)$record,
|
||||
array('component' => 1, 'searchable' => 1, 'customurl' => 1));
|
||||
$collectiondata['name'] = $record->collection;
|
||||
if (!array_key_exists($key, $existingcolls)) {
|
||||
$existingcolls[$key] = core_tag_collection::create($collectiondata);
|
||||
} else {
|
||||
core_tag_collection::update($existingcolls[$key], $collectiondata);
|
||||
}
|
||||
$record->tagcollid = $existingcolls[$key]->id;
|
||||
$collections[$key] = $existingcolls[$key];
|
||||
unset($record->collection);
|
||||
}
|
||||
unset($record->searchable);
|
||||
unset($record->customurl);
|
||||
if (!isset($record->callback)) {
|
||||
$record->callback = null;
|
||||
}
|
||||
if (!isset($record->callbackfile)) {
|
||||
$record->callbackfile = null;
|
||||
}
|
||||
$itemtypes[$record->itemtype . ':' . $record->component] = $record;
|
||||
}
|
||||
}
|
||||
$todeletearea = array_diff_key($existingareas, $itemtypes);
|
||||
$todeletecoll = array_diff_key($existingcolls, $collections);
|
||||
|
||||
// Delete tag areas that are no longer needed.
|
||||
foreach ($todeletearea as $key => $record) {
|
||||
self::delete($record);
|
||||
}
|
||||
|
||||
// Update tag areas if changed.
|
||||
$toupdatearea = array_intersect_key($existingareas, $itemtypes);
|
||||
foreach ($toupdatearea as $key => $tagarea) {
|
||||
if (!isset($itemtypes[$key]->tagcollid)) {
|
||||
foreach ($todeletecoll as $tagcoll) {
|
||||
if ($tagcoll->id == $tagarea->tagcollid) {
|
||||
$itemtypes[$key]->tagcollid = core_tag_collection::get_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
self::update($tagarea, $itemtypes[$key]);
|
||||
}
|
||||
|
||||
// Create new tag areas.
|
||||
$toaddarea = array_diff_key($itemtypes, $existingareas);
|
||||
foreach ($toaddarea as $record) {
|
||||
self::create($record);
|
||||
}
|
||||
|
||||
// Delete tag collections that are no longer needed.
|
||||
foreach ($todeletecoll as $key => $tagcoll) {
|
||||
core_tag_collection::delete($tagcoll);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all tag areas, collections and instances associated with the plugin.
|
||||
*
|
||||
* @param string $pluginname
|
||||
*/
|
||||
public static function uninstall($pluginname) {
|
||||
global $DB;
|
||||
|
||||
list($a, $b) = core_component::normalize_component($pluginname);
|
||||
if (empty($b) || $a === 'core') {
|
||||
throw new coding_exception('Core component can not be uninstalled');
|
||||
}
|
||||
$component = $a . '_' . $b;
|
||||
|
||||
core_tag_tag::delete_instances($component);
|
||||
|
||||
$DB->delete_records('tag_area', array('component' => $component));
|
||||
$DB->delete_records('tag_coll', array('component' => $component));
|
||||
cache::make('core', 'tags')->delete_many(array('tag_area', 'tag_coll'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves existing tags associated with an item type to another tag collection
|
||||
*
|
||||
* @param string $component
|
||||
* @param string $itemtype
|
||||
* @param int $tagcollid
|
||||
*/
|
||||
public static function move_tags($component, $itemtype, $tagcollid) {
|
||||
global $DB;
|
||||
$params = array('itemtype1' => $itemtype, 'component1' => $component,
|
||||
'itemtype2' => $itemtype, 'component2' => $component,
|
||||
'tagcollid1' => $tagcollid, 'tagcollid2' => $tagcollid);
|
||||
|
||||
// Find all collections that need to be cleaned later.
|
||||
$sql = "SELECT DISTINCT t.tagcollid " .
|
||||
"FROM {tag_instance} ti " .
|
||||
"JOIN {tag} t ON t.id = ti.tagid AND t.tagcollid <> :tagcollid1 " .
|
||||
"WHERE ti.itemtype = :itemtype2 AND ti.component = :component2 ";
|
||||
$cleanupcollections = $DB->get_fieldset_sql($sql, $params);
|
||||
|
||||
// Find all tags that are related to the tags being moved and make sure they are present in the target tagcoll.
|
||||
$sql = "SELECT DISTINCT r.name, r.rawname, r.description, r.descriptionformat, ".
|
||||
" r.userid, r.tagtype, r.flag ".
|
||||
"FROM {tag_instance} ti ". // Instances that need moving.
|
||||
"JOIN {tag} t ON t.id = ti.tagid AND t.tagcollid <> :tagcollid1 ". // Tags that need moving.
|
||||
"JOIN {tag_instance} tr ON tr.itemtype = 'tag' and tr.component = 'core' AND tr.itemid = t.id ".
|
||||
"JOIN {tag} r ON r.id = tr.tagid ". // Tags related to the tags that need moving.
|
||||
"LEFT JOIN {tag} re ON re.name = r.name AND re.tagcollid = :tagcollid2 ". // Existing tags in the target tagcoll with the same name as related tags.
|
||||
"WHERE ti.itemtype = :itemtype2 AND ti.component = :component2 ".
|
||||
" AND re.id IS NULL"; // We need related tags that ARE NOT present in the target tagcoll.
|
||||
$result = $DB->get_records_sql($sql, $params);
|
||||
foreach ($result as $tag) {
|
||||
$tag->tagcollid = $tagcollid;
|
||||
$tag->id = $DB->insert_record('tag', $tag);
|
||||
\core\event\tag_created::create_from_tag($tag);
|
||||
}
|
||||
|
||||
// Find all tags that need moving and have related tags, remember their related tags.
|
||||
$sql = "SELECT t.name AS tagname, r.rawname AS relatedtag ".
|
||||
"FROM {tag_instance} ti ". // Instances that need moving.
|
||||
"JOIN {tag} t ON t.id = ti.tagid AND t.tagcollid <> :tagcollid1 ". // Tags that need moving.
|
||||
"JOIN {tag_instance} tr ON t.id = tr.tagid AND tr.itemtype = 'tag' and tr.component = 'core' ".
|
||||
"JOIN {tag} r ON r.id = tr.itemid ". // Tags related to the tags that need moving.
|
||||
"WHERE ti.itemtype = :itemtype2 AND ti.component = :component2 ".
|
||||
"ORDER BY t.id, tr.ordering ";
|
||||
$relatedtags = array();
|
||||
$result = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($result as $record) {
|
||||
$relatedtags[$record->tagname][] = $record->relatedtag;
|
||||
}
|
||||
$result->close();
|
||||
|
||||
// Find all tags that are used for this itemtype/component and are not present in the target tag collection.
|
||||
$sql = "SELECT DISTINCT t.id, t.name, t.rawname, t.description, t.descriptionformat,
|
||||
t.userid, t.tagtype, t.flag
|
||||
FROM {tag_instance} ti
|
||||
JOIN {tag} t ON t.id = ti.tagid AND t.tagcollid <> :tagcollid1
|
||||
LEFT JOIN {tag} tt ON tt.name = t.name AND tt.tagcollid = :tagcollid2
|
||||
WHERE ti.itemtype = :itemtype2 AND ti.component = :component2
|
||||
AND tt.id IS NULL";
|
||||
$todelete = array();
|
||||
$result = $DB->get_records_sql($sql, $params);
|
||||
foreach ($result as $tag) {
|
||||
$originaltagid = $tag->id;
|
||||
unset($tag->id);
|
||||
$tag->tagcollid = $tagcollid;
|
||||
$tag->id = $DB->insert_record('tag', $tag);
|
||||
\core\event\tag_created::create_from_tag($tag);
|
||||
$DB->execute("UPDATE {tag_instance} SET tagid = ? WHERE tagid = ? AND itemtype = ? AND component = ?",
|
||||
array($tag->id, $originaltagid, $itemtype, $component));
|
||||
}
|
||||
|
||||
// Find all tags that are used for this itemtype/component and are already present in the target tag collection.
|
||||
$sql = "SELECT DISTINCT t.id, tt.id AS targettagid
|
||||
FROM {tag_instance} ti
|
||||
JOIN {tag} t ON t.id = ti.tagid AND t.tagcollid <> :tagcollid1
|
||||
JOIN {tag} tt ON tt.name = t.name AND tt.tagcollid = :tagcollid2
|
||||
WHERE ti.itemtype = :itemtype2 AND ti.component = :component2";
|
||||
$result = $DB->get_records_sql($sql, $params);
|
||||
foreach ($result as $tag) {
|
||||
$DB->execute("UPDATE {tag_instance} SET tagid = ? WHERE tagid = ? AND itemtype = ? AND component = ?",
|
||||
array($tag->targettagid, $tag->id, $itemtype, $component));
|
||||
}
|
||||
|
||||
// Add related tags to the moved tags.
|
||||
if ($relatedtags) {
|
||||
$tags = core_tag_tag::get_by_name_bulk($tagcollid, array_keys($relatedtags));
|
||||
foreach ($tags as $tag) {
|
||||
$tag->add_related_tags($relatedtags[$tag->name]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($cleanupcollections) {
|
||||
core_tag_collection::cleanup_unused_tags($cleanupcollections);
|
||||
}
|
||||
|
||||
// Reset caches.
|
||||
cache::make('core', 'tags')->delete('tag_area');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag_areas_table
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Table with the list of available tag areas for "Manage tags" page.
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_tag_areas_table extends html_table {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string|moodle_url $pageurl
|
||||
*/
|
||||
public function __construct($pageurl) {
|
||||
global $OUTPUT;
|
||||
parent::__construct();
|
||||
|
||||
$this->attributes['class'] = 'generaltable tag-areas-table';
|
||||
|
||||
$this->head = array(
|
||||
get_string('tagareaname', 'core_tag'),
|
||||
get_string('component', 'tag'),
|
||||
get_string('tagareaenabled', 'core_tag'),
|
||||
get_string('tagcollection', 'tag'),
|
||||
);
|
||||
|
||||
$this->data = array();
|
||||
$this->rowclasses = array();
|
||||
|
||||
$tagareas = core_tag_area::get_areas();
|
||||
$tagcollections = core_tag_collection::get_collections_menu(true);
|
||||
$tagcollectionsall = core_tag_collection::get_collections_menu();
|
||||
|
||||
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'));
|
||||
|
||||
$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];
|
||||
}
|
||||
$this->data[] = array(
|
||||
$areaname,
|
||||
($record->component === 'core' || preg_match('/^core_/', $record->component)) ?
|
||||
get_string('coresystem') : get_string('pluginname', $record->component),
|
||||
$enabled,
|
||||
$collectionselect
|
||||
);
|
||||
$this->rowclasses[] = $record->enabled ? '' : 'dimmed_text';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class to manage tag collections
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class to manage tag collections
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_tag_collection {
|
||||
|
||||
/** @var string used for function cloud_sort() */
|
||||
public static $cloudsortfield = 'name';
|
||||
|
||||
/**
|
||||
* Returns the list of tag collections defined in the system.
|
||||
*
|
||||
* @param bool $onlysearchable only return collections that can be searched.
|
||||
* @return array array of objects where each object has properties: id, name, isdefault, itemtypes, sortorder
|
||||
*/
|
||||
public static function get_collections($onlysearchable = false) {
|
||||
global $DB;
|
||||
$cache = cache::make('core', 'tags');
|
||||
if (($tagcolls = $cache->get('tag_coll')) === false) {
|
||||
// Retrieve records from DB and create a default one if it is not present.
|
||||
$tagcolls = $DB->get_records('tag_coll', null, 'isdefault DESC, sortorder, id');
|
||||
if (empty($tagcolls)) {
|
||||
// When this method is called for the first time it automatically creates the default tag collection.
|
||||
$DB->insert_record('tag_coll', array('isdefault' => 1, 'sortorder' => 0));
|
||||
$tagcolls = $DB->get_records('tag_coll');
|
||||
} else {
|
||||
// Make sure sortorder is correct.
|
||||
$idx = 0;
|
||||
foreach ($tagcolls as $id => $tagcoll) {
|
||||
if ($tagcoll->sortorder != $idx) {
|
||||
$DB->update_record('tag_coll', array('sortorder' => $idx, 'id' => $id));
|
||||
$tagcolls[$id]->sortorder = $idx;
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
}
|
||||
$cache->set('tag_coll', $tagcolls);
|
||||
}
|
||||
if ($onlysearchable) {
|
||||
$rv = array();
|
||||
foreach ($tagcolls as $id => $tagcoll) {
|
||||
if ($tagcoll->searchable) {
|
||||
$rv[$id] = $tagcoll;
|
||||
}
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
return $tagcolls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tag collection object
|
||||
*
|
||||
* @param int $tagcollid
|
||||
* @return stdClass
|
||||
*/
|
||||
public static function get_by_id($tagcollid) {
|
||||
$tagcolls = self::get_collections();
|
||||
if (array_key_exists($tagcollid, $tagcolls)) {
|
||||
return $tagcolls[$tagcollid];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of existing tag collections as id=>name
|
||||
*
|
||||
* @param bool $unlockedonly
|
||||
* @param bool $onlysearchable
|
||||
* @param string $selectalllabel
|
||||
* @return array
|
||||
*/
|
||||
public static function get_collections_menu($unlockedonly = false, $onlysearchable = false,
|
||||
$selectalllabel = null) {
|
||||
$tagcolls = self::get_collections($onlysearchable);
|
||||
$options = array();
|
||||
foreach ($tagcolls as $id => $tagcoll) {
|
||||
if (!$unlockedonly || empty($tagcoll->component)) {
|
||||
$options[$id] = self::display_name($tagcoll);
|
||||
}
|
||||
}
|
||||
if (count($options) > 1 && $selectalllabel) {
|
||||
$options = array(0 => $selectalllabel) + $options;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns id of the default tag collection
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_default() {
|
||||
$collections = self::get_collections();
|
||||
$keys = array_keys($collections);
|
||||
return $keys[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatted name of the tag collection
|
||||
*
|
||||
* @param stdClass $record record from DB table tag_coll
|
||||
* @return string
|
||||
*/
|
||||
public static function display_name($record) {
|
||||
$syscontext = context_system::instance();
|
||||
if (!empty($record->component)) {
|
||||
$identifier = 'tagcollection_' .
|
||||
clean_param($record->name, PARAM_STRINGID);
|
||||
$component = $record->component;
|
||||
if ($component === 'core') {
|
||||
$component = 'tag';
|
||||
}
|
||||
return get_string($identifier, $component);
|
||||
}
|
||||
if (!empty($record->name)) {
|
||||
return format_string($record->name, true, $syscontext);
|
||||
} else if ($record->isdefault) {
|
||||
return get_string('defautltagcoll', 'tag');
|
||||
} else {
|
||||
return $record->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tag areas in the given tag collection
|
||||
*
|
||||
* @param int $tagcollid
|
||||
* @return array
|
||||
*/
|
||||
public static function get_areas($tagcollid) {
|
||||
$allitemtypes = core_tag_area::get_areas($tagcollid, true);
|
||||
$itemtypes = array();
|
||||
foreach ($allitemtypes as $itemtype => $it) {
|
||||
foreach ($it as $component => $v) {
|
||||
$itemtypes[$v->id] = $v;
|
||||
}
|
||||
}
|
||||
return $itemtypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of names of areas (enabled only) that are in this collection.
|
||||
*
|
||||
* @param int $tagcollid
|
||||
* @return array
|
||||
*/
|
||||
public static function get_areas_names($tagcollid) {
|
||||
$allitemtypes = core_tag_area::get_areas($tagcollid, true);
|
||||
$itemtypes = array();
|
||||
foreach ($allitemtypes as $itemtype => $it) {
|
||||
foreach ($it as $component => $v) {
|
||||
$itemtypes[] = core_tag_area::display_name($component, $itemtype);
|
||||
}
|
||||
}
|
||||
return $itemtypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tag collection
|
||||
*
|
||||
* @param stdClass $data data from form core_tag_collection_form
|
||||
* @return int|false id of created tag collection or false if failed
|
||||
*/
|
||||
public static function create($data) {
|
||||
global $DB;
|
||||
$data = (object)$data;
|
||||
$tagcolls = self::get_collections();
|
||||
$tagcoll = (object)array(
|
||||
'name' => $data->name,
|
||||
'isdefault' => 0,
|
||||
'component' => !empty($data->component) ? $data->component : null,
|
||||
'sortorder' => count($tagcolls),
|
||||
'searchable' => isset($data->searchable) ? (int)(bool)$data->searchable : 1,
|
||||
'customurl' => !empty($data->customurl) ? $data->customurl : null,
|
||||
);
|
||||
$tagcoll->id = $DB->insert_record('tag_coll', $tagcoll);
|
||||
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_coll');
|
||||
|
||||
\core\event\tag_collection_created::create_from_record($tagcoll)->trigger();
|
||||
return $tagcoll;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return bool wether the record was updated
|
||||
*/
|
||||
public static function update($tagcoll, $data) {
|
||||
global $DB;
|
||||
$defaulttagcollid = self::get_default();
|
||||
$allowedfields = array('name', 'searchable', 'customurl');
|
||||
if ($tagcoll->id == $defaulttagcollid) {
|
||||
$allowedfields = array('name');
|
||||
}
|
||||
|
||||
$updatedata = array();
|
||||
$data = (array)$data;
|
||||
foreach ($allowedfields as $key) {
|
||||
if (array_key_exists($key, $data) && $data[$key] !== $tagcoll->$key) {
|
||||
$updatedata[$key] = $data[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$updatedata) {
|
||||
// Nothing to update.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($updatedata['searchable'])) {
|
||||
$updatedata['searchable'] = (int)(bool)$updatedata['searchable'];
|
||||
}
|
||||
foreach ($updatedata as $key => $value) {
|
||||
$tagcoll->$key = $value;
|
||||
}
|
||||
$updatedata['id'] = $tagcoll->id;
|
||||
$DB->update_record('tag_coll', $updatedata);
|
||||
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_coll');
|
||||
|
||||
\core\event\tag_collection_updated::create_from_record($tagcoll)->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a custom tag collection
|
||||
*
|
||||
* @param stdClass $tagcoll existing record in DB table tag_coll
|
||||
* @return bool wether the tag collection was deleted
|
||||
*/
|
||||
public static function delete($tagcoll) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$defaulttagcollid = self::get_default();
|
||||
if ($tagcoll->id == $defaulttagcollid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move all tags from this tag collection to the default one.
|
||||
$allitemtypes = core_tag_area::get_areas($tagcoll->id);
|
||||
foreach ($allitemtypes as $it) {
|
||||
foreach ($it as $v) {
|
||||
core_tag_area::update($v, array('tagcollid' => $defaulttagcollid));
|
||||
}
|
||||
}
|
||||
|
||||
// Delete tags from this tag_coll.
|
||||
core_tag_tag::delete_tags($DB->get_fieldset_select('tag', 'id', 'tagcollid = ?', array($tagcoll->id)));
|
||||
|
||||
// Delete the tag collection.
|
||||
$DB->delete_records('tag_coll', array('id' => $tagcoll->id));
|
||||
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_coll');
|
||||
|
||||
\core\event\tag_collection_deleted::create_from_record($tagcoll)->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the tag collection in the list one position up or down
|
||||
*
|
||||
* @param stdClass $tagcoll existing record in DB table tag_coll
|
||||
* @param int $direction move direction: +1 or -1
|
||||
* @return bool
|
||||
*/
|
||||
public static function change_sortorder($tagcoll, $direction) {
|
||||
global $DB;
|
||||
if ($direction != -1 && $direction != 1) {
|
||||
throw coding_exception('Second argument in tag_coll_change_sortorder() can be only 1 or -1');
|
||||
}
|
||||
$tagcolls = self::get_collections();
|
||||
$keys = array_keys($tagcolls);
|
||||
$idx = array_search($tagcoll->id, $keys);
|
||||
if ($idx === false || $idx == 0 || $idx + $direction < 1 || $idx + $direction >= count($tagcolls)) {
|
||||
return false;
|
||||
}
|
||||
$otherid = $keys[$idx + $direction];
|
||||
$DB->update_record('tag_coll', array('id' => $tagcoll->id, 'sortorder' => $idx + $direction));
|
||||
$DB->update_record('tag_coll', array('id' => $otherid, 'sortorder' => $idx));
|
||||
// Reset cache.
|
||||
cache::make('core', 'tags')->delete('tag_coll');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently deletes all non-official tags that no longer have any instances pointing to them
|
||||
*
|
||||
* @param array $collections optional list of tag collections ids to cleanup
|
||||
*/
|
||||
public static function cleanup_unused_tags($collections = null) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$params = array();
|
||||
$sql = "SELECT tg.id FROM {tag} tg LEFT OUTER JOIN {tag_instance} ti ON ti.tagid = tg.id
|
||||
WHERE ti.id IS NULL AND tg.tagtype = 'default'";
|
||||
if ($collections) {
|
||||
list($sqlcoll, $params) = $DB->get_in_or_equal($collections);
|
||||
$sql .= " AND tg.tagcollid " . $sqlcoll;
|
||||
}
|
||||
if ($unusedtags = $DB->get_fieldset_sql($sql, $params)) {
|
||||
core_tag_tag::delete_tags($unusedtags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of tags with number of items tagged
|
||||
*
|
||||
* @param int $tagcollid
|
||||
* @param string $tagtype possible values 'official', 'default' or empty for any tag type
|
||||
* @param int $limit maximum number of tags to retrieve, tags are sorted by the instance count
|
||||
* descending here regardless of $sort parameter
|
||||
* @param string $sort sort order for display, default 'name' - tags will be sorted after they are retrieved
|
||||
* @param string $search search string
|
||||
* @param int $fromctx context id where this tag cloud is displayed
|
||||
* @param int $ctx only retrieve tag instances in this context
|
||||
* @param int $rec retrieve tag instances in the $ctx context and it's children (default 1)
|
||||
* @return \core_tag\output\tagcloud
|
||||
*/
|
||||
public static function get_tag_cloud($tagcollid, $tagtype = '', $limit = 150, $sort = 'name',
|
||||
$search = '', $fromctx = 0, $ctx = 0, $rec = 1) {
|
||||
global $DB;
|
||||
|
||||
$fromclause = 'FROM {tag_instance} ti JOIN {tag} tg ON tg.id = ti.tagid';
|
||||
$whereclause = 'WHERE ti.itemtype <> \'tag\'';
|
||||
list($sql, $params) = $DB->get_in_or_equal($tagcollid ? array($tagcollid) :
|
||||
array_keys(self::get_collections(true)));
|
||||
$whereclause .= ' AND tg.tagcollid ' . $sql;
|
||||
if (!empty($tagtype)) {
|
||||
$whereclause .= ' AND tg.tagtype = ?';
|
||||
$params[] = $tagtype;
|
||||
}
|
||||
$context = $ctx ? context::instance_by_id($ctx) : context_system::instance();
|
||||
if ($rec && $context->contextlevel != CONTEXT_SYSTEM) {
|
||||
$fromclause .= ' JOIN {context} ctx ON ctx.id = ti.contextid ';
|
||||
$whereclause .= ' AND ctx.path LIKE ?';
|
||||
$params[] = $context->path . '%';
|
||||
} else if (!$rec) {
|
||||
$whereclause .= ' AND ti.contextid = ?';
|
||||
$params[] = $context->id;
|
||||
}
|
||||
if (strval($search) !== '') {
|
||||
$whereclause .= ' AND tg.name LIKE ?';
|
||||
$params[] = '%' . core_text::strtolower($search) . '%';
|
||||
}
|
||||
$tagsincloud = $DB->get_records_sql(
|
||||
"SELECT tg.id, tg.rawname, tg.name, tg.tagtype, COUNT(ti.id) AS count, tg.flag, tg.tagcollid
|
||||
$fromclause
|
||||
$whereclause
|
||||
GROUP BY tg.id, tg.rawname, tg.name, tg.flag, tg.tagtype, tg.tagcollid
|
||||
ORDER BY count DESC, tg.name ASC",
|
||||
$params, 0, $limit);
|
||||
|
||||
$tagscount = count($tagsincloud);
|
||||
if ($tagscount == $limit) {
|
||||
$tagscount = $DB->get_field_sql("SELECT COUNT(DISTINCT tg.id) $fromclause $whereclause", $params);
|
||||
}
|
||||
|
||||
self::$cloudsortfield = $sort;
|
||||
usort($tagsincloud, "self::cloud_sort");
|
||||
|
||||
return new core_tag\output\tagcloud($tagsincloud, $tagscount, $fromctx, $ctx, $rec);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to sort the tags in the cloud.
|
||||
*
|
||||
* @param string $a Tag name to compare against $b
|
||||
* @param string $b Tag name to compare against $a
|
||||
* @return int The result of the comparison/validation 1, 0 or -1
|
||||
*/
|
||||
public static function cloud_sort($a, $b) {
|
||||
$tagsort = self::$cloudsortfield ?: 'name';
|
||||
|
||||
if (is_numeric($a->$tagsort)) {
|
||||
return ($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort) ? 1 : -1;
|
||||
} else if (is_string($a->$tagsort)) {
|
||||
return strcmp($a->$tagsort, $b->$tagsort);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag_collections_table
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Table with the list of tag collections for "Manage tags" page.
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_tag_collections_table extends html_table {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param string|moodle_url $pageurl
|
||||
*/
|
||||
public function __construct($pageurl) {
|
||||
global $OUTPUT;
|
||||
parent::__construct();
|
||||
|
||||
$this->attributes['class'] = 'generaltable tag-collections-table';
|
||||
|
||||
$this->head = array(
|
||||
get_string('name'),
|
||||
get_string('component', 'tag'),
|
||||
get_string('tagareas', 'tag'),
|
||||
get_string('searchable', 'tag') . $OUTPUT->help_icon('searchable', 'tag'),
|
||||
''
|
||||
);
|
||||
|
||||
$this->data = array();
|
||||
|
||||
$tagcolls = core_tag_collection::get_collections();
|
||||
$idx = 0;
|
||||
foreach ($tagcolls as $tagcoll) {
|
||||
$actions = '';
|
||||
$name = core_tag_collection::display_name($tagcoll);
|
||||
$url = new moodle_url($pageurl, array('sesskey' => sesskey(), 'tc' => $tagcoll->id));
|
||||
if (!$tagcoll->isdefault) {
|
||||
// Move up.
|
||||
if ($idx > 1) {
|
||||
$url->param('action', 'collmoveup');
|
||||
$actions .= $OUTPUT->action_icon($url, new pix_icon('t/up', get_string('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')));
|
||||
}
|
||||
}
|
||||
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')));
|
||||
}
|
||||
$manageurl = new moodle_url('/tag/manage.php', array('tc' => $tagcoll->id));
|
||||
$component = '';
|
||||
if ($tagcoll->component) {
|
||||
$component = ($tagcoll->component === 'core' || preg_match('/^core_/', $tagcoll->component)) ?
|
||||
get_string('coresystem') : get_string('pluginname', $tagcoll->component);
|
||||
}
|
||||
$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++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+91
-22
@@ -66,7 +66,6 @@ class core_tag_external extends external_api {
|
||||
*/
|
||||
public static function update_tags($tags) {
|
||||
global $CFG, $PAGE, $DB;
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
// Validate and normalize parameters.
|
||||
$tags = self::validate_parameters(self::update_tags_parameters(), array('tags' => $tags));
|
||||
@@ -87,8 +86,6 @@ class core_tag_external extends external_api {
|
||||
$tag['rawname'] = clean_param($tag['rawname'], PARAM_TAG);
|
||||
if (empty($tag['rawname'])) {
|
||||
unset($tag['rawname']);
|
||||
} else {
|
||||
$tag['name'] = core_text::strtolower($tag['rawname']);
|
||||
}
|
||||
}
|
||||
if (!$canmanage) {
|
||||
@@ -109,7 +106,7 @@ class core_tag_external extends external_api {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (!$tagobject = $DB->get_record('tag', array('id' => $tag['id']))) {
|
||||
if (!$tagobject = core_tag_tag::get($tag['id'], '*')) {
|
||||
$warnings[] = array(
|
||||
'item' => $tag['id'],
|
||||
'warningcode' => 'tagnotfound',
|
||||
@@ -118,7 +115,7 @@ class core_tag_external extends external_api {
|
||||
continue;
|
||||
}
|
||||
// First check if new tag name is allowed.
|
||||
if (!empty($tag['name']) && ($existing = $DB->get_record('tag', array('name' => $tag['name']), 'id'))) {
|
||||
if (!empty($tag['rawname']) && ($existing = core_tag_tag::get_by_name($tagobject->tagcollid, $tag['rawname']))) {
|
||||
if ($existing->id != $tag['id']) {
|
||||
$warnings[] = array(
|
||||
'item' => $tag['id'],
|
||||
@@ -132,23 +129,18 @@ class core_tag_external extends external_api {
|
||||
$tag['tagtype'] = $tag['official'] ? 'official' : 'default';
|
||||
unset($tag['official']);
|
||||
}
|
||||
$tag['timemodified'] = time();
|
||||
$DB->update_record('tag', $tag);
|
||||
|
||||
foreach ($tag as $key => $value) {
|
||||
$tagobject->$key = $value;
|
||||
if (isset($tag['flag'])) {
|
||||
if ($tag['flag']) {
|
||||
$tagobject->flag();
|
||||
} else {
|
||||
$tagobject->reset_flag();
|
||||
}
|
||||
unset($tag['flag']);
|
||||
}
|
||||
unset($tag['id']);
|
||||
if (count($tag)) {
|
||||
$tagobject->update($tag);
|
||||
}
|
||||
|
||||
$event = \core\event\tag_updated::create(array(
|
||||
'objectid' => $tagobject->id,
|
||||
'relateduserid' => $tagobject->userid,
|
||||
'context' => context_system::instance(),
|
||||
'other' => array(
|
||||
'name' => $tagobject->name,
|
||||
'rawname' => $tagobject->rawname
|
||||
)
|
||||
));
|
||||
$event->trigger();
|
||||
}
|
||||
return array('warnings' => $warnings);
|
||||
}
|
||||
@@ -192,7 +184,6 @@ class core_tag_external extends external_api {
|
||||
*/
|
||||
public static function get_tags($tags) {
|
||||
global $CFG, $PAGE, $DB;
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
|
||||
// Validate and normalize parameters.
|
||||
$tags = self::validate_parameters(self::get_tags_parameters(), array('tags' => $tags));
|
||||
@@ -248,6 +239,7 @@ class core_tag_external extends external_api {
|
||||
'tags' => new external_multiple_structure( new external_single_structure(
|
||||
array(
|
||||
'id' => new external_value(PARAM_INT, 'tag id'),
|
||||
'tagcollid' => new external_value(PARAM_INT, 'tag collection id'),
|
||||
'name' => new external_value(PARAM_TAG, 'name'),
|
||||
'rawname' => new external_value(PARAM_RAW, 'tag raw name (may contain capital letters)'),
|
||||
'description' => new external_value(PARAM_RAW, 'tag description'),
|
||||
@@ -263,4 +255,81 @@ class core_tag_external extends external_api {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for function get_tagindex()
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function get_tagindex_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'tagindex' => new external_single_structure(array(
|
||||
'tag' => new external_value(PARAM_TAG, 'tag name'),
|
||||
'tc' => new external_value(PARAM_INT, 'tag collection id'),
|
||||
'ta' => new external_value(PARAM_INT, 'tag area id'),
|
||||
'excl' => new external_value(PARAM_BOOL, 'exlusive mode for this tag area', VALUE_OPTIONAL, 0),
|
||||
'from' => new external_value(PARAM_INT, 'context id where the link was displayed', VALUE_OPTIONAL, 0),
|
||||
'ctx' => new external_value(PARAM_INT, 'context id where to search for items', VALUE_OPTIONAL, 0),
|
||||
'rec' => new external_value(PARAM_INT, 'search in the context recursive', VALUE_OPTIONAL, 1),
|
||||
'page' => new external_value(PARAM_INT, 'page number (0-based)', VALUE_OPTIONAL, 0),
|
||||
), 'parameters')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags by their ids
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public static function get_tagindex($params) {
|
||||
global $PAGE;
|
||||
// Validate and normalize parameters.
|
||||
$tagindex = self::validate_parameters(
|
||||
self::get_tagindex_parameters(), array('tagindex' => $params));
|
||||
$params = $tagindex['tagindex'] + array(
|
||||
'excl' => 0,
|
||||
'from' => 0,
|
||||
'ctx' => 0,
|
||||
'rec' => 1,
|
||||
'page' => 0
|
||||
);
|
||||
|
||||
// Login to the course / module if applicable.
|
||||
$context = $params['ctx'] ? context::instance_by_id($params['ctx']) : context_system::instance();
|
||||
require_login(null, false, null, false, true);
|
||||
self::validate_context($context);
|
||||
|
||||
$tag = core_tag_tag::get_by_name($params['tc'], $params['tag'], '*', MUST_EXIST);
|
||||
$tagareas = core_tag_collection::get_areas($params['tc']);
|
||||
$tagindex = $tag->get_tag_index($tagareas[$params['ta']], $params['excl'], $params['from'],
|
||||
$params['ctx'], $params['rec'], $params['page']);
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
return $tagindex->export_for_template($renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return structure for get_tag()
|
||||
*
|
||||
* @return external_description
|
||||
*/
|
||||
public static function get_tagindex_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'tagid' => new external_value(PARAM_INT, 'tag id'),
|
||||
'ta' => new external_value(PARAM_INT, 'tag area id'),
|
||||
'component' => new external_value(PARAM_COMPONENT, 'component'),
|
||||
'itemtype' => new external_value(PARAM_NOTAGS, 'itemtype'),
|
||||
'nextpageurl' => new external_value(PARAM_URL, 'URL for the next page', VALUE_OPTIONAL),
|
||||
'prevpageurl' => new external_value(PARAM_URL, 'URL for the next page', VALUE_OPTIONAL),
|
||||
'exclusiveurl' => new external_value(PARAM_URL, 'URL for exclusive link', VALUE_OPTIONAL),
|
||||
'exclusivetext' => new external_value(PARAM_TEXT, 'text for exclusive link', VALUE_OPTIONAL),
|
||||
'title' => new external_value(PARAM_RAW, 'title'),
|
||||
'content' => new external_value(PARAM_RAW, 'title'),
|
||||
'hascontent' => new external_value(PARAM_INT, 'whether the content is present'),
|
||||
'anchor' => new external_value(PARAM_TEXT, 'name of anchor', VALUE_OPTIONAL),
|
||||
), 'tag index'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,16 +38,24 @@ class core_tag_manage_table extends table_sql {
|
||||
/** @var int stores the total number of found tags */
|
||||
public $totalcount = null;
|
||||
|
||||
/** @var int */
|
||||
protected $tagcollid;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $tagcollid
|
||||
*/
|
||||
public function __construct() {
|
||||
public function __construct($tagcollid) {
|
||||
global $USER, $CFG, $PAGE;
|
||||
parent::__construct('tag-management-list-'.$USER->id);
|
||||
|
||||
$this->tagcollid = $tagcollid;
|
||||
|
||||
$perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$baseurl = new moodle_url('/tag/manage.php', array('perpage' => $perpage, 'page' => $page));
|
||||
$baseurl = new moodle_url('/tag/manage.php', array('tc' => $tagcollid,
|
||||
'perpage' => $perpage, 'page' => $page));
|
||||
|
||||
$tablecolumns = array('select', 'name', 'fullname', 'count', 'flag', 'timemodified', 'tagtype', 'controls');
|
||||
$tableheaders = array(get_string('select', 'tag'),
|
||||
@@ -80,8 +88,10 @@ class core_tag_manage_table extends table_sql {
|
||||
$this->set_attribute('id', 'tag-management-list');
|
||||
$this->set_attribute('class', 'admintable generaltable tag-management-table');
|
||||
|
||||
$totalcount = "SELECT COUNT(id) FROM {tag}";
|
||||
$params = array();
|
||||
$totalcount = "SELECT COUNT(id)
|
||||
FROM {tag}
|
||||
WHERE tagcollid = :tagcollid";
|
||||
$params = array('tagcollid' => $this->tagcollid);
|
||||
|
||||
$this->set_count_sql($totalcount, $params);
|
||||
|
||||
@@ -135,13 +145,13 @@ class core_tag_manage_table extends table_sql {
|
||||
$sql = "
|
||||
SELECT tg.id, tg.name, tg.rawname, tg.tagtype, tg.flag, tg.timemodified,
|
||||
u.id AS owner, $allusernames,
|
||||
COUNT(ti.id) AS count
|
||||
COUNT(ti.id) AS count, tg.tagcollid
|
||||
FROM {tag} tg
|
||||
LEFT JOIN {tag_instance} ti ON ti.tagid = tg.id
|
||||
LEFT JOIN {user} u ON u.id = tg.userid
|
||||
WHERE 1 = 1 $where
|
||||
WHERE tagcollid = :tagcollid $where
|
||||
GROUP BY tg.id, tg.name, tg.rawname, tg.tagtype, tg.flag, tg.timemodified,
|
||||
u.id, $allusernames
|
||||
u.id, $allusernames, tg.tagcollid
|
||||
ORDER BY $sort";
|
||||
|
||||
if (!$this->is_downloading()) {
|
||||
|
||||
@@ -39,15 +39,19 @@ use moodle_url;
|
||||
*/
|
||||
class tag implements renderable, templatable {
|
||||
|
||||
/** @var stdClass */
|
||||
/** @var \core_tag_tag|stdClass */
|
||||
protected $record;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param stdClass $tag
|
||||
* @param \core_tag_tag|stdClass $tag
|
||||
*/
|
||||
public function __construct($tag) {
|
||||
if ($tag instanceof \core_tag_tag) {
|
||||
$this->record = $tag;
|
||||
return;
|
||||
}
|
||||
$tag = (array)$tag +
|
||||
array(
|
||||
'name' => '',
|
||||
@@ -56,7 +60,8 @@ class tag implements renderable, templatable {
|
||||
'descriptionformat' => FORMAT_HTML,
|
||||
'flag' => 0,
|
||||
'tagtype' => 'default',
|
||||
'id' => 0
|
||||
'id' => 0,
|
||||
'tagcollid' => 0,
|
||||
);
|
||||
$this->record = (object)$tag;
|
||||
}
|
||||
@@ -73,6 +78,7 @@ class tag implements renderable, templatable {
|
||||
|
||||
$r = new stdClass();
|
||||
$r->id = (int)$this->record->id;
|
||||
$r->tagcollid = clean_param($this->record->tagcollid, PARAM_INT);
|
||||
$r->rawname = clean_param($this->record->rawname, PARAM_TAG);
|
||||
$r->name = clean_param($this->record->name, PARAM_TAG);
|
||||
$format = clean_param($this->record->descriptionformat, PARAM_INT);
|
||||
@@ -85,7 +91,7 @@ class tag implements renderable, templatable {
|
||||
$r->official = ($this->record->tagtype === 'official') ? 1 : 0;
|
||||
}
|
||||
|
||||
$url = new moodle_url('/tag/index.php', array('id' => $this->record->id));
|
||||
$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(),
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag\output\tagindex
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_tag\output;
|
||||
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use moodle_url;
|
||||
use core_tag_tag;
|
||||
|
||||
/**
|
||||
* Class to display a tag cloud - set of tags where each has a weight.
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tagcloud implements templatable {
|
||||
|
||||
/** @var array */
|
||||
protected $tagset;
|
||||
|
||||
/** @var int */
|
||||
protected $totalcount;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $tagset array of core_tag or stdClass elements, each of them must have attributes:
|
||||
* name, rawname, tagcollid
|
||||
* preferrably also have attributes:
|
||||
* tagtype, count, flag
|
||||
* @param int $totalcount total count of tags (for example to indicate that there are more tags than the count of tagset)
|
||||
* leave 0 if count of tagset is the actual count of tags
|
||||
* @param int $fromctx context id where this tag cloud is displayed
|
||||
* @param int $ctx context id for tag view link
|
||||
* @param int $rec recursive argument for tag view link
|
||||
*/
|
||||
public function __construct($tagset, $totalcount = 0, $fromctx = 0, $ctx = 0, $rec = 1) {
|
||||
$canmanagetags = has_capability('moodle/tag:manage', \context_system::instance());
|
||||
|
||||
$maxcount = 1;
|
||||
foreach ($tagset as $tag) {
|
||||
if (isset($tag->count) && $tag->count > $maxcount) {
|
||||
$maxcount = $tag->count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->tagset = array();
|
||||
foreach ($tagset as $idx => $tag) {
|
||||
$this->tagset[$idx] = new stdClass();
|
||||
|
||||
$this->tagset[$idx]->name = core_tag_tag::make_display_name($tag, false);
|
||||
|
||||
if ($canmanagetags && !empty($tag->flag)) {
|
||||
$this->tagset[$idx]->flag = 1;
|
||||
}
|
||||
|
||||
$viewurl = core_tag_tag::make_url($tag->tagcollid, $tag->rawname, 0, $fromctx, $ctx, $rec);
|
||||
$this->tagset[$idx]->viewurl = $viewurl->out(false);
|
||||
|
||||
if (!empty($tag->tagtype)) {
|
||||
$this->tagset[$idx]->tagtype = $tag->tagtype;
|
||||
}
|
||||
|
||||
if (!empty($tag->count)) {
|
||||
$this->tagset[$idx]->count = $tag->count;
|
||||
$this->tagset[$idx]->size = (int)($tag->count / $maxcount * 20);
|
||||
}
|
||||
}
|
||||
|
||||
$this->totalcount = $totalcount ? $totalcount : count($this->tagset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of tags in the cloud
|
||||
* @return int
|
||||
*/
|
||||
public function get_count() {
|
||||
return count($this->tagset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$cnt = count($this->tagset);
|
||||
return (object)array(
|
||||
'tags' => $this->tagset,
|
||||
'tagscount' => $cnt,
|
||||
'totalcount' => $this->totalcount,
|
||||
'overflow' => ($this->totalcount > $cnt) ? 1 : 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag\output\tagfeed
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_tag\output;
|
||||
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to display feed of tagged items
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tagfeed implements templatable {
|
||||
|
||||
/** @var array */
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Usually the most convenient way is to call constructor without arguments and
|
||||
* add items later using add() method.
|
||||
*
|
||||
* @param array $items
|
||||
*/
|
||||
public function __construct($items = array()) {
|
||||
$this->items = array();
|
||||
if ($items) {
|
||||
foreach ($items as $item) {
|
||||
$item = (array)$item + array('img' => '', 'heading' => '', 'details' => '');
|
||||
$this->add($item['img'], $item['heading'], $item['details']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one item to the tagfeed
|
||||
*
|
||||
* @param string $img HTML code representing image (or image wrapped in a link), note that
|
||||
* core_tag/tagfeed template expects image to be 35x35 px
|
||||
* @param string $heading HTML for item heading
|
||||
* @param string $details HTML for item details (keep short)
|
||||
*/
|
||||
public function add($img, $heading, $details = '') {
|
||||
$this->items[] = array('img' => $img, 'heading' => $heading, 'details' => $details);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return array('items' => $this->items);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag\output\tagindex
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_tag\output;
|
||||
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use moodle_url;
|
||||
use core_tag_tag;
|
||||
|
||||
/**
|
||||
* Class to display items tagged with a specific tag
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tagindex implements templatable {
|
||||
|
||||
/** @var core_tag_tag|stdClass */
|
||||
protected $tag;
|
||||
|
||||
/** @var stdClass */
|
||||
protected $tagarea;
|
||||
|
||||
/** @var stdClass */
|
||||
protected $record;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param core_tag_tag|stdClass $tag
|
||||
* @param string $component
|
||||
* @param string $itemtype
|
||||
* @param string $content
|
||||
* @param bool $exclusivemode
|
||||
* @param int $fromctx context id where the link was displayed, may be used by callbacks
|
||||
* to display items in the same context first
|
||||
* @param int $ctx context id where we need to search for items
|
||||
* @param int $rec search items in sub contexts as well
|
||||
* @param int $page
|
||||
* @param bool $totalpages
|
||||
*/
|
||||
public function __construct($tag, $component, $itemtype, $content,
|
||||
$exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0, $totalpages = 1) {
|
||||
$this->record = new stdClass();
|
||||
$this->tag = $tag;
|
||||
|
||||
$tagareas = \core_tag_area::get_areas();
|
||||
if (!isset($tagareas[$itemtype][$component])) {
|
||||
throw new \coding_exception('Tag area for component '.$component.' and itemtype '.$itemtype.' is not defined');
|
||||
}
|
||||
$this->tagarea = $tagareas[$itemtype][$component];
|
||||
$this->record->tagid = $tag->id;
|
||||
$this->record->ta = $this->tagarea->id;
|
||||
$this->record->itemtype = $itemtype;
|
||||
$this->record->component = $component;
|
||||
|
||||
$a = (object)array(
|
||||
'tagarea' => \core_tag_area::display_name($component, $itemtype),
|
||||
'tag' => \core_tag_tag::make_display_name($tag)
|
||||
);
|
||||
if ($exclusivemode) {
|
||||
$this->record->title = get_string('itemstaggedwith', 'tag', $a);
|
||||
} else {
|
||||
$this->record->title = (string)$a->tagarea;
|
||||
}
|
||||
$this->record->content = $content;
|
||||
|
||||
$this->record->nextpageurl = null;
|
||||
$this->record->prevpageurl = null;
|
||||
$this->record->exclusiveurl = null;
|
||||
|
||||
$url = core_tag_tag::make_url($tag->tagcollid, $tag->rawname, $exclusivemode, $fromctx, $ctx, $rec);
|
||||
$urlparams = array('ta' => $this->tagarea->id);
|
||||
if ($totalpages > $page + 1) {
|
||||
$this->record->nextpageurl = new moodle_url($url, $urlparams + array('page' => $page + 1));
|
||||
}
|
||||
if ($page > 0) {
|
||||
$this->record->prevpageurl = new moodle_url($url, $urlparams + array('page' => $page - 1));
|
||||
}
|
||||
if (!$exclusivemode && ($totalpages > 1 || $page)) {
|
||||
$this->record->exclusiveurl = new moodle_url($url, $urlparams + array('excl' => 1));
|
||||
}
|
||||
$this->record->exclusivetext = get_string('exclusivemode', 'tag', $a);
|
||||
$this->record->hascontent = ($totalpages > 1 || $page || $content);
|
||||
$this->record->anchor = $component . '_' . $itemtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic setter
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name, $value) {
|
||||
$this->record->$name = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name) {
|
||||
return $this->record->$name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name) {
|
||||
return isset($this->record->$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->record->nextpageurl && $this->record->nextpageurl instanceof moodle_url) {
|
||||
$this->record->nextpageurl = $this->record->nextpageurl->out(false);
|
||||
}
|
||||
if ($this->record->prevpageurl && $this->record->prevpageurl instanceof moodle_url) {
|
||||
$this->record->prevpageurl = $this->record->prevpageurl->out(false);
|
||||
}
|
||||
if ($this->record->exclusiveurl && $this->record->exclusiveurl instanceof moodle_url) {
|
||||
$this->record->exclusiveurl = $this->record->exclusiveurl->out(false);
|
||||
}
|
||||
return $this->record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag\output\taglist
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_tag\output;
|
||||
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use core_tag_tag;
|
||||
use context;
|
||||
|
||||
/**
|
||||
* Class to preapare a list of tags for display, usually the list of tags some entry is tagged with.
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class taglist implements templatable {
|
||||
|
||||
/** @var array */
|
||||
protected $tags;
|
||||
|
||||
/** @var string */
|
||||
protected $label;
|
||||
|
||||
/** @var string */
|
||||
protected $classes;
|
||||
|
||||
/** @var int */
|
||||
protected $limit;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $tags list of instances of \core_tag_tag or \stdClass
|
||||
* @param string $label label to display in front, by default 'Tags' (get_string('tags')), set to null
|
||||
* to use default, set to '' (empty string) to omit the label completely
|
||||
* @param string $classes additional classes for the enclosing div element
|
||||
* @param int $limit limit the number of tags to display, if size of $tags is more than this limit the "more" link
|
||||
* will be appended to the end, JS will toggle the rest of the tags
|
||||
* @param context $pagecontext specify if needed to overwrite the current page context for the view tag link
|
||||
*/
|
||||
public function __construct($tags, $label = null, $classes = '', $limit = 10, $pagecontext = null) {
|
||||
global $PAGE;
|
||||
$canmanagetags = has_capability('moodle/tag:manage', \context_system::instance());
|
||||
|
||||
$this->label = ($label === null) ? get_string('tags') : $label;
|
||||
$this->classes = $classes;
|
||||
$fromctx = $pagecontext ? $pagecontext->id :
|
||||
(($PAGE->context->contextlevel == CONTEXT_SYSTEM) ? 0 : $PAGE->context->id);
|
||||
|
||||
$this->tags = array();
|
||||
foreach ($tags as $idx => $tag) {
|
||||
$this->tags[$idx] = new stdClass();
|
||||
|
||||
$this->tags[$idx]->name = core_tag_tag::make_display_name($tag, false);
|
||||
|
||||
if ($canmanagetags && !empty($tag->flag)) {
|
||||
$this->tags[$idx]->flag = 1;
|
||||
}
|
||||
|
||||
$viewurl = core_tag_tag::make_url($tag->tagcollid, $tag->rawname, 0, $fromctx);
|
||||
$this->tags[$idx]->viewurl = $viewurl->out(false);
|
||||
|
||||
if (!empty($tag->tagtype)) {
|
||||
$this->tags[$idx]->tagtype = $tag->tagtype;
|
||||
}
|
||||
|
||||
if ($limit && count($this->tags) > $limit) {
|
||||
$this->tags[$idx]->overlimit = 1;
|
||||
}
|
||||
}
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$cnt = count($this->tags);
|
||||
return (object)array(
|
||||
'tags' => array_values($this->tags),
|
||||
'label' => $this->label,
|
||||
'tagscount' => $cnt,
|
||||
'overflow' => ($this->limit && $cnt > $this->limit) ? 1 : 0,
|
||||
'classes' => $this->classes,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class core_tag_renderer
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class core_tag_renderer
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2015 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_tag_renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Renders the tag search page
|
||||
*
|
||||
* @param string $query
|
||||
* @param int $tagcollid
|
||||
* @return string
|
||||
*/
|
||||
public function tag_search_page($query = '', $tagcollid = 0) {
|
||||
$rv = $this->output->heading(get_string('searchtags', 'tag'), 2);
|
||||
|
||||
$searchbox = $this->search_form($query, $tagcollid);
|
||||
$rv .= html_writer::div($searchbox, '', array('id' => 'tag-search-box'));
|
||||
|
||||
$tagcloud = core_tag_collection::get_tag_cloud($tagcollid, '', 150, 'name', $query);
|
||||
$searchresults = '';
|
||||
if ($tagcloud->get_count()) {
|
||||
$searchresults = $this->output->render_from_template('core_tag/tagcloud',
|
||||
$tagcloud->export_for_template($this->output));
|
||||
$rv .= html_writer::div($searchresults, '', array('id' => 'tag-search-results'));
|
||||
} else if (strval($query) !== '') {
|
||||
$rv .= '<div class="tag-search-empty">' . get_string('notagsfound', 'tag', s($query)) . '</div>';
|
||||
}
|
||||
|
||||
return $rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the tag index page
|
||||
*
|
||||
* @param core_tag_tag $tag
|
||||
* @param \core_tag\output\tagindex[] $entities
|
||||
* @param int $tagareaid
|
||||
* @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
|
||||
* are displayed on the page and the per-page limit may be bigger
|
||||
* @param int $fromctx context id where the link was displayed, may be used by callbacks
|
||||
* to display items in the same context first
|
||||
* @param int $ctx context id where to search for records
|
||||
* @param bool $rec search in subcontexts as well
|
||||
* @param int $page 0-based number of page being displayed
|
||||
* @return string
|
||||
*/
|
||||
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');
|
||||
|
||||
$tagname = $tag->get_display_name();
|
||||
$systemcontext = context_system::instance();
|
||||
|
||||
if ($tag->flag > 0 && has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
$tagname = '<span class="flagged-tag">' . $tagname . '</span>';
|
||||
}
|
||||
|
||||
$rv = '';
|
||||
$rv .= $this->output->heading($tagname, 2);
|
||||
|
||||
$rv .= $this->tag_links($tag);
|
||||
|
||||
if ($desciption = $tag->get_formatted_description()) {
|
||||
$rv .= $this->output->box($desciption, 'generalbox tag-description');
|
||||
}
|
||||
|
||||
$relatedtagslimit = 10;
|
||||
$relatedtags = $tag->get_related_tags();
|
||||
$taglist = new \core_tag\output\taglist($relatedtags, get_string('relatedtags', 'tag'),
|
||||
'tag-relatedtags', $relatedtagslimit);
|
||||
$rv .= $OUTPUT->render_from_template('core_tag/taglist', $taglist->export_for_template($OUTPUT));
|
||||
|
||||
// Display quick menu of the item types (if more than one item type found).
|
||||
$entitylinks = array();
|
||||
foreach ($entities as $entity) {
|
||||
if (!empty($entity->hascontent)) {
|
||||
$entitylinks[] = '<li><a href="#'.$entity->anchor.'">' .
|
||||
core_tag_area::display_name($entity->component, $entity->itemtype) . '</a></li>';
|
||||
}
|
||||
}
|
||||
|
||||
if (count($entitylinks) > 1) {
|
||||
$rv .= '<div class="tag-index-toc"><ul class="inline-list">' . join('', $entitylinks) . '</ul></div>';
|
||||
} else if (!$entitylinks) {
|
||||
$rv .= '<div class="tag-noresults">' . get_string('noresultsfor', 'tag', $tagname) . '</div>';
|
||||
}
|
||||
|
||||
// Display entities tagged with the tag.
|
||||
$content = '';
|
||||
foreach ($entities as $entity) {
|
||||
if (!empty($entity->hascontent)) {
|
||||
$content .= $this->output->render_from_template('core_tag/index', $entity->export_for_template($this->output));
|
||||
}
|
||||
}
|
||||
|
||||
if ($exclusivemode) {
|
||||
$rv .= $content;
|
||||
} else if ($content) {
|
||||
$rv .= html_writer::div($content, 'tag-index-items');
|
||||
}
|
||||
|
||||
// Display back link if we are browsing one tag area.
|
||||
if ($tagareaid) {
|
||||
$url = $tag->get_view_url(0, $fromctx, $ctx, $rec);
|
||||
$rv .= '<div class="tag-backtoallitems">' .
|
||||
html_writer::link($url, get_string('backtoallitems', 'tag', $tag->get_display_name())) .
|
||||
'</div>';
|
||||
}
|
||||
|
||||
return $rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a box that contains the management links of a tag
|
||||
*
|
||||
* @param core_tag_tag $tag
|
||||
* @return string
|
||||
*/
|
||||
protected function tag_links($tag) {
|
||||
if ($links = $tag->get_links()) {
|
||||
$content = '<ul class="inline-list"><li>' . implode('</li> <li>', $links) . '</li></ul>';
|
||||
return html_writer::div($content, 'tag-management-box');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the tag search box
|
||||
*
|
||||
* @param string $query last search string
|
||||
* @param int $tagcollid last selected tag collection id
|
||||
* @return string
|
||||
*/
|
||||
protected function search_form($query = '', $tagcollid = 0) {
|
||||
$searchurl = new moodle_url('/tag/search.php');
|
||||
$output = '<form action="' . $searchurl . '">';
|
||||
$output .= '<label class="accesshide" for="searchform_query">' . get_string('searchtags', 'tag') . '</label>';
|
||||
$output .= '<input id="searchform_query" name="query" type="text" size="40" value="' . s($query) . '" />';
|
||||
$tagcolls = core_tag_collection::get_collections_menu(false, true, get_string('inalltagcoll', 'tag'));
|
||||
if (count($tagcolls) > 1) {
|
||||
$output .= '<label class="accesshide" for="searchform_tc">' . get_string('selectcoll', 'tag') . '</label>';
|
||||
$output .= html_writer::select($tagcolls, 'tc', $tagcollid, null, array('id' => 'searchform_tc'));
|
||||
}
|
||||
$output .= '<input name="go" type="submit" size="40" value="' . s(get_string('search', 'tag')) . '" />';
|
||||
$output .= '</form>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
+1414
File diff suppressed because it is too large
Load Diff
+47
-70
@@ -26,8 +26,8 @@ require_once('../config.php');
|
||||
require_once('lib.php');
|
||||
require_once('edit_form.php');
|
||||
|
||||
$tag_id = optional_param('id', 0, PARAM_INT);
|
||||
$tag_name = optional_param('tag', '', PARAM_TAG);
|
||||
$tagid = optional_param('id', 0, PARAM_INT);
|
||||
$tagname = optional_param('tag', '', PARAM_TAG);
|
||||
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
|
||||
|
||||
require_login();
|
||||
@@ -40,34 +40,50 @@ if (empty($CFG->usetags)) {
|
||||
$systemcontext = context_system::instance();
|
||||
require_capability('moodle/tag:edit', $systemcontext);
|
||||
|
||||
if ($tag_name) {
|
||||
$tag = tag_get('name', $tag_name, '*');
|
||||
} else if ($tag_id) {
|
||||
$tag = tag_get('id', $tag_id, '*');
|
||||
if ($tagname) {
|
||||
$tagcollid = optional_param('tc', 0, PARAM_INT);
|
||||
if (!$tagcollid) {
|
||||
// Tag name specified but tag collection was not. Try to guess it.
|
||||
$tags = core_tag_tag::guess_by_name($tagname, '*');
|
||||
if (count($tags) > 1) {
|
||||
// This tag was found in more than one collection, redirect to search.
|
||||
redirect(new moodle_url('/tag/search.php', array('tag' => $tagname)));
|
||||
} else if (count($tags) == 1) {
|
||||
$tag = reset($tags);
|
||||
}
|
||||
} else {
|
||||
if (!$tag = core_tag_tag::get_by_name($tagcollid, $tagname, '*')) {
|
||||
redirect(new moodle_url('/tag/search.php', array('tagcollid' => $tagcollid)));
|
||||
}
|
||||
}
|
||||
} else if ($tagid) {
|
||||
$tag = core_tag_tag::get($tagid, '*');
|
||||
}
|
||||
|
||||
if (empty($tag)) {
|
||||
redirect($CFG->wwwroot.'/tag/search.php');
|
||||
redirect(new moodle_url('/tag/search.php'));
|
||||
}
|
||||
|
||||
$PAGE->set_url('/tag/index.php', array('id' => $tag->id));
|
||||
$PAGE->set_url($tag->get_view_url());
|
||||
$PAGE->set_subpage($tag->id);
|
||||
$PAGE->set_context($systemcontext);
|
||||
$PAGE->set_blocks_editing_capability('moodle/tag:editblocks');
|
||||
$PAGE->set_pagelayout('standard');
|
||||
|
||||
$tagname = tag_display_name($tag);
|
||||
$tagname = $tag->get_display_name();
|
||||
$tagcollid = $tag->tagcollid;
|
||||
|
||||
// set the relatedtags field of the $tag object that will be passed to the form
|
||||
$tag->relatedtags = tag_get_tags_array('tag', $tag->id);
|
||||
$data = $tag->to_object();
|
||||
$data->relatedtags = core_tag_tag::get_item_tags_array('core', 'tag', $tag->id);
|
||||
|
||||
$options = new stdClass();
|
||||
$options->smiley = false;
|
||||
$options->filter = false;
|
||||
|
||||
// convert and remove any XSS
|
||||
$tag->description = format_text($tag->description, $tag->descriptionformat, $options);
|
||||
$tag->descriptionformat = FORMAT_HTML;
|
||||
$data->description = format_text($tag->description, $tag->descriptionformat, $options);
|
||||
$data->descriptionformat = FORMAT_HTML;
|
||||
|
||||
$errorstring = '';
|
||||
|
||||
@@ -78,76 +94,37 @@ $editoroptions = array(
|
||||
'context' => $systemcontext,
|
||||
'subdirs' => file_area_contains_subdirs($systemcontext, 'tag', 'description', $tag->id),
|
||||
);
|
||||
$tag = file_prepare_standard_editor($tag, 'description', $editoroptions, $systemcontext, 'tag', 'description', $tag->id);
|
||||
$data = file_prepare_standard_editor($data, 'description', $editoroptions, $systemcontext, 'tag', 'description', $data->id);
|
||||
|
||||
$tagform = new tag_edit_form(null, compact('editoroptions'));
|
||||
if ( $tag->tagtype == 'official' ) {
|
||||
$tag->tagtype = '1';
|
||||
} else {
|
||||
$tag->tagtype = '0';
|
||||
}
|
||||
$tagform = new tag_edit_form(null, array('editoroptions' => $editoroptions, 'tag' => $tag));
|
||||
$data->tagtype = ($data->tagtype === 'official') ? '1' : '0';
|
||||
$data->returnurl = $returnurl;
|
||||
|
||||
$tag->returnurl = $returnurl;
|
||||
$tagform->set_data($tag);
|
||||
$tagform->set_data($data);
|
||||
|
||||
// If new data has been sent, update the tag record
|
||||
if ($tagform->is_cancelled()) {
|
||||
redirect($returnurl ? new moodle_url($returnurl) :
|
||||
new moodle_url('/tag/index.php', array('tag' => $tag->name)));
|
||||
redirect($returnurl ? new moodle_url($returnurl) : $tag->get_view_url());
|
||||
} else if ($tagnew = $tagform->get_data()) {
|
||||
// If new data has been sent, update the tag record.
|
||||
$updatedata = array();
|
||||
|
||||
if (has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
if (($tag->tagtype != 'default') && (!isset($tagnew->tagtype) || ($tagnew->tagtype != '1'))) {
|
||||
tag_type_set($tag->id, 'default');
|
||||
|
||||
} elseif (($tag->tagtype != 'official') && ($tagnew->tagtype == '1')) {
|
||||
tag_type_set($tag->id, 'official');
|
||||
}
|
||||
$updatedata['tagtype'] = empty($tagnew->tagtype) ? 'default' : 'official';
|
||||
$updatedata['rawname'] = $tagnew->rawname;
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
unset($tagnew->name);
|
||||
unset($tagnew->rawname);
|
||||
$tagnew = file_postupdate_standard_editor($tagnew, 'description', $editoroptions,
|
||||
$systemcontext, 'tag', 'description', $tag->id);
|
||||
$updatedata['description'] = $tagnew->description;
|
||||
$updatedata['descriptionformat'] = $tagnew->descriptionformat;
|
||||
|
||||
} else { // They might be trying to change the rawname, make sure it's a change that doesn't affect name
|
||||
$norm = tag_normalize($tagnew->rawname, TAG_CASE_LOWER);
|
||||
$tagnew->name = array_shift($norm);
|
||||
// Update name, description and official type.
|
||||
$tag->update($updatedata);
|
||||
|
||||
if ($tag->rawname !== $tagnew->rawname) { // The name has changed, let's make sure it's not another existing tag
|
||||
if (($id = tag_get_id($tagnew->name)) && $id != $tag->id) { // Something exists already, so flag an error.
|
||||
$errorstring = s($tagnew->rawname).': '.get_string('namesalreadybeeingused', 'tag');
|
||||
}
|
||||
}
|
||||
}
|
||||
// Updated related tags.
|
||||
$tag->set_related_tags($tagnew->relatedtags);
|
||||
|
||||
if (empty($errorstring)) { // All is OK, let's save it
|
||||
|
||||
$tagnew = file_postupdate_standard_editor($tagnew, 'description', $editoroptions, $systemcontext, 'tag', 'description', $tag->id);
|
||||
|
||||
if ($tag->description != $tagnew->description) {
|
||||
tag_description_set($tag_id, $tagnew->description, $tagnew->descriptionformat);
|
||||
}
|
||||
|
||||
$tagnew->timemodified = time();
|
||||
|
||||
if (has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
// Check if we need to rename the tag.
|
||||
if (isset($tagnew->name) && ($tag->rawname != $tagnew->rawname)) {
|
||||
// Rename the tag.
|
||||
if (!tag_rename($tag->id, $tagnew->rawname)) {
|
||||
print_error('errorupdatingrecord', 'tag');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//updated related tags
|
||||
tag_set('tag', $tagnew->id, $tagnew->relatedtags, 'core', $systemcontext->id);
|
||||
//print_object($tagnew); die();
|
||||
|
||||
$tagname = isset($tagnew->rawname) ? $tagnew->rawname : $tag->rawname;
|
||||
redirect($returnurl ? new moodle_url($returnurl) :
|
||||
new moodle_url('/tag/index.php', array('tag' => $tagname)));
|
||||
}
|
||||
redirect($returnurl ? new moodle_url($returnurl) : $tag->get_view_url());
|
||||
}
|
||||
|
||||
navigation_node::override_active_url(new moodle_url('/tag/search.php'));
|
||||
|
||||
+27
-1
@@ -68,10 +68,36 @@ class tag_edit_form extends moodleform {
|
||||
$mform->addElement('checkbox', 'tagtype', get_string('officialtag', 'tag'));
|
||||
}
|
||||
|
||||
$mform->addElement('tags', 'relatedtags', get_string('relatedtags','tag'));
|
||||
$mform->addElement('tags', 'relatedtags', get_string('relatedtags', 'tag'),
|
||||
array('tagcollid' => $this->_customdata['tag']->tagcollid));
|
||||
|
||||
$this->add_action_buttons(true, get_string('updatetag', 'tag'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom form validation
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
if (isset($data['rawname'])) {
|
||||
$newname = core_text::strtolower($data['rawname']);
|
||||
$tag = $this->_customdata['tag'];
|
||||
if ($tag->name != $newname) {
|
||||
// The name has changed, let's make sure it's not another existing tag.
|
||||
if (core_tag_tag::get_by_name($tag->tagcollid, $newname)) {
|
||||
// Something exists already, so flag an error.
|
||||
$errors['rawname'] = get_string('namesalreadybeeingused', 'tag');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+67
-142
@@ -23,10 +23,8 @@
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once('lib.php');
|
||||
require_once('locallib.php');
|
||||
require_once($CFG->dirroot.'/lib/weblib.php');
|
||||
require_once($CFG->dirroot.'/blog/lib.php');
|
||||
require_once($CFG->dirroot . '/lib/weblib.php');
|
||||
require_once($CFG->dirroot . '/blog/lib.php');
|
||||
|
||||
require_login();
|
||||
|
||||
@@ -36,166 +34,93 @@ if (empty($CFG->usetags)) {
|
||||
|
||||
$tagid = optional_param('id', 0, PARAM_INT); // tag id
|
||||
$tagname = optional_param('tag', '', PARAM_TAG); // tag
|
||||
$tagareaid = optional_param('ta', 0, PARAM_INT); // Tag area id.
|
||||
$exclusivemode = optional_param('excl', 0, PARAM_BOOL); // Exclusive mode (show entities in one tag area only).
|
||||
$page = optional_param('page', 0, PARAM_INT); // Page to display.
|
||||
$fromctx = optional_param('from', null, PARAM_INT);
|
||||
$ctx = optional_param('ctx', null, PARAM_INT);
|
||||
$rec = optional_param('rec', 1, PARAM_INT);
|
||||
|
||||
$edit = optional_param('edit', -1, PARAM_BOOL);
|
||||
$userpage = optional_param('userpage', 0, PARAM_INT); // which page to show
|
||||
$perpage = optional_param('perpage', 24, PARAM_INT);
|
||||
|
||||
$systemcontext = context_system::instance();
|
||||
|
||||
if ($tagname) {
|
||||
$tag = tag_get('name', $tagname, '*');
|
||||
$tagcollid = optional_param('tc', 0, PARAM_INT);
|
||||
if (!$tagcollid) {
|
||||
// Tag name specified but tag collection was not. Try to guess it.
|
||||
$tags = core_tag_tag::guess_by_name($tagname, '*');
|
||||
if (count($tags) > 1) {
|
||||
// This tag was found in more than one collection, redirect to search.
|
||||
redirect(new moodle_url('/tag/search.php', array('query' => $tagname)));
|
||||
} else if (count($tags) == 1) {
|
||||
$tag = reset($tags);
|
||||
}
|
||||
} else {
|
||||
if (!$tag = core_tag_tag::get_by_name($tagcollid, $tagname, '*')) {
|
||||
redirect(new moodle_url('/tag/search.php', array('tc' => $tagcollid, 'query' => $tagname)));
|
||||
}
|
||||
}
|
||||
} else if ($tagid) {
|
||||
$tag = tag_get('id', $tagid, '*');
|
||||
$tag = core_tag_tag::get($tagid, '*');
|
||||
}
|
||||
unset($tagid);
|
||||
if (empty($tag)) {
|
||||
redirect($CFG->wwwroot.'/tag/search.php');
|
||||
redirect(new moodle_url('/tag/search.php'));
|
||||
}
|
||||
|
||||
$PAGE->set_url('/tag/index.php', array('id' => $tag->id));
|
||||
if ($ctx && ($context = context::instance_by_id($ctx, IGNORE_MISSING)) && $context->contextlevel >= CONTEXT_COURSE) {
|
||||
list($context, $course, $cm) = get_context_info_array($context->id);
|
||||
require_login($course, false, $cm, false, true);
|
||||
} else {
|
||||
$PAGE->set_context($systemcontext);
|
||||
}
|
||||
|
||||
$tagcollid = $tag->tagcollid;
|
||||
|
||||
$PAGE->set_url($tag->get_view_url($exclusivemode, $fromctx, $ctx, $rec));
|
||||
$PAGE->set_subpage($tag->id);
|
||||
$PAGE->set_context($systemcontext);
|
||||
$tagnode = $PAGE->navigation->find('tags', null);
|
||||
$tagnode->make_active();
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_blocks_editing_capability('moodle/tag:editblocks');
|
||||
|
||||
if (($edit != -1) and $PAGE->user_allowed_editing()) {
|
||||
$USER->editing = $edit;
|
||||
$buttons = '';
|
||||
if (has_capability('moodle/tag:manage', context_system::instance())) {
|
||||
$buttons .= $OUTPUT->single_button(new moodle_url('/tag/manage.php'),
|
||||
get_string('managetags', 'tag'), 'GET');
|
||||
}
|
||||
|
||||
$tagname = tag_display_name($tag);
|
||||
$title = get_string('tag', 'tag') .' - '. $tagname;
|
||||
|
||||
$button = '';
|
||||
if ($PAGE->user_allowed_editing() ) {
|
||||
$button = $OUTPUT->edit_button(new moodle_url("$CFG->wwwroot/tag/index.php", array('id' => $tag->id)));
|
||||
if ($PAGE->user_allowed_editing()) {
|
||||
if ($edit != -1) {
|
||||
$USER->editing = $edit;
|
||||
}
|
||||
$buttons .= $OUTPUT->edit_button(clone($PAGE->url));
|
||||
}
|
||||
|
||||
$PAGE->navbar->add($tagname);
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_title(get_string('tag', 'tag') .' - '. $tag->get_display_name());
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
$PAGE->set_button($button);
|
||||
$courserenderer = $PAGE->get_renderer('core', 'course');
|
||||
$PAGE->set_button($buttons);
|
||||
|
||||
// Find all areas in this collection and their items tagged with this tag.
|
||||
$tagareas = core_tag_collection::get_areas($tagcollid);
|
||||
if ($tagareaid) {
|
||||
$tagareas = array_intersect_key($tagareas, array($tagareaid => 1));
|
||||
}
|
||||
if (!$tagareaid && count($tagareas) == 1) {
|
||||
// Automatically set "exclusive" mode for tag collection with one tag area only.
|
||||
$exclusivemode = 1;
|
||||
}
|
||||
$entities = array();
|
||||
foreach ($tagareas as $ta) {
|
||||
$entities[] = $tag->get_tag_index($ta, $exclusivemode, $fromctx, $ctx, $rec, $page);
|
||||
}
|
||||
$entities = array_filter($entities);
|
||||
|
||||
$tagrenderer = $PAGE->get_renderer('core', 'tag');
|
||||
$pagecontents = $tagrenderer->tag_index_page($tag, array_filter($entities), $tagareaid,
|
||||
$exclusivemode, $fromctx, $ctx, $rec, $page);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Manage all tags links
|
||||
if (has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
echo '<div class="managelink"><a href="'. $CFG->wwwroot .'/tag/manage.php">'. get_string('managetags', 'tag') .'</a></div>' ;
|
||||
}
|
||||
|
||||
$tagname = tag_display_name($tag);
|
||||
|
||||
if ($tag->flag > 0 && has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
$tagname = '<span class="flagged-tag">' . $tagname . '</span>';
|
||||
}
|
||||
|
||||
echo $OUTPUT->heading($tagname, 2);
|
||||
tag_print_management_box($tag);
|
||||
tag_print_description_box($tag);
|
||||
// Check what type of results are avaialable
|
||||
$courses = $courserenderer->tagged_courses($tag->id);
|
||||
|
||||
if (!empty($CFG->enableblogs) && has_capability('moodle/blog:view', $systemcontext)) {
|
||||
require_once($CFG->dirroot.'/blog/lib.php');
|
||||
require_once($CFG->dirroot.'/blog/locallib.php');
|
||||
|
||||
$bloglisting = new blog_listing(array('tag' => $tag->id));
|
||||
$limit = 10;
|
||||
$start = 0;
|
||||
$blogs = $bloglisting->get_entries($start, $limit);
|
||||
}
|
||||
$usercount = tag_record_count('user', $tag->id);
|
||||
|
||||
// Only include <a href />'s to those anchors that actually will be shown
|
||||
$relatedpageslink = "";
|
||||
$countanchors = 0;
|
||||
if (!empty($courses)) {
|
||||
$relatedpageslink = '<a href="#course">'.get_string('courses').'</a>';
|
||||
$countanchors++;
|
||||
}
|
||||
if (!empty($blogs)) {
|
||||
if ($countanchors > 0) {
|
||||
$relatedpageslink .= ' | ';
|
||||
}
|
||||
$relatedpageslink .= '<a href="#blog">'.get_string('relatedblogs', 'tag').'</a>';
|
||||
$countanchors++;
|
||||
}
|
||||
if ($usercount > 0) {
|
||||
if ($countanchors > 0) {
|
||||
$relatedpageslink .= ' | ';
|
||||
}
|
||||
$relatedpageslink .= '<a href="#user">'.get_string('users').'</a>';
|
||||
$countanchors++;
|
||||
}
|
||||
// If only one anchor is present, no <a href /> is needed
|
||||
if ($countanchors == 0) {
|
||||
echo '<div class="relatedpages"><p>'.get_string('noresultsfor', 'tag', $tagname).'</p></div>';
|
||||
} elseif ($countanchors > 1) {
|
||||
echo '<div class="relatedpages"><p>'.$relatedpageslink.'</p></div>';
|
||||
}
|
||||
|
||||
// Display courses tagged with the tag
|
||||
if (!empty($courses)) {
|
||||
|
||||
echo $OUTPUT->box_start('generalbox', 'tag-blogs'); //could use an id separate from tag-blogs, but would have to copy the css style to make it look the same
|
||||
|
||||
echo "<a name='course'></a>";
|
||||
echo $courses;
|
||||
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
// Print up to 10 previous blogs entries
|
||||
|
||||
if (!empty($blogs)) {
|
||||
echo $OUTPUT->box_start('generalbox', 'tag-blogs');
|
||||
$heading = get_string('relatedblogs', 'tag', $tagname). ' ' . get_string('taggedwith', 'tag', $tagname);
|
||||
echo "<a name='blog'></a>";
|
||||
echo $OUTPUT->heading($heading, 3);
|
||||
|
||||
echo '<ul id="tagblogentries">';
|
||||
foreach ($blogs as $blog) {
|
||||
if ($blog->publishstate == 'draft') {
|
||||
$class = 'class="dimmed"';
|
||||
} else {
|
||||
$class = '';
|
||||
}
|
||||
echo '<li '.$class.'>';
|
||||
echo '<a '.$class.' href="'.$CFG->wwwroot.'/blog/index.php?entryid='.$blog->id.'">';
|
||||
echo format_string($blog->subject);
|
||||
echo '</a>';
|
||||
echo ' - ';
|
||||
echo '<a '.$class.' href="'.$CFG->wwwroot.'/user/view.php?id='.$blog->userid.'">';
|
||||
echo fullname($blog);
|
||||
echo '</a>';
|
||||
echo ', '. userdate($blog->lastmodified);
|
||||
echo '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
|
||||
$allblogsurl = new moodle_url('/blog/index.php', array('tagid' => $tag->id));
|
||||
echo '<p class="moreblogs"><a href="'.$allblogsurl->out().'">'.get_string('seeallblogs', 'tag', $tagname).'</a></p>';
|
||||
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
if ($usercount > 0) {
|
||||
|
||||
//user table box
|
||||
echo $OUTPUT->box_start('generalbox', 'tag-user-table');
|
||||
|
||||
$heading = get_string('users'). ' ' . get_string('taggedwith', 'tag', $tagname) . ': ' . $usercount;
|
||||
echo "<a name='user'></a>";
|
||||
echo $OUTPUT->heading($heading, 3);
|
||||
|
||||
$baseurl = new moodle_url('/tag/index.php', array('id' => $tag->id));
|
||||
$pagingbar = new paging_bar($usercount, $userpage, $perpage, $baseurl);
|
||||
$pagingbar->pagevar = 'userpage';
|
||||
echo $OUTPUT->render($pagingbar);
|
||||
tag_print_tagged_users_table($tag, $userpage * $perpage, $perpage);
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
echo $pagecontents;
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
+2
-1526
File diff suppressed because it is too large
Load Diff
+2
-418
@@ -23,421 +23,5 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
/**
|
||||
* Prints or returns a HTML tag cloud with varying classes styles depending on the popularity and type of each tag.
|
||||
*
|
||||
* @package core_tag
|
||||
* @access public
|
||||
* @category tag
|
||||
* @param array $tagset Array of tags to display
|
||||
* @param int $nr_of_tags Limit for the number of tags to return/display, used if $tagset is null
|
||||
* @param bool $return if true the function will return the generated tag cloud instead of displaying it.
|
||||
* @param string $sort (optional) selected sorting, default is alpha sort (name) also timemodified or popularity
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_cloud($tagset=null, $nr_of_tags=150, $return=false, $sort='') {
|
||||
global $CFG, $DB;
|
||||
|
||||
$can_manage_tags = has_capability('moodle/tag:manage', context_system::instance());
|
||||
|
||||
if (is_null($tagset)) {
|
||||
// No tag set received, so fetch tags from database
|
||||
if ( !$tagsincloud = $DB->get_records_sql('SELECT tg.rawname, tg.id, tg.name, tg.tagtype, COUNT(ti.id) AS count, tg.flag
|
||||
FROM {tag_instance} ti JOIN {tag} tg ON tg.id = ti.tagid
|
||||
WHERE ti.itemtype <> \'tag\'
|
||||
GROUP BY tg.id, tg.rawname, tg.name, tg.flag, tg.tagtype
|
||||
ORDER BY count DESC, tg.name ASC', null, 0, $nr_of_tags) ) {
|
||||
$tagsincloud = array();
|
||||
}
|
||||
} else {
|
||||
$tagsincloud = $tagset;
|
||||
}
|
||||
|
||||
$tagkeys = array_keys($tagsincloud);
|
||||
if (!empty($tagkeys)) {
|
||||
$firsttagkey = $tagkeys[0];
|
||||
$maxcount = $tagsincloud[$firsttagkey]->count;
|
||||
}
|
||||
|
||||
$etags = array();
|
||||
|
||||
foreach ($tagsincloud as $tag) {
|
||||
$size = (int) (( $tag->count / $maxcount) * 20);
|
||||
$tag->class = "$tag->tagtype s$size";
|
||||
$etags[] = $tag;
|
||||
}
|
||||
|
||||
// Set up sort global - used to pass sort type into tag_cloud_sort through usort() avoiding multiple sort functions.
|
||||
// TODO make calling functions pass 'count' or 'timemodified' not 'popularity' or 'date'.
|
||||
$oldsort = empty($CFG->tagsort) ? null : $CFG->tagsort;
|
||||
if ($sort == 'popularity') {
|
||||
$CFG->tagsort = 'count';
|
||||
} else if ($sort == 'date') {
|
||||
$CFG->tagsort = 'timemodified';
|
||||
} else {
|
||||
$CFG->tagsort = 'name';
|
||||
}
|
||||
usort($etags, "tag_cloud_sort");
|
||||
$CFG->tagsort = $oldsort;
|
||||
|
||||
$output = '';
|
||||
$output .= "\n<ul class='tag_cloud inline-list'>\n";
|
||||
foreach ($etags as $tag) {
|
||||
if ($tag->flag > 0 && $can_manage_tags) {
|
||||
$tagname = '<span class="flagged-tag">'. tag_display_name($tag) .'</span>';
|
||||
} else {
|
||||
$tagname = tag_display_name($tag);
|
||||
}
|
||||
|
||||
$link = $CFG->wwwroot .'/tag/index.php?tag='. rawurlencode($tag->name);
|
||||
$output .= '<li><a href="'. $link .'" class="'. $tag->class .'" '.
|
||||
'title="'. get_string('numberofentries', 'blog', $tag->count) .'">'.
|
||||
$tagname .'</a></li> ';
|
||||
}
|
||||
$output .= "\n</ul>\n";
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
} else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used by print_tag_cloud, to usort() the tags in the cloud. See php.net/usort for the parameters documentation.
|
||||
* This was originally in blocks/blog_tags/block_blog_tags.php, named blog_tags_sort().
|
||||
*
|
||||
* @package core_tag
|
||||
* @access private
|
||||
* @param string $a Tag name to compare against $b
|
||||
* @param string $b Tag name to compare against $a
|
||||
* @return int The result of the comparison/validation 1, 0 or -1
|
||||
*/
|
||||
function tag_cloud_sort($a, $b) {
|
||||
global $CFG;
|
||||
|
||||
if (empty($CFG->tagsort)) {
|
||||
$tagsort = 'name'; // by default, sort by name
|
||||
} else {
|
||||
$tagsort = $CFG->tagsort;
|
||||
}
|
||||
|
||||
if (is_numeric($a->$tagsort)) {
|
||||
return ($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort) ? 1 : -1;
|
||||
} elseif (is_string($a->$tagsort)) {
|
||||
return strcmp($a->$tagsort, $b->$tagsort);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a box with the description of a tag and its related tags
|
||||
*
|
||||
* @package core_tag
|
||||
* @access public
|
||||
* @todo MDL-31149 create a system setting for $max_tags_displayed, instead of using an in code literal
|
||||
* @param stdClass $tag_object
|
||||
* @param bool $return if true the function will return the generated tag cloud instead of displaying it.
|
||||
* @return string/null a HTML box showing a description of the tag object and it's relationsips or null if output is done directly
|
||||
* in the function.
|
||||
*/
|
||||
function tag_print_description_box($tag_object, $return=false) {
|
||||
|
||||
global $USER, $CFG, $OUTPUT;
|
||||
|
||||
$max_tags_displayed = 10;
|
||||
|
||||
$tagname = tag_display_name($tag_object);
|
||||
$related_tags = tag_get_related_tags($tag_object->id, TAG_RELATED_ALL, $max_tags_displayed+1); // this gets one more than we want
|
||||
|
||||
$content = !empty($tag_object->description) || $related_tags;
|
||||
$output = '';
|
||||
|
||||
if ($content) {
|
||||
$output .= $OUTPUT->box_start('generalbox', 'tag-description');
|
||||
}
|
||||
|
||||
if (!empty($tag_object->description)) {
|
||||
$options = new stdClass();
|
||||
$options->para = false;
|
||||
$options->overflowdiv = true;
|
||||
$tag_object->description = file_rewrite_pluginfile_urls($tag_object->description, 'pluginfile.php', context_system::instance()->id, 'tag', 'description', $tag_object->id);
|
||||
$output .= format_text($tag_object->description, $tag_object->descriptionformat, $options);
|
||||
}
|
||||
|
||||
if ($related_tags) {
|
||||
$more_links = false;
|
||||
if (count($related_tags) > $max_tags_displayed) {
|
||||
array_pop($related_tags);
|
||||
$more_links = true;
|
||||
}
|
||||
$output .= '<br /><br /><strong>'. get_string('relatedtags', 'tag') .': </strong>'. tag_get_related_tags_csv($related_tags);
|
||||
if ($more_links) {
|
||||
$output .= ' ...';
|
||||
}
|
||||
}
|
||||
|
||||
if ($content) {
|
||||
$output .= $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
} else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a box that contains the management links of a tag
|
||||
*
|
||||
* @access public
|
||||
* @param stdClass $tag_object
|
||||
* @param bool $return if true the function will return the generated tag cloud instead of displaying it.
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_management_box($tag_object, $return=false) {
|
||||
|
||||
global $USER, $CFG, $OUTPUT;
|
||||
|
||||
$tagname = tag_display_name($tag_object);
|
||||
$output = '';
|
||||
|
||||
if (!isguestuser()) {
|
||||
$output .= $OUTPUT->box_start('box','tag-management-box');
|
||||
$systemcontext = context_system::instance();
|
||||
$links = array();
|
||||
|
||||
// Add a link for users to add/remove this from their interests
|
||||
if (tag_record_tagged_with('user', $USER->id, $tag_object->name)) {
|
||||
$links[] = '<a href="'. $CFG->wwwroot .'/tag/user.php?action=removeinterest&sesskey='. sesskey() .'&tag='. rawurlencode($tag_object->name) .'">'. get_string('removetagfrommyinterests', 'tag', $tagname) .'</a>';
|
||||
} else {
|
||||
$links[] = '<a href="'. $CFG->wwwroot .'/tag/user.php?action=addinterest&sesskey='. sesskey() .'&tag='. rawurlencode($tag_object->name) .'">'. get_string('addtagtomyinterests', 'tag', $tagname) .'</a>';
|
||||
}
|
||||
|
||||
// Flag as inappropriate link. Only people with moodle/tag:flag capability.
|
||||
if (has_capability('moodle/tag:flag', $systemcontext)) {
|
||||
$links[] = '<a href="'. $CFG->wwwroot .'/tag/user.php?action=flaginappropriate&sesskey='. sesskey() .'&tag='. rawurlencode($tag_object->name) .'">'. get_string('flagasinappropriate', 'tag', rawurlencode($tagname)) .'</a>';
|
||||
}
|
||||
|
||||
// Edit tag: Only people with moodle/tag:edit capability who either have it as an interest or can manage tags
|
||||
if (has_capability('moodle/tag:edit', $systemcontext) ||
|
||||
has_capability('moodle/tag:manage', $systemcontext)) {
|
||||
$links[] = '<a href="'. $CFG->wwwroot .'/tag/edit.php?tag='. rawurlencode($tag_object->name) .'">'. get_string('edittag', 'tag') .'</a>';
|
||||
}
|
||||
|
||||
$output .= implode(' | ', $links);
|
||||
$output .= $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
} else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the tag search box
|
||||
*
|
||||
* @access public
|
||||
* @param bool $return if true return html string
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_search_box($return=false) {
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
$output = $OUTPUT->box_start('','tag-search-box');
|
||||
$output .= '<form action="'.$CFG->wwwroot.'/tag/search.php" style="display:inline">';
|
||||
$output .= '<div>';
|
||||
$output .= '<label class="accesshide" for="searchform_search">'.get_string('searchtags', 'tag').'</label>';
|
||||
$output .= '<input id="searchform_search" name="query" type="text" size="40" />';
|
||||
$output .= '<button id="searchform_button" type="submit">'. get_string('search', 'tag') .'</button><br />';
|
||||
$output .= '</div>';
|
||||
$output .= '</form>';
|
||||
$output .= $OUTPUT->box_end();
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
}
|
||||
else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the tag search results
|
||||
*
|
||||
* @access public
|
||||
* @param string $query text that tag names will be matched against
|
||||
* @param int $page current page
|
||||
* @param int $perpage nr of users displayed per page
|
||||
* @param bool $return if true return html string
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_search_results($query, $page, $perpage, $return=false) {
|
||||
|
||||
global $CFG, $USER, $OUTPUT;
|
||||
|
||||
$norm = tag_normalize($query, TAG_CASE_ORIGINAL);
|
||||
$query = array_shift($norm);
|
||||
|
||||
$count = sizeof(tag_find_tags($query, false));
|
||||
$tags = array();
|
||||
|
||||
if ( $found_tags = tag_find_tags($query, true, $page * $perpage, $perpage) ) {
|
||||
$tags = array_values($found_tags);
|
||||
}
|
||||
|
||||
$baseurl = $CFG->wwwroot.'/tag/search.php?query='. rawurlencode($query);
|
||||
$output = '';
|
||||
|
||||
// link "Add $query to my interests"
|
||||
$addtaglink = '';
|
||||
if( !tag_record_tagged_with('user', $USER->id, $query) ) {
|
||||
$addtaglink = '<a href="'. $CFG->wwwroot .'/tag/user.php?action=addinterest&sesskey='. sesskey() .'&tag='. rawurlencode($query) .'">';
|
||||
$addtaglink .= get_string('addtagtomyinterests', 'tag', htmlspecialchars($query)) .'</a>';
|
||||
}
|
||||
|
||||
if ( !empty($tags) ) { // there are results to display!!
|
||||
$output .= $OUTPUT->heading(get_string('searchresultsfor', 'tag', htmlspecialchars($query)) ." : {$count}", 3, 'main');
|
||||
|
||||
//print a link "Add $query to my interests"
|
||||
if (!empty($addtaglink)) {
|
||||
$output .= $OUTPUT->box($addtaglink, 'box', 'tag-management-box');
|
||||
}
|
||||
|
||||
$nr_of_lis_per_ul = 6;
|
||||
$nr_of_uls = ceil( sizeof($tags) / $nr_of_lis_per_ul );
|
||||
|
||||
$output .= '<ul id="tag-search-results">';
|
||||
for($i = 0; $i < $nr_of_uls; $i++) {
|
||||
$output .= '<li>';
|
||||
foreach (array_slice($tags, $i * $nr_of_lis_per_ul, $nr_of_lis_per_ul) as $tag) {
|
||||
$tag_link = ' <a href="'. $CFG->wwwroot .'/tag/index.php?id='. $tag->id .'">'. tag_display_name($tag) .'</a>';
|
||||
$output .= '•'. $tag_link .'<br/>';
|
||||
}
|
||||
$output .= '</li>';
|
||||
}
|
||||
$output .= '</ul>';
|
||||
$output .= '<div> </div>'; // <-- small layout hack in order to look good in Firefox
|
||||
|
||||
$output .= $OUTPUT->paging_bar($count, $page, $perpage, $baseurl);
|
||||
}
|
||||
else { //no results were found!!
|
||||
$output .= $OUTPUT->heading(get_string('noresultsfor', 'tag', htmlspecialchars($query)), 3, 'main');
|
||||
|
||||
//print a link "Add $query to my interests"
|
||||
if (!empty($addtaglink)) {
|
||||
$output .= $OUTPUT->box($addtaglink, 'box', 'tag-management-box');
|
||||
}
|
||||
}
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
}
|
||||
else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a table of the users tagged with the tag passed as argument
|
||||
*
|
||||
* @param int $tag_object the tag we wish to return data for
|
||||
* @param int $limitfrom (optional, required if $limitnum is set) prints users starting at this point.
|
||||
* @param int $limitnum (optional, required if $limitfrom is set) prints this many users.
|
||||
* @param bool $return if true return html string
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_tagged_users_table($tag_object, $limitfrom='', $limitnum='', $return=false) {
|
||||
|
||||
//List of users with this tag
|
||||
$userlist = tag_find_records($tag_object->name, 'user', $limitfrom, $limitnum);
|
||||
|
||||
$output = tag_print_user_list($userlist, true);
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
}
|
||||
else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an individual user box
|
||||
*
|
||||
* @param user_object $user (contains the following fields: id, firstname, lastname and picture)
|
||||
* @param bool $return if true return html string
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_user_box($user, $return=false) {
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
$usercontext = context_user::instance($user->id);
|
||||
$profilelink = '';
|
||||
|
||||
if ($usercontext and (has_capability('moodle/user:viewdetails', $usercontext) || has_coursecontact_role($user->id))) {
|
||||
$profilelink = $CFG->wwwroot .'/user/view.php?id='. $user->id;
|
||||
}
|
||||
|
||||
$output = $OUTPUT->box_start('user-box', 'user'. $user->id);
|
||||
$fullname = fullname($user);
|
||||
$alt = '';
|
||||
|
||||
if (!empty($profilelink)) {
|
||||
$output .= '<a href="'. $profilelink .'">';
|
||||
$alt = $fullname;
|
||||
}
|
||||
|
||||
$output .= $OUTPUT->user_picture($user, array('size'=>100));
|
||||
$output .= '<br />';
|
||||
|
||||
if (!empty($profilelink)) {
|
||||
$output .= '</a>';
|
||||
}
|
||||
|
||||
//truncate name if it's too big
|
||||
if (core_text::strlen($fullname) > 26) {
|
||||
$fullname = core_text::substr($fullname, 0, 26) .'...';
|
||||
}
|
||||
|
||||
$output .= '<strong>'. $fullname .'</strong>';
|
||||
$output .= $OUTPUT->box_end();
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
}
|
||||
else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a list of users
|
||||
*
|
||||
* @param array $userlist an array of user objects
|
||||
* @param bool $return if true return html string, otherwise output the result
|
||||
* @return string|null a HTML string or null if this function does the output
|
||||
*/
|
||||
function tag_print_user_list($userlist, $return=false) {
|
||||
|
||||
$output = '<ul class="inline-list">';
|
||||
|
||||
foreach ($userlist as $user){
|
||||
$output .= '<li>'. tag_print_user_box($user, true) ."</li>\n";
|
||||
}
|
||||
$output .= "</ul>\n";
|
||||
|
||||
if ($return) {
|
||||
return $output;
|
||||
}
|
||||
else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
debugging('All functions from /tags/locallib.php were deprecated and it will be removed soon, '.
|
||||
'do not include this file in your code', DEBUG_DEVELOPER);
|
||||
|
||||
+163
-36
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -16,8 +15,9 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @package core
|
||||
* @subpackage tag
|
||||
* Managing tags, tag areas and tags collections
|
||||
*
|
||||
* @package core_tag
|
||||
* @copyright 2007 Luiz Cruz <luiz.laydner@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
@@ -37,12 +37,8 @@ $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);
|
||||
|
||||
require_login();
|
||||
|
||||
if (empty($CFG->usetags)) {
|
||||
print_error('tagsaredisabled', 'tag');
|
||||
}
|
||||
$tagcollid = optional_param('tc', 0, PARAM_INT);
|
||||
$tagareaid = optional_param('ta', null, PARAM_INT);
|
||||
|
||||
$params = array();
|
||||
if ($perpage != DEFAULT_PAGE_SIZE) {
|
||||
@@ -51,60 +47,168 @@ if ($perpage != DEFAULT_PAGE_SIZE) {
|
||||
if ($page > 0) {
|
||||
$params['page'] = $page;
|
||||
}
|
||||
|
||||
admin_externalpage_setup('managetags', '', $params, '', array('pagelayout' => 'report'));
|
||||
|
||||
if (empty($CFG->usetags)) {
|
||||
print_error('tagsaredisabled', 'tag');
|
||||
}
|
||||
|
||||
$tagobject = null;
|
||||
if ($tagid) {
|
||||
$tagobject = core_tag_tag::get($tagid, '*', MUST_EXIST);
|
||||
$tagcollid = $tagobject->tagcollid;
|
||||
}
|
||||
$tagcoll = core_tag_collection::get_by_id($tagcollid);
|
||||
$tagarea = core_tag_area::get_by_id($tagareaid);
|
||||
$manageurl = new moodle_url('/tag/manage.php');
|
||||
if ($tagcoll) {
|
||||
// We are inside a tag collection - add it to the page url and the breadcrumb.
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array('tc' => $tagcoll->id)));
|
||||
$PAGE->navbar->add(core_tag_collection::display_name($tagcoll),
|
||||
new moodle_url($manageurl, array('tc' => $tagcoll->id)));
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
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')));
|
||||
}
|
||||
redirect($manageurl);
|
||||
break;
|
||||
|
||||
case 'collmoveup':
|
||||
if ($tagcoll) {
|
||||
require_sesskey();
|
||||
core_tag_collection::change_sortorder($tagcoll, -1);
|
||||
redirect(new moodle_url($manageurl, array('notice' => 'changessaved')));
|
||||
}
|
||||
redirect($manageurl);
|
||||
break;
|
||||
|
||||
case 'collmovedown':
|
||||
if ($tagcoll) {
|
||||
require_sesskey();
|
||||
core_tag_collection::change_sortorder($tagcoll, 1);
|
||||
redirect(new moodle_url($manageurl, array('notice' => 'changessaved')));
|
||||
}
|
||||
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 'delete':
|
||||
require_sesskey();
|
||||
if (!$tagschecked && $tagid) {
|
||||
$tagschecked = array($tagid);
|
||||
}
|
||||
tag_delete($tagschecked);
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'deleted')));
|
||||
core_tag_tag::delete_tags($tagschecked);
|
||||
redirect(new moodle_url($PAGE->url, $tagschecked ? array('notice' => 'deleted') : null));
|
||||
break;
|
||||
|
||||
case 'setflag':
|
||||
require_sesskey();
|
||||
tag_set_flag($tagid);
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'flagged')));
|
||||
if ($tagid) {
|
||||
$tagobject->flag();
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'flagged')));
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
break;
|
||||
|
||||
case 'resetflag':
|
||||
require_sesskey();
|
||||
tag_unset_flag($tagid);
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'resetflag')));
|
||||
if ($tagid) {
|
||||
$tagobject->reset_flag();
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'resetflag')));
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
break;
|
||||
|
||||
case 'changetype':
|
||||
require_sesskey();
|
||||
if ($tagtype === 'official' || $tagtype === 'default') {
|
||||
if (tag_type_set($tagid, $tagtype)) {
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'typechanged')));
|
||||
}
|
||||
if ($tagid && $tagobject->update(array('tagtype' => $tagtype))) {
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'typechanged')));
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
break;
|
||||
|
||||
case 'addofficialtag':
|
||||
require_sesskey();
|
||||
$otagsadd = optional_param('otagsadd', '', PARAM_RAW);
|
||||
$newtags = preg_split('/\s*,\s*/', trim($otagsadd), -1, PREG_SPLIT_NO_EMPTY);
|
||||
$newtags = array_filter(tag_normalize($newtags, TAG_CASE_ORIGINAL));
|
||||
if (!$newtags) {
|
||||
redirect($PAGE->url);
|
||||
$tagobjects = null;
|
||||
if ($tagcoll) {
|
||||
$otagsadd = optional_param('otagsadd', '', PARAM_RAW);
|
||||
$newtags = preg_split('/\s*,\s*/', trim($otagsadd), -1, PREG_SPLIT_NO_EMPTY);
|
||||
$tagobjects = core_tag_tag::create_if_missing($tagcoll->id, $newtags, true);
|
||||
}
|
||||
foreach ($newtags as $newotag) {
|
||||
if ($newotagid = tag_get_id($newotag) ) {
|
||||
// Tag exists, change the type.
|
||||
tag_type_set($newotagid, 'official');
|
||||
} else {
|
||||
tag_add($newotag, 'official');
|
||||
foreach ($tagobjects as $tagobject) {
|
||||
if ($tagobject->tagtype !== 'official') {
|
||||
$tagobject->update(array('tagtype' => 'official'));
|
||||
}
|
||||
}
|
||||
redirect(new moodle_url($PAGE->url, array('notice' => 'added')));
|
||||
redirect(new moodle_url($PAGE->url, $tagobjects ? array('notice' => 'added') : null));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -114,8 +218,28 @@ 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);
|
||||
$colltable = new core_tag_collections_table($manageurl);
|
||||
|
||||
echo $OUTPUT->heading(get_string('tagcollections', 'core_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 $OUTPUT->heading(get_string('tagareas', 'core_tag'), 3);
|
||||
echo html_writer::table($tagareastable);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Tag collection is specified. Manage tags in this collection.
|
||||
|
||||
// Small form to add an official tag.
|
||||
print('<form class="tag-addtags-form" method="post" action="'.$CFG->wwwroot.'/tag/manage.php">');
|
||||
print('<input type="hidden" name="tc" value="'.$tagcollid.'" />');
|
||||
print('<input type="hidden" name="action" value="addofficialtag" />');
|
||||
print('<input type="hidden" name="perpage" value="'.$perpage.'" />');
|
||||
print('<input type="hidden" name="page" value="'.$page.'" />');
|
||||
@@ -128,18 +252,21 @@ print('<div class="tag-management-form generalbox"><label class="accesshide" for
|
||||
'</div>');
|
||||
print('</form>');
|
||||
|
||||
$table = new core_tag_manage_table();
|
||||
$table = new core_tag_manage_table($tagcollid);
|
||||
echo '<form class="tag-management-form" method="post" action="'.$CFG->wwwroot.'/tag/manage.php">';
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'tc', 'value' => $tagcollid));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'delete'));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'perpage', 'value' => $perpage));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'page', 'value' => $page));
|
||||
echo $table->out($perpage, true);
|
||||
|
||||
echo html_writer::start_tag('p');
|
||||
echo html_writer::tag('button', get_string('deleteselected', 'tag'),
|
||||
array('id' => 'tag-management-delete', 'type' => 'submit', 'class' => 'tagdeleteselected'));
|
||||
echo html_writer::end_tag('p');
|
||||
if ($table->rawdata) {
|
||||
echo html_writer::start_tag('p');
|
||||
echo html_writer::tag('button', get_string('deleteselected', 'tag'),
|
||||
array('id' => 'tag-management-delete', 'type' => 'submit', 'class' => 'tagdeleteselected'));
|
||||
echo html_writer::end_tag('p');
|
||||
}
|
||||
echo '</form>';
|
||||
|
||||
$totalcount = $table->totalcount;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user