MDL-40368 tool_capability: overall improvements made

* Can now compare multiple capabilities at the same time.
* Capability search now persists between requests.
* Upgraded to use renderers.
* Upgraded module.js to YUI shifted module.
* Converted deprecated calls.
* Converted forms to Moodleforms.
* Implemented backend functionality to overview at
  different context levels. Not possible presently as
  there are no front end hooks.
This commit is contained in:
Sam Hemelryk 2013-06-28 12:39:18 +12:00
parent f0d37f4ac5
commit 9935136f4d
12 changed files with 845 additions and 259 deletions

View File

@ -0,0 +1,62 @@
<?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/>.
/**
* Capability tool settings form.
*
* Do no include this file, it is automatically loaded by the class loader!
*
* @package tool_capability
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->libdir.'/formslib.php');
/**
* Class tool_capability_settings_form
*
* The settings form for the comparison of roles/capabilities.
*
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_capability_settings_form extends moodleform {
/**
* The form definition.
*/
public function definition() {
$form = $this->_form;
// Set the form ID.
$form->setAttributes(array('id' => 'capability-overview-form') + $form->getAttributes());
$form->addElement('header', 'reportsettings', get_string('reportsettings', 'tool_capability'));
$form->addElement('html', html_writer::tag('p', get_string('intro', 'tool_capability'), array('id' => 'intro')));
$form->addElement('hidden', 'search');
$form->setType('search', PARAM_TEXT);
$form->addElement('select', 'capability', get_string('capabilitylabel', 'tool_capability'), $this->_customdata['capabilities'], array('multiple' => 'multiple', 'size' => 10, 'data-search' => 'capability'));
$form->setType('capability', PARAM_CAPABILITY);
$form->addElement('select', 'roles', get_string('roleslabel', 'tool_capability'), $this->_customdata['roles'], array('multiple' => 'multiple', 'size' => 10));
$form->setType('roles', PARAM_TEXT);
$form->addElement('submit', 'submitbutton', get_string('getreport', 'tool_capability'));
}
}

View File

@ -18,215 +18,83 @@
* For a given capability, show what permission it has for every role, and
* everywhere that it is overridden.
*
* @package tool
* @subpackage capability
* @package tool_capability
* @copyright 2008 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__) . '/../../../config.php');
require_once($CFG->dirroot.'/'.$CFG->admin.'/tool/capability/locallib.php');
require_once($CFG->libdir.'/adminlib.php');
// Check permissions.
require_login();
$systemcontext = context_system::instance();
require_capability('moodle/role:manage', $systemcontext);
// Get URL parameters.
$capability = optional_param('capability', '', PARAM_CAPABILITY);
$roleids = optional_param_array('roles', array('0'), PARAM_INT);
$systemcontext = context_system::instance();
$contextid = optional_param('context', $systemcontext->id, PARAM_INT);
// Clean the passed in list of role ids. If 'All' selected as an option, or
// if none were selected, do all roles.
$allroles = role_fix_names(get_all_roles());
$cleanedroleids = array();
foreach ($roleids as $roleid) {
if ($roleid == 0) {
$cleanedroleids = array_keys($allroles);
break;
}
if (array_key_exists($roleid, $allroles)) {
$cleanedroleids[] = $roleid;
}
}
if (empty($cleanedroleids)) {
$cleanedroleids = array_keys($allroles);
}
// Include the required JavaScript.
$PAGE->requires->js_init_call('M.tool_capability.init', array(get_string('search')));
// Log.
add_to_log(SITEID, "admin", "tool capability", "tool/capability/index.php?capability=$capability", $capability);
// Check permissions.
list($context, $course, $cm) = get_context_info_array($contextid);
require_login($course, false, $cm);
require_capability('moodle/role:manage', $context);
// Print the header.
admin_externalpage_setup('toolcapability');
echo $OUTPUT->header();
// Prepare the list of capabilities to choose from
$allcapabilities = fetch_context_capabilities($systemcontext);
// Prepare the list of capabilities to choose from.
$capabilitychoices = array();
foreach ($allcapabilities as $cap) {
foreach ($context->get_capabilities() as $cap) {
$capabilitychoices[$cap->name] = $cap->name . ': ' . get_capability_string($cap->name);
}
// Prepare the list of roles to choose from
$allroles = role_fix_names(get_all_roles($context));
// Prepare the list of roles to choose from.
$rolechoices = array('0' => get_string('all'));
foreach ($allroles as $role) {
$rolechoices[$role->id] = $role->localname;
}
if (count($cleanedroleids) == count($allroles)) {
// Select 'All', rather than each role individually.
$selectedroleids = array('0');
} else {
$selectedroleids = $cleanedroleids;
$form = new tool_capability_settings_form(null, array(
'capabilities' => $capabilitychoices,
'roles' => $rolechoices
));
$PAGE->requires->yui_module('moodle-tool_capability-search', 'M.tool_capability.init_capability_search', array(array('strsearch' => get_string('search'))));
// Log.
$capabilities = array();
$rolestoshow = array();
$roleids = array('0');
$cleanedroleids = array();
if ($data = $form->get_data()) {
$capabilities = $data->capability;
$allrolesids = array_keys($allroles);
$roleids = $data->roles;
if (in_array('0', $roleids)) {
$rolestoshow = $allroles;
} else {
$cleanedroleids = array_intersect($allrolesids, $roleids);
if (count($cleanedroleids) === 0) {
$rolestoshow = $allroles;
} else {
foreach ($cleanedroleids as $id) {
$rolestoshow[$id] = $allroles[$id];
}
}
}
}
// Print the settings form.
echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
echo '<form method="get" action="" id="settingsform"><div>';
echo $OUTPUT->heading(get_string('reportsettings', 'tool_capability'));
echo '<p id="intro">', get_string('intro', 'tool_capability') , '</p>';
echo '<p><label for="menucapability"> ' . get_string('capabilitylabel', 'tool_capability') . '</label></p>';
echo html_writer::select($capabilitychoices, 'capability', $capability, array(''=>'choose'), array('size'=>10));
echo '<p><label for="menuroles"> ' . get_string('roleslabel', 'tool_capability') . '</label></p>';
echo html_writer::select($rolechoices, 'roles[]', $selectedroleids, false, array('size'=>10, 'multiple'=>'multiple'));
echo '<p><input type="submit" id="settingssubmit" value="' . get_string('getreport', 'tool_capability') . '" /></p>';
echo '</div></form>';
echo $OUTPUT->box_end();
add_to_log(SITEID, "admin", "tool capability", "tool/capability/index.php", count($capabilities));
$renderer = $PAGE->get_renderer('tool_capability');
echo $OUTPUT->header();
$form->display();
// If we have a capability, generate the report.
if ($capability) {
// Work out the bits needed for the SQL WHERE clauses.
$params = array($capability);
$sqlroletest = '';
if (count($cleanedroleids) != count($allroles)) {
list($sqlroletest, $roleparams) = $DB->get_in_or_equal($cleanedroleids);
$params = array_merge($params, $roleparams);
$sqlroletest = 'AND roleid ' . $sqlroletest;
}
// Get all the role_capabilities rows for this capability - that is, all
// role definitions, and all role overrides.
$rolecaps = $DB->get_records_sql("
SELECT id, roleid, contextid, permission
FROM {role_capabilities}
WHERE capability = ? $sqlroletest", $params);
// In order to display a nice tree of contexts, we need to get all the
// ancestors of all the contexts in the query we just did.
$relevantpaths = $DB->get_records_sql_menu("
SELECT DISTINCT con.path, 1
FROM {context} con JOIN {role_capabilities} rc ON rc.contextid = con.id
WHERE capability = ? $sqlroletest", $params);
$requiredcontexts = array($systemcontext->id);
foreach ($relevantpaths as $path => $notused) {
$requiredcontexts = array_merge($requiredcontexts, explode('/', trim($path, '/')));
}
$requiredcontexts = array_unique($requiredcontexts);
// Now load those contexts.
list($sqlcontexttest, $contextparams) = $DB->get_in_or_equal($requiredcontexts);
$contexts = get_sorted_contexts('ctx.id ' . $sqlcontexttest, $contextparams);
// Prepare some empty arrays to hold the data we are about to compute.
foreach ($contexts as $conid => $con) {
$contexts[$conid]->children = array();
$contexts[$conid]->rolecapabilities = array();
}
// Put the contexts into a tree structure.
foreach ($contexts as $conid => $con) {
$context = context::instance_by_id($conid);
$parentcontextid = get_parent_contextid($context);
if ($parentcontextid) {
$contexts[$parentcontextid]->children[] = $conid;
}
}
// Put the role capabilities into the context tree.
foreach ($rolecaps as $rolecap) {
$contexts[$rolecap->contextid]->rolecapabilities[$rolecap->roleid] = $rolecap->permission;
}
// Fill in any missing rolecaps for the system context.
foreach ($cleanedroleids as $roleid) {
if (!isset($contexts[$systemcontext->id]->rolecapabilities[$roleid])) {
$contexts[$systemcontext->id]->rolecapabilities[$roleid] = CAP_INHERIT;
}
}
// Print the report heading.
echo $OUTPUT->heading(get_string('reportforcapability', 'tool_capability', get_capability_string($capability)), 2, 'main', 'report');
if (count($cleanedroleids) != count($allroles)) {
$rolenames = array();
foreach ($cleanedroleids as $roleid) {
$rolenames[] = $allroles[$roleid]->localname;
}
echo '<p>', get_string('forroles', 'tool_capability', implode(', ', $rolenames)), '</p>';
}
// Now, recursively print the contexts, and the role information.
print_report_tree($systemcontext->id, $contexts, $allroles);
if (count($capabilities) && count($rolestoshow)) {
/** @var tool_capability_renderer $renderer */
echo $renderer->capability_comparison_table($capabilities, $context->id, $rolestoshow);
}
// Footer.
echo $OUTPUT->footer();
function print_report_tree($contextid, $contexts, $allroles) {
global $CFG;
// Array for holding lang strings.
static $strpermissions = null;
if (is_null($strpermissions)) {
$strpermissions = array(
CAP_INHERIT => get_string('notset','role'),
CAP_ALLOW => get_string('allow','role'),
CAP_PREVENT => get_string('prevent','role'),
CAP_PROHIBIT => get_string('prohibit','role')
);
}
// Start the list item, and print the context name as a link to the place to
// make changes.
if ($contextid == get_system_context()->id) {
$url = "$CFG->wwwroot/$CFG->admin/roles/manage.php";
$title = get_string('changeroles', 'tool_capability');
} else {
$url = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid";
$title = get_string('changeoverrides', 'tool_capability');
}
$context = context::instance_by_id($contextid);
echo '<h3><a href="' . $url . '" title="' . $title . '">', $context->get_context_name(), '</a></h3>';
// If there are any role overrides here, print them.
if (!empty($contexts[$contextid]->rolecapabilities)) {
$rowcounter = 0;
echo '<table class="generaltable rolecaps"><tbody>';
foreach ($allroles as $role) {
if (isset($contexts[$contextid]->rolecapabilities[$role->id])) {
$permission = $contexts[$contextid]->rolecapabilities[$role->id];
echo '<tr class="r' . ($rowcounter % 2) . '"><th class="cell">', $role->localname,
'</th><td class="cell">' . $strpermissions[$permission] . '</td></tr>';
$rowcounter++;
}
}
echo '</tbody></table>';
}
// After we have done the site context, change the string for CAP_INHERIT
// from 'notset' to 'inherit'.
$strpermissions[CAP_INHERIT] = get_string('inherit','role');
// If there are any child contexts, print them recursively.
if (!empty($contexts[$contextid]->children)) {
echo '<ul>';
foreach ($contexts[$contextid]->children as $childcontextid) {
echo '<li>';
print_report_tree($childcontextid, $contexts, $allroles);
echo '</li>';
}
echo '</ul>';
}
}
echo $OUTPUT->footer();

View File

@ -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/>.
/**
* Functions used by the capability tool.
*
* @package tool_capability
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Calculates capability data organised by context for the given roles.
*
* @param string $capability The capability to get data for.
* @param array $roles An array of roles to get data for.
* @return context[] An array of contexts.
*/
function tool_capability_calculate_role_data($capability, array $roles) {
global $DB;
$systemcontext = context_system::instance();
$roleids = array_keys($roles);
// Work out the bits needed for the SQL WHERE clauses.
$params = array($capability);
list($sqlroletest, $roleparams) = $DB->get_in_or_equal($roleids);
$params = array_merge($params, $roleparams);
$sqlroletest = 'AND roleid ' . $sqlroletest;
// Get all the role_capabilities rows for this capability - that is, all
// role definitions, and all role overrides.
$rolecaps = $DB->get_records_sql("
SELECT id, roleid, contextid, permission
FROM {role_capabilities}
WHERE capability = ? $sqlroletest", $params);
// In order to display a nice tree of contexts, we need to get all the
// ancestors of all the contexts in the query we just did.
$relevantpaths = $DB->get_records_sql_menu("
SELECT DISTINCT con.path, 1
FROM {context} con JOIN {role_capabilities} rc ON rc.contextid = con.id
WHERE capability = ? $sqlroletest", $params);
$requiredcontexts = array($systemcontext->id);
foreach ($relevantpaths as $path => $notused) {
$requiredcontexts = array_merge($requiredcontexts, explode('/', trim($path, '/')));
}
$requiredcontexts = array_unique($requiredcontexts);
// Now load those contexts.
list($sqlcontexttest, $contextparams) = $DB->get_in_or_equal($requiredcontexts);
$contexts = get_sorted_contexts('ctx.id ' . $sqlcontexttest, $contextparams);
// Prepare some empty arrays to hold the data we are about to compute.
foreach ($contexts as $conid => $con) {
$contexts[$conid]->children = array();
$contexts[$conid]->rolecapabilities = array();
}
// Put the contexts into a tree structure.
foreach ($contexts as $conid => $con) {
$context = context::instance_by_id($conid);
$parentcontextid = get_parent_contextid($context);
if ($parentcontextid) {
$contexts[$parentcontextid]->children[] = $conid;
}
}
// Put the role capabilities into the context tree.
foreach ($rolecaps as $rolecap) {
$contexts[$rolecap->contextid]->rolecapabilities[$rolecap->roleid] = $rolecap->permission;
}
// Fill in any missing rolecaps for the system context.
foreach ($roleids as $roleid) {
if (!isset($contexts[$systemcontext->id]->rolecapabilities[$roleid])) {
$contexts[$systemcontext->id]->rolecapabilities[$roleid] = CAP_INHERIT;
}
}
return $contexts;
}

View File

@ -1,75 +0,0 @@
M.tool_capability = {
select: null,
input: null,
button: null,
init: function(Y, strsearch) {
var context = M.tool_capability;
// Find the form controls.
context.select = document.getElementById('menucapability');
context.button = document.getElementById('settingssubmit');
// Create a div to hold the search UI.
var div = document.createElement('div');
div.id = 'capabilitysearchui';
// Find the capability search input.
var input = document.createElement('input');
input.type = 'text';
input.id = 'capabilitysearch';
context.input = input;
// Create a label for the search input.
var label = document.createElement('label');
label.htmlFor = input.id;
label.appendChild(document.createTextNode(strsearch + ' '));
// Tie it all together
div.appendChild(label);
div.appendChild(input);
context.select.parentNode.insertBefore(div, context.select);
Y.on('keyup', context.typed, input);
Y.on('change', context.validate, context.select);
context.select.options[0].style.display = 'none';
context.validate();
},
typed: function() {
var context = M.tool_capability;
var filtertext = context.input.value;
var options = context.select.options;
var onlycapability = -1;
for (var i = 1; i < options.length; i++) {
if (options[i].text.indexOf(filtertext) >= 0) {
options[i].disabled = false;
options[i].style.display = 'block';
if (onlycapability == -1) {
onlycapability = i;
} else {
onlycapability = -2;
}
} else {
options[i].disabled = true;
options[i].selected = false;
options[i].style.display = 'none';
}
}
if (onlycapability >= 0) {
options[onlycapability].selected = true;
}
if (onlycapability == -1) {
context.input.className = "error";
} else {
context.input.className = "";
}
context.validate();
},
validate: function() {
var context = M.tool_capability;
context.button.disabled = (context.select.value == '');
}
}

View File

@ -0,0 +1,136 @@
<?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/>.
/**
* Capability tool renderer.
*
* @package tool_capability
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* The primary renderer for the capability tool.
*
* @copyright 2013 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_capability_renderer extends plugin_renderer_base {
/**
* Returns an array of permission strings.
*
* @return lang_string[]
*/
protected function get_permission_strings() {
static $strpermissions;
if (!$strpermissions) {
$strpermissions = array(
CAP_INHERIT => new lang_string('inherit','role'),
CAP_ALLOW => new lang_string('allow','role'),
CAP_PREVENT => new lang_string('prevent','role'),
CAP_PROHIBIT => new lang_string('prohibit','role')
);
}
return $strpermissions;
}
/**
* Returns an array of permission CSS classes.
*
* @return string[]
*/
protected function get_permission_classes() {
static $permissionclasses;
if (!$permissionclasses) {
$permissionclasses = array(
CAP_INHERIT => 'inherit',
CAP_ALLOW => 'allow',
CAP_PREVENT => 'prevent',
CAP_PROHIBIT => 'prohibit',
);
}
return $permissionclasses;
}
/**
* Produces a table to visually compare roles and capabilities.
*
* @param array $capabilities An array of capabilities to show comparison for.
* @param int $contextid The context we are displaying for.
* @param array $roles An array of roles to show comparison for.
* @return string
*/
public function capability_comparison_table(array $capabilities, $contextid, array $roles) {
$strpermissions = $this->get_permission_strings();
$permissionclasses = $this->get_permission_classes();
if ($contextid === context_system::instance()->id) {
$strpermissions[CAP_INHERIT] = new lang_string('notset', 'role');
}
$table = new html_table();
$table->attributes['class'] = 'comparisontable';
$table->head = array('&nbsp;');
foreach ($roles as $role) {
$url = new moodle_url('/admin/roles/override.php', array('contextid' => $contextid, 'roleid' => $role->id));
$table->head[] = html_writer::div(html_writer::link($url, $role->localname));
}
$table->data = array();
foreach ($capabilities as $capability) {
$contexts = tool_capability_calculate_role_data($capability, $roles);
$captitle = new html_table_cell(get_capability_string($capability) . html_writer::span($capability));
$captitle->header = true;
$row = new html_table_row(array($captitle));
foreach ($roles as $role) {
if (isset($contexts[$contextid]->rolecapabilities[$role->id])) {
$permission = $contexts[$contextid]->rolecapabilities[$role->id];
} else {
$permission = CAP_INHERIT;
}
$cell = new html_table_cell($strpermissions[$permission]);
$cell->attributes['class'] = $permissionclasses[$permission];
$row->cells[] = $cell;
}
$table->data[] = $row;
}
// Start the list item, and print the context name as a link to the place to make changes.
if ($contextid == context_system::instance()->id) {
$url = new moodle_url('/admin/roles/manage.php');
$title = get_string('changeroles', 'tool_capability');
} else {
$url = new moodle_url('/admin/roles/override.php', array('contextid' => $contextid));
$title = get_string('changeoverrides', 'tool_capability');
}
$context = context::instance_by_id($contextid);
$html = $this->output->heading(html_writer::link($url, $context->get_context_name(), array('title' => $title)), 3);
$html .= html_writer::table($table);
// If there are any child contexts, print them recursively.
if (!empty($contexts[$contextid]->children)) {
foreach ($contexts[$contextid]->children as $childcontextid) {
$html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles, true);
}
}
return $html;
}
}

View File

@ -0,0 +1,32 @@
.path-admin-tool-capability .comparisontable {margin-top:150px;}
.path-admin-tool-capability .comparisontable th,
.path-admin-tool-capability .comparisontable td {vertical-align:middle;padding:0.4em 0.5em 0.3em;}
.path-admin-tool-capability .comparisontable thead th {vertical-align:bottom;background:none;}
.path-admin-tool-capability .comparisontable thead th div {position:relative;}
.path-admin-tool-capability .comparisontable thead th div > a {
position:absolute;
top:-1.75em;
left:1em;
width:150px;
text-align:left;
margin-bottom:1em;
text-indent:-1.45em;
-webkit-transform-origin: top left;
-moz-transform-origin: top left;
-ms-transform-origin: top left;
-o-transform-origin: top left;
-webkit-transform: rotate(315deg);
-moz-transform: rotate(315deg);
-ms-transform: rotate(315deg);
-o-transform: rotate(315deg);
}
.path-admin-tool-capability .comparisontable tbody th {background-color:#EEE;text-align:right;border:1px solid #DFDFDF;}
.path-admin-tool-capability .comparisontable tbody th span {display:block;color:#666;font-size:80%;}
.path-admin-tool-capability .comparisontable tbody td {border:1px solid #DFDFDF;}
.path-admin-tool-capability .comparisontable .inherit {color:#666;}
.path-admin-tool-capability .comparisontable .allow {color:#006600;font-weight:bold;}
.path-admin-tool-capability .comparisontable .prevent {color:#ad6704;font-weight:bold;}
.path-admin-tool-capability .comparisontable .prohibit {color:#880000;font-weight:bold;}

View File

@ -0,0 +1,151 @@
YUI.add('moodle-tool_capability-search', function (Y, NAME) {
/**
* This file contains the capability overview search functionality.
*
* @module moodle-tool_capability-search
*/
/**
* Constructs a new capability search manager.
*
* @namespace M.tool_capability.search
* @class Search
* @constructor
* @extends Y.Base
*/
var SEARCH = function() {
SEARCH.superclass.constructor.apply(this, arguments);
};
SEARCH.prototype = {
/**
* The search form.
* @property form
* @type Node
* @protected
*/
form : null,
/**
* The capability select node.
* @property select
* @type Node
* @protected
*/
select: null,
/**
* The search input field.
* @property input
* @type Node
* @protected
*/
input: null,
/**
* The submit button for the form.
* @property button
* @type Node
* @protected
*/
button: null,
/**
* The last search node if there is one.
* If there is a last search node then the last search term will be persisted between requests.
* @property lastsearch
* @type Node
* @protected
*/
lastsearch : null,
/**
* Constructs the search manager.
* @method initializer
*/
initializer : function() {
this.form = Y.one('#capability-overview-form');
this.select = this.form.one('select[data-search=capability]');
this.button = this.form.all('input[type=submit]');
this.lastsearch = this.form.one('input[name=search]');
var div = Y.Node.create('<div id="capabilitysearchui"></div>'),
label = Y.Node.create('<label for="capabilitysearch">'+this.get('strsearch')+'</label>');
this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
div.append(label).append(this.input);
this.select.insert(div, 'before');
this.select.one('option').setStyle('display', 'none');
this.input.on('keyup', this.typed, this);
this.select.on('change', this.validate, this);
if (this.lastsearch) {
this.input.set('value', this.lastsearch.get('value'));
this.typed();
this.select.set('scrollTop', this.select.one('option[selected]').get('getX'));
}
this.validate();
},
/**
* Disables the submit button if there are no capabilities selected.
* @method validate
*/
validate : function() {
this.button.set('disabled', (this.select.get('value') === ''));
},
/**
* Called when ever the user types into the search field.
* This method hides any capabilities that don't match the search term.
* @method typed
*/
typed : function() {
var search = this.input.get('value'),
options = this.select.get('options'),
matching = 0,
last = null;
if (this.lastsearch) {
this.lastsearch.set('value', search);
}
options.each(function(option){
if (option.get('text').indexOf(search) >= 0) {
matching++;
last = option;
option.set('disabled', false).setStyle('display', 'block');
} else {
option.set('disabled', true).set('selected', false).setStyle('display', 'none');
}
}, this);
if (matching === 0) {
this.input.addClass("error");
} else {
this.input.removeClass("error");
if (matching === 1) {
last.set('selected', true);
}
}
this.validate();
}
};
Y.extend(SEARCH, Y.Base, SEARCH.prototype, {
NAME : 'tool_capability-search',
ATTRS : {
strsearch : {}
}
});
/**
* Core namespace.
* @static
* @class tool_capability
*/
M.tool_capability = M.tool_capability || {};
/**
* Initialises capability search functionality.
* @static
* @method init_capability_search
* @param {Object} options
*/
M.tool_capability.init_capability_search = function(options) {
new SEARCH(options);
};
}, '@VERSION@', {"requires": ["base", "node"]});

View File

@ -0,0 +1 @@
YUI.add("moodle-tool_capability-search",function(e,t){var n=function(){n.superclass.constructor.apply(this,arguments)};n.prototype={form:null,select:null,input:null,button:null,lastsearch:null,initializer:function(){this.form=e.one("#capability-overview-form"),this.select=this.form.one("select[data-search=capability]"),this.button=this.form.all("input[type=submit]"),this.lastsearch=this.form.one("input[name=search]");var t=e.Node.create('<div id="capabilitysearchui"></div>'),n=e.Node.create('<label for="capabilitysearch">'+this.get("strsearch")+"</label>");this.input=e.Node.create('<input type="text" id="capabilitysearch" />'),t.append(n).append(this.input),this.select.insert(t,"before"),this.select.one("option").setStyle("display","none"),this.input.on("keyup",this.typed,this),this.select.on("change",this.validate,this),this.lastsearch&&(this.input.set("value",this.lastsearch.get("value")),this.typed(),this.select.set("scrollTop",this.select.one("option[selected]").get("getX"))),this.validate()},validate:function(){this.button.set("disabled",this.select.get("value")==="")},typed:function(){var e=this.input.get("value"),t=this.select.get("options"),n=0,r=null;this.lastsearch&&this.lastsearch.set("value",e),t.each(function(t){t.get("text").indexOf(e)>=0?(n++,r=t,t.set("disabled",!1).setStyle("display","block")):t.set("disabled",!0).set("selected",!1).setStyle("display","none")},this),n===0?this.input.addClass("error"):(this.input.removeClass("error"),n===1&&r.set("selected",!0)),this.validate()}},e.extend(n,e.Base,n.prototype,{NAME:"tool_capability-search",ATTRS:{strsearch:{}}}),M.tool_capability=M.tool_capability||{},M.tool_capability.init_capability_search=function(e){new n(e)}},"@VERSION@",{requires:["base","node"]});

View File

@ -0,0 +1,151 @@
YUI.add('moodle-tool_capability-search', function (Y, NAME) {
/**
* This file contains the capability overview search functionality.
*
* @module moodle-tool_capability-search
*/
/**
* Constructs a new capability search manager.
*
* @namespace M.tool_capability.search
* @class Search
* @constructor
* @extends Y.Base
*/
var SEARCH = function() {
SEARCH.superclass.constructor.apply(this, arguments);
};
SEARCH.prototype = {
/**
* The search form.
* @property form
* @type Node
* @protected
*/
form : null,
/**
* The capability select node.
* @property select
* @type Node
* @protected
*/
select: null,
/**
* The search input field.
* @property input
* @type Node
* @protected
*/
input: null,
/**
* The submit button for the form.
* @property button
* @type Node
* @protected
*/
button: null,
/**
* The last search node if there is one.
* If there is a last search node then the last search term will be persisted between requests.
* @property lastsearch
* @type Node
* @protected
*/
lastsearch : null,
/**
* Constructs the search manager.
* @method initializer
*/
initializer : function() {
this.form = Y.one('#capability-overview-form');
this.select = this.form.one('select[data-search=capability]');
this.button = this.form.all('input[type=submit]');
this.lastsearch = this.form.one('input[name=search]');
var div = Y.Node.create('<div id="capabilitysearchui"></div>'),
label = Y.Node.create('<label for="capabilitysearch">'+this.get('strsearch')+'</label>');
this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
div.append(label).append(this.input);
this.select.insert(div, 'before');
this.select.one('option').setStyle('display', 'none');
this.input.on('keyup', this.typed, this);
this.select.on('change', this.validate, this);
if (this.lastsearch) {
this.input.set('value', this.lastsearch.get('value'));
this.typed();
this.select.set('scrollTop', this.select.one('option[selected]').get('getX'));
}
this.validate();
},
/**
* Disables the submit button if there are no capabilities selected.
* @method validate
*/
validate : function() {
this.button.set('disabled', (this.select.get('value') === ''));
},
/**
* Called when ever the user types into the search field.
* This method hides any capabilities that don't match the search term.
* @method typed
*/
typed : function() {
var search = this.input.get('value'),
options = this.select.get('options'),
matching = 0,
last = null;
if (this.lastsearch) {
this.lastsearch.set('value', search);
}
options.each(function(option){
if (option.get('text').indexOf(search) >= 0) {
matching++;
last = option;
option.set('disabled', false).setStyle('display', 'block');
} else {
option.set('disabled', true).set('selected', false).setStyle('display', 'none');
}
}, this);
if (matching === 0) {
this.input.addClass("error");
} else {
this.input.removeClass("error");
if (matching === 1) {
last.set('selected', true);
}
}
this.validate();
}
};
Y.extend(SEARCH, Y.Base, SEARCH.prototype, {
NAME : 'tool_capability-search',
ATTRS : {
strsearch : {}
}
});
/**
* Core namespace.
* @static
* @class tool_capability
*/
M.tool_capability = M.tool_capability || {};
/**
* Initialises capability search functionality.
* @static
* @method init_capability_search
* @param {Object} options
*/
M.tool_capability.init_capability_search = function(options) {
new SEARCH(options);
};
}, '@VERSION@', {"requires": ["base", "node"]});

View File

@ -0,0 +1,10 @@
{
"name": "moodle-tool_capability-search",
"builds": {
"moodle-tool_capability-search": {
"jsfiles": [
"search.js"
]
}
}
}

View File

@ -0,0 +1,147 @@
/**
* This file contains the capability overview search functionality.
*
* @module moodle-tool_capability-search
*/
/**
* Constructs a new capability search manager.
*
* @namespace M.tool_capability.search
* @class Search
* @constructor
* @extends Y.Base
*/
var SEARCH = function() {
SEARCH.superclass.constructor.apply(this, arguments);
};
SEARCH.prototype = {
/**
* The search form.
* @property form
* @type Node
* @protected
*/
form : null,
/**
* The capability select node.
* @property select
* @type Node
* @protected
*/
select: null,
/**
* The search input field.
* @property input
* @type Node
* @protected
*/
input: null,
/**
* The submit button for the form.
* @property button
* @type Node
* @protected
*/
button: null,
/**
* The last search node if there is one.
* If there is a last search node then the last search term will be persisted between requests.
* @property lastsearch
* @type Node
* @protected
*/
lastsearch : null,
/**
* Constructs the search manager.
* @method initializer
*/
initializer : function() {
this.form = Y.one('#capability-overview-form');
this.select = this.form.one('select[data-search=capability]');
this.button = this.form.all('input[type=submit]');
this.lastsearch = this.form.one('input[name=search]');
var div = Y.Node.create('<div id="capabilitysearchui"></div>'),
label = Y.Node.create('<label for="capabilitysearch">'+this.get('strsearch')+'</label>');
this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
div.append(label).append(this.input);
this.select.insert(div, 'before');
this.select.one('option').setStyle('display', 'none');
this.input.on('keyup', this.typed, this);
this.select.on('change', this.validate, this);
if (this.lastsearch) {
this.input.set('value', this.lastsearch.get('value'));
this.typed();
this.select.set('scrollTop', this.select.one('option[selected]').get('getX'));
}
this.validate();
},
/**
* Disables the submit button if there are no capabilities selected.
* @method validate
*/
validate : function() {
this.button.set('disabled', (this.select.get('value') === ''));
},
/**
* Called when ever the user types into the search field.
* This method hides any capabilities that don't match the search term.
* @method typed
*/
typed : function() {
var search = this.input.get('value'),
options = this.select.get('options'),
matching = 0,
last = null;
if (this.lastsearch) {
this.lastsearch.set('value', search);
}
options.each(function(option){
if (option.get('text').indexOf(search) >= 0) {
matching++;
last = option;
option.set('disabled', false).setStyle('display', 'block');
} else {
option.set('disabled', true).set('selected', false).setStyle('display', 'none');
}
}, this);
if (matching === 0) {
this.input.addClass("error");
} else {
this.input.removeClass("error");
if (matching === 1) {
last.set('selected', true);
}
}
this.validate();
}
};
Y.extend(SEARCH, Y.Base, SEARCH.prototype, {
NAME : 'tool_capability-search',
ATTRS : {
strsearch : {}
}
});
/**
* Core namespace.
* @static
* @class tool_capability
*/
M.tool_capability = M.tool_capability || {};
/**
* Initialises capability search functionality.
* @static
* @method init_capability_search
* @param {Object} options
*/
M.tool_capability.init_capability_search = function(options) {
new SEARCH(options);
};

View File

@ -0,0 +1,8 @@
{
"moodle-tool_capability-search": {
"requires": [
"base",
"node"
]
}
}