Merge branch 'master' into install_master
@@ -59,6 +59,10 @@ if (empty($_GET['cache']) and empty($_POST['cache']) and empty($_GET['sesskey'])
|
||||
if (function_exists('opcache_reset')) {
|
||||
opcache_reset();
|
||||
}
|
||||
$cache = 0;
|
||||
|
||||
} else {
|
||||
$cache = 1;
|
||||
}
|
||||
|
||||
require('../config.php');
|
||||
@@ -74,22 +78,28 @@ $showallplugins = optional_param('showallplugins', 0, PARAM_BOOL);
|
||||
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
|
||||
$fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL);
|
||||
$newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW);
|
||||
$cache = optional_param('cache', 0, PARAM_BOOL);
|
||||
|
||||
// Set up PAGE.
|
||||
$url = new moodle_url('/admin/index.php');
|
||||
if (!is_null($newaddonreq)) {
|
||||
// We need to set the eventual add-on installation request in the $PAGE's URL
|
||||
// so that it is stored in $SESSION->wantsurl and the admin is redirected
|
||||
// correctly once they are logged-in.
|
||||
$url->param('installaddonrequest', $newaddonreq);
|
||||
}
|
||||
if ($cache) {
|
||||
$url->param('cache', $cache);
|
||||
$url->param('cache', 1);
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
unset($url);
|
||||
|
||||
// Are we returning from an add-on installation request at moodle.org/plugins?
|
||||
if ($newaddonreq and !$cache and empty($CFG->disableonclickaddoninstall)) {
|
||||
$target = new moodle_url('/admin/tool/installaddon/index.php', array(
|
||||
'installaddonrequest' => $newaddonreq,
|
||||
'confirm' => 0));
|
||||
if (!isloggedin() or isguestuser()) {
|
||||
// Login and go the the add-on tool page.
|
||||
$SESSION->wantsurl = $target->out();
|
||||
redirect(get_login_url());
|
||||
}
|
||||
redirect($target);
|
||||
}
|
||||
|
||||
$PAGE->set_pagelayout('admin'); // Set a default pagelayout
|
||||
|
||||
$documentationlink = '<a href="http://docs.moodle.org/en/Installation">Installation docs</a>';
|
||||
@@ -153,6 +163,7 @@ if (!core_tables_exist()) {
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->install_licence_page();
|
||||
die();
|
||||
@@ -167,6 +178,7 @@ if (!core_tables_exist()) {
|
||||
$PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->install_environment_page($maturity, $envstatus, $environment_results, $release);
|
||||
die();
|
||||
@@ -221,14 +233,12 @@ if (empty($CFG->version)) {
|
||||
}
|
||||
|
||||
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
|
||||
if ($cache) {
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name'=>'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url('/admin/index.php'), 'Config cache inconsistency detected, resetting caches...');
|
||||
}
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name'=>'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url('/admin/index.php'), 'Config cache inconsistency detected, resetting caches...');
|
||||
}
|
||||
|
||||
if ($version > $CFG->version) { // upgrade
|
||||
if (!$cache and $version > $CFG->version) { // upgrade
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
@@ -245,6 +255,7 @@ if ($version > $CFG->version) { // upgrade
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->upgrade_stale_php_files_page();
|
||||
die();
|
||||
@@ -260,6 +271,7 @@ if ($version > $CFG->version) { // upgrade
|
||||
$PAGE->set_heading($strdatabasechecking);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->upgrade_confirm_page($a->newversion, $maturity);
|
||||
die();
|
||||
@@ -274,6 +286,7 @@ if ($version > $CFG->version) { // upgrade
|
||||
$PAGE->set_heading($strcurrentrelease);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environment_results);
|
||||
die();
|
||||
@@ -288,10 +301,12 @@ if ($version > $CFG->version) { // upgrade
|
||||
|
||||
$reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1));
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
// check plugin dependencies first
|
||||
$failed = array();
|
||||
if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
die();
|
||||
}
|
||||
@@ -305,8 +320,6 @@ if ($version > $CFG->version) { // upgrade
|
||||
redirect($reloadurl);
|
||||
}
|
||||
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$deployer = available_update_deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$deployer->initialize($reloadurl, $reloadurl);
|
||||
@@ -333,15 +346,15 @@ if ($version > $CFG->version) { // upgrade
|
||||
}
|
||||
|
||||
// Updated human-readable release version if necessary
|
||||
if ($release <> $CFG->release) { // Update the release version
|
||||
if (!$cache and $release <> $CFG->release) { // Update the release version
|
||||
set_config('release', $release);
|
||||
}
|
||||
|
||||
if ($branch <> $CFG->branch) { // Update the branch
|
||||
if (!$cache and $branch <> $CFG->branch) { // Update the branch
|
||||
set_config('branch', $branch);
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
if (!$cache and moodle_needs_upgrading()) {
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
if (!$confirmplugins) {
|
||||
@@ -450,8 +463,8 @@ if (during_initial_install()) {
|
||||
|
||||
// Now we can be sure everything was upgraded and caches work fine,
|
||||
// redirect if necessary to make sure caching is enabled.
|
||||
if (!$cache and !optional_param('sesskey', '', PARAM_RAW)) {
|
||||
redirect(new moodle_url($PAGE->url, array('cache' => 1)));
|
||||
if (!$cache) {
|
||||
redirect(new moodle_url('/admin/index.php', array('cache' => 1)));
|
||||
}
|
||||
|
||||
// Check for valid admin user - no guest autologin
|
||||
@@ -473,17 +486,6 @@ if (!empty($id) and $id == $CFG->siteidentifier) {
|
||||
set_config('registered', time());
|
||||
}
|
||||
|
||||
// Check if we are returning from an add-on installation request at moodle.org/plugins
|
||||
if (!is_null($newaddonreq)) {
|
||||
if (!empty($CFG->disableonclickaddoninstall)) {
|
||||
// The feature is disabled in config.php, ignore the request.
|
||||
} else {
|
||||
redirect(new moodle_url('/admin/tool/installaddon/index.php', array(
|
||||
'installaddonrequest' => $newaddonreq,
|
||||
'confirm' => 0)));
|
||||
}
|
||||
}
|
||||
|
||||
// setup critical warnings before printing admin tree block
|
||||
$insecuredataroot = is_dataroot_insecure(true);
|
||||
$SESSION->admin_critical_warning = ($insecuredataroot==INSECURE_DATAROOT_ERROR);
|
||||
|
||||
@@ -38,9 +38,6 @@ require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/pluginlib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
|
||||
$fetchremote = optional_param('fetchremote', false, PARAM_BOOL);
|
||||
$updatesonly = optional_param('updatesonly', false, PARAM_BOOL);
|
||||
$contribonly = optional_param('contribonly', false, PARAM_BOOL);
|
||||
@@ -48,12 +45,30 @@ $uninstall = optional_param('uninstall', '', PARAM_COMPONENT);
|
||||
$delete = optional_param('delete', '', PARAM_COMPONENT);
|
||||
$confirmed = optional_param('confirm', false, PARAM_BOOL);
|
||||
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
// NOTE: do not use admin_externalpage_setup() here because it loads
|
||||
// full admin tree which is not possible during uninstallation.
|
||||
|
||||
require_login();
|
||||
$syscontext = context_system::instance();
|
||||
require_capability('moodle/site:config', $syscontext);
|
||||
|
||||
$pluginman = plugin_manager::instance();
|
||||
|
||||
if ($uninstall) {
|
||||
require_sesskey();
|
||||
|
||||
if (!$confirmed) {
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
} else {
|
||||
$PAGE->set_url('/admin/plugins.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
}
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$pluginfo = $pluginman->get_plugin_info($uninstall);
|
||||
|
||||
// Make sure we know the plugin.
|
||||
@@ -104,6 +119,15 @@ if ($uninstall) {
|
||||
|
||||
if ($delete and $confirmed) {
|
||||
require_sesskey();
|
||||
|
||||
$PAGE->set_url('/admin/plugins.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$pluginfo = $pluginman->get_plugin_info($delete);
|
||||
|
||||
// Make sure we know the plugin.
|
||||
@@ -143,9 +167,15 @@ if ($delete and $confirmed) {
|
||||
if (function_exists('opcache_reset')) {
|
||||
opcache_reset();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
// We need to execute upgrade to make sure everything including caches is up to date.
|
||||
redirect(new moodle_url('/admin/index.php'));
|
||||
}
|
||||
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$checker = available_update_checker::instance();
|
||||
|
||||
// Filtering options.
|
||||
|
||||
@@ -140,12 +140,13 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
public function upgrade_confirm_page($strnewversion, $maturity) {
|
||||
$output = '';
|
||||
|
||||
$continueurl = new moodle_url('index.php', array('confirmupgrade' => 1));
|
||||
$cancelurl = new moodle_url('index.php');
|
||||
$continueurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1));
|
||||
$continue = new single_button($continueurl, get_string('continue'), 'get');
|
||||
$cancelurl = new moodle_url('/admin/index.php');
|
||||
|
||||
$output .= $this->header();
|
||||
$output .= $this->maturity_warning($maturity);
|
||||
$output .= $this->confirm(get_string('upgradesure', 'admin', $strnewversion), $continueurl, $cancelurl);
|
||||
$output .= $this->confirm(get_string('upgradesure', 'admin', $strnewversion), $continue, $cancelurl);
|
||||
$output .= $this->footer();
|
||||
|
||||
return $output;
|
||||
@@ -412,6 +413,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$pluginname = $pluginman->plugin_name($pluginfo->component);
|
||||
|
||||
// Do not show navigation here, they must click one of the buttons.
|
||||
$this->page->set_pagelayout('maintenance');
|
||||
$this->page->set_cacheable(false);
|
||||
|
||||
$output .= $this->output->header();
|
||||
$output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
|
||||
|
||||
@@ -425,7 +430,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
'uninstalldeleteconfirmexternal');
|
||||
}
|
||||
|
||||
$output .= $this->output->confirm($confirm, $continueurl, $this->page->url);
|
||||
// After any uninstall we must execute full upgrade to finish the cleanup!
|
||||
$output .= $this->output->confirm($confirm, $continueurl, new moodle_url('/admin/index.php'));
|
||||
$output .= $this->output->footer();
|
||||
|
||||
return $output;
|
||||
@@ -442,7 +448,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
public function plugin_uninstall_results_page(plugin_manager $pluginman, plugininfo_base $pluginfo, progress_trace_buffer $progress) {
|
||||
$output = '';
|
||||
|
||||
$pluginname = $pluginman->plugin_name($pluginfo->component);
|
||||
$pluginname = $pluginfo->component;
|
||||
|
||||
$output .= $this->output->header();
|
||||
$output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
|
||||
@@ -451,7 +457,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$output .= $this->output->box(get_string('uninstalldelete', 'core_plugin',
|
||||
array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'generalbox uninstalldelete');
|
||||
$output .= $this->output->continue_button($this->page->url);
|
||||
$output .= $this->output->continue_button(new moodle_url('/admin/index.php'));
|
||||
$output .= $this->output->footer();
|
||||
|
||||
return $output;
|
||||
@@ -708,7 +714,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
if (!$registered) {
|
||||
|
||||
$registerbutton = $this->single_button(new moodle_url('registration/register.php',
|
||||
$registerbutton = $this->single_button(new moodle_url('/admin/registration/register.php',
|
||||
array('huburl' => HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.org')),
|
||||
get_string('register', 'admin'));
|
||||
|
||||
|
||||
@@ -1646,8 +1646,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
// Now start the whole NTLM machinery.
|
||||
if($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESATTEMPT ||
|
||||
$this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) {
|
||||
|
||||
if(check_browser_version('MSIE')) {
|
||||
if (core_useragent::check_ie_version()) {
|
||||
$sesskey = sesskey();
|
||||
redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_magic.php?sesskey='.$sesskey);
|
||||
} else if ($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) {
|
||||
|
||||
@@ -28,7 +28,7 @@ $file = $CFG->dirroot.'/pix/spacer.gif';
|
||||
|
||||
if ($authplugin->ntlmsso_magic($sesskey) && file_exists($file)) {
|
||||
if (!empty($authplugin->config->ntlmsso_ie_fastpath)) {
|
||||
if (check_browser_version('MSIE')) {
|
||||
if (core_useragent::check_ie_version()) {
|
||||
// $PAGE->https_required() up above takes care of what $CFG->httpswwwroot should be.
|
||||
redirect($CFG->httpswwwroot.'/auth/ldap/ntlmsso_finish.php');
|
||||
}
|
||||
|
||||
@@ -1421,6 +1421,12 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
$data->theme = '';
|
||||
}
|
||||
|
||||
// Check if this is an old SCORM course format.
|
||||
if ($data->format == 'scorm') {
|
||||
$data->format = 'singleactivity';
|
||||
$data->activitytype = 'scorm';
|
||||
}
|
||||
|
||||
// Course record ready, update it
|
||||
$DB->update_record('course', $data);
|
||||
|
||||
@@ -3624,7 +3630,7 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
|
||||
// Iterate over aliases in the queue.
|
||||
foreach ($rs as $record) {
|
||||
$info = restore_dbops::decode_backup_temp_info($record->info);
|
||||
$info = backup_controller_dbops::decode_backup_temp_info($record->info);
|
||||
|
||||
// Try to pick a repository instance that should serve the alias.
|
||||
$repository = $this->choose_repository($info);
|
||||
|
||||
@@ -59,7 +59,7 @@ class database_logger extends base_logger {
|
||||
if ($this->levelcol) {
|
||||
$columns[$this->levelcol] = $level;
|
||||
}
|
||||
$columns[$this->messagecol] = $message; //TODO: should this be cleaned?
|
||||
$columns[$this->messagecol] = clean_param($message, PARAM_NOTAGS);
|
||||
return $this->insert_log_record($this->logtable, $columns);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,6 @@ class database_logger extends base_logger {
|
||||
// to preserve DB logs if the whole backup/restore transaction is
|
||||
// rollback
|
||||
global $DB;
|
||||
return $DB->insert_record($this->logtable, $columns, false); // Don't return inserted id
|
||||
return $DB->insert_record($table, $columns, false); // Don't return inserted id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class backup_base_optigroup_testcase extends basic_testcase {
|
||||
/**
|
||||
* Incorrect creation tests (attributes and final elements)
|
||||
*/
|
||||
function itest_wrong_creation() {
|
||||
function test_wrong_creation() {
|
||||
|
||||
// Create instance with invalid name
|
||||
try {
|
||||
|
||||
@@ -140,7 +140,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
}
|
||||
if (empty($table)) {
|
||||
$table = new html_table();
|
||||
$table->head = array('Module', 'Title', 'Userinfo');
|
||||
$table->head = array(get_string('module','backup'), get_string('title','backup'), get_string('userinfo','backup'));
|
||||
$table->colclasses = array('modulename', 'moduletitle', 'userinfoincluded');
|
||||
$table->align = array('left','left', 'center');
|
||||
$table->attributes = array('class'=>'activitytable generaltable');
|
||||
|
||||
@@ -100,13 +100,6 @@ Feature: Restore Moodle 2 course backups
|
||||
And I follow "Edit settings"
|
||||
And I expand all fieldsets
|
||||
And the "id_format" field should match "Social format" value
|
||||
And I fill the moodle form with:
|
||||
| id_format | SCORM format |
|
||||
And I press "Save changes"
|
||||
And I should see "Adding a new SCORM package"
|
||||
And I follow "Edit settings"
|
||||
And I expand all fieldsets
|
||||
And the "id_format" field should match "SCORM format" value
|
||||
And I press "Cancel"
|
||||
|
||||
@javascript
|
||||
|
||||
@@ -595,8 +595,9 @@ class blog_listing {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
|
||||
$allnamefields = get_all_user_name_fields(true, 'u');
|
||||
// The query used to locate blog entries is complicated. It will be built from the following components:
|
||||
$requiredfields = "p.*, u.firstname, u.lastname, u.email"; // the SELECT clause
|
||||
$requiredfields = "p.*, $allnamefields, u.email"; // the SELECT clause
|
||||
$tables = array('p' => 'post', 'u' => 'user'); // components of the FROM clause (table_id => table_name)
|
||||
$conditions = array('u.deleted = 0', 'p.userid = u.id', '(p.module = \'blog\' OR p.module = \'blog_external\')'); // components of the WHERE clause (conjunction)
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ class cache implements cache_loader {
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param int $strictness One of IGNORE_MISSING | MUST_EXIST
|
||||
* @return mixed|false The data from the cache or false if the key did not exist within the cache.
|
||||
* @throws moodle_exception
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get($key, $strictness = IGNORE_MISSING) {
|
||||
// 1. Parse the key.
|
||||
@@ -329,7 +329,7 @@ class cache implements cache_loader {
|
||||
}
|
||||
// 5. Validate strictness.
|
||||
if ($strictness === MUST_EXIST && $result === false) {
|
||||
throw new moodle_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
}
|
||||
// 6. Set it to the store if we got it from the loader/datasource.
|
||||
if ($setaftervalidation) {
|
||||
@@ -363,7 +363,7 @@ class cache implements cache_loader {
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
* @throws moodle_exception
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING) {
|
||||
|
||||
@@ -420,7 +420,7 @@ class cache implements cache_loader {
|
||||
$missingkeys = array();
|
||||
foreach ($result as $key => $value) {
|
||||
if ($value === false) {
|
||||
$missingkeys[] = ($usingloader) ? $key : $parsedkeys[$key];
|
||||
$missingkeys[] = $parsedkeys[$key];
|
||||
}
|
||||
}
|
||||
if (!empty($missingkeys)) {
|
||||
@@ -430,11 +430,9 @@ class cache implements cache_loader {
|
||||
$resultmissing = $this->datasource->load_many_for_cache($missingkeys);
|
||||
}
|
||||
foreach ($resultmissing as $key => $value) {
|
||||
$pkey = ($usingloader) ? $key : $keysparsed[$key];
|
||||
$realkey = ($usingloader) ? $parsedkeys[$key] : $key;
|
||||
$result[$pkey] = $value;
|
||||
$result[$keysparsed[$key]] = $value;
|
||||
if ($value !== false) {
|
||||
$this->set($realkey, $value);
|
||||
$this->set($key, $value);
|
||||
}
|
||||
}
|
||||
unset($resultmissing);
|
||||
@@ -453,7 +451,7 @@ class cache implements cache_loader {
|
||||
if ($strictness === MUST_EXIST) {
|
||||
foreach ($keys as $key) {
|
||||
if (!array_key_exists($key, $fullresult)) {
|
||||
throw new moodle_exception('Not all the requested keys existed within the cache stores.');
|
||||
throw new coding_exception('Not all the requested keys existed within the cache stores.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,6 +481,11 @@ class cache implements cache_loader {
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set($this->storetype, $this->definition->get_id());
|
||||
}
|
||||
if ($this->loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$this->loader->set($key, $data);
|
||||
}
|
||||
if (is_object($data) && $data instanceof cacheable_object) {
|
||||
$data = new cache_cached_object($data);
|
||||
} else if (!is_scalar($data)) {
|
||||
@@ -506,6 +509,7 @@ class cache implements cache_loader {
|
||||
* Removes references where required.
|
||||
*
|
||||
* @param stdClass|array $data
|
||||
* @return mixed What ever was put in but without any references.
|
||||
*/
|
||||
protected function unref($data) {
|
||||
if ($this->definition->uses_simple_data()) {
|
||||
@@ -593,6 +597,11 @@ class cache implements cache_loader {
|
||||
* ... if they care that is.
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
if ($this->loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$this->loader->set_many($keyvaluearray);
|
||||
}
|
||||
$data = array();
|
||||
$simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
|
||||
$usepersistcache = $this->is_using_persist_cache();
|
||||
@@ -858,7 +867,7 @@ class cache implements cache_loader {
|
||||
* Returns the loader associated with this instance.
|
||||
*
|
||||
* @since 2.4.4
|
||||
* @return cache_loader|false
|
||||
* @return cache|false
|
||||
*/
|
||||
protected function get_loader() {
|
||||
return $this->loader;
|
||||
@@ -1340,7 +1349,6 @@ class cache_application extends cache implements cache_loader_with_locking {
|
||||
* @param string|int $key The key for the data being requested.
|
||||
* @param int $strictness One of IGNORE_MISSING | MUST_EXIST
|
||||
* @return mixed|false The data from the cache or false if the key did not exist within the cache.
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public function get($key, $strictness = IGNORE_MISSING) {
|
||||
if ($this->requirelockingread && $this->check_lock_state($key) === false) {
|
||||
@@ -1364,7 +1372,7 @@ class cache_application extends cache implements cache_loader_with_locking {
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
* @throws moodle_exception
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING) {
|
||||
if ($this->requirelockingread) {
|
||||
@@ -1458,6 +1466,7 @@ class cache_application extends cache implements cache_loader_with_locking {
|
||||
* @todo we should support locking in the session as well. Should be pretty simple to set up.
|
||||
*
|
||||
* @internal don't use me directly.
|
||||
* @method cache_store|cache_is_searchable get_store() Returns the cache store which must implement both cache_is_searchable.
|
||||
*
|
||||
* @package core
|
||||
* @category cache
|
||||
@@ -1494,6 +1503,11 @@ class cache_session extends cache {
|
||||
*/
|
||||
const KEY_PREFIX = 'sess_';
|
||||
|
||||
/**
|
||||
* This is the key used to track last access.
|
||||
*/
|
||||
const LASTACCESS = '__lastaccess__';
|
||||
|
||||
/**
|
||||
* Override the cache::construct method.
|
||||
*
|
||||
@@ -1507,12 +1521,15 @@ class cache_session extends cache {
|
||||
* @param cache_definition $definition
|
||||
* @param cache_store $store
|
||||
* @param cache_loader|cache_data_source $loader
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
|
||||
// First up copy the loadeduserid to the current user id.
|
||||
$this->currentuserid = self::$loadeduserid;
|
||||
parent::__construct($definition, $store, $loader);
|
||||
|
||||
// This will trigger check tracked user. If this gets removed a call to that will need to be added here in its place.
|
||||
$this->set(self::LASTACCESS, cache::now());
|
||||
|
||||
if ($definition->has_invalidation_events()) {
|
||||
$lastinvalidation = $this->get('lastsessioninvalidation');
|
||||
if ($lastinvalidation === false) {
|
||||
@@ -1561,6 +1578,21 @@ class cache_session extends cache {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session id for the loader.
|
||||
*/
|
||||
protected function set_session_id() {
|
||||
$this->sessionid = preg_replace('#[^a-zA-Z0-9_]#', '_', session_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix used for all keys.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_key_prefix() {
|
||||
return 'u'.$this->currentuserid.'_'.$this->sessionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the key turning it into a string (or array is required) suitable to be passed to the cache store.
|
||||
*
|
||||
@@ -1573,17 +1605,18 @@ class cache_session extends cache {
|
||||
* @return string|array String unless the store supports multi-identifiers in which case an array if returned.
|
||||
*/
|
||||
protected function parse_key($key) {
|
||||
if ($key === 'lastaccess') {
|
||||
$key = '__lastaccess__';
|
||||
$prefix = $this->get_key_prefix();
|
||||
if ($key === self::LASTACCESS) {
|
||||
return $key.$prefix;
|
||||
}
|
||||
return 'sess_'.parent::parse_key($key);
|
||||
return $prefix.'_'.parent::parse_key($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that this cache instance is tracking the current user.
|
||||
*/
|
||||
protected function check_tracked_user() {
|
||||
if (isset($_SESSION['USER']->id)) {
|
||||
if (isset($_SESSION['USER']->id) && $_SESSION['USER']->id !== null) {
|
||||
// Get the id of the current user.
|
||||
$new = $_SESSION['USER']->id;
|
||||
} else {
|
||||
@@ -1597,55 +1630,25 @@ class cache_session extends cache {
|
||||
// This way we don't bloat the session.
|
||||
$this->purge();
|
||||
// Update the session id just in case!
|
||||
$this->sessionid = session_id();
|
||||
$this->set_session_id();
|
||||
}
|
||||
self::$loadeduserid = $new;
|
||||
$this->currentuserid = $new;
|
||||
} else if ($new !== $this->currentuserid) {
|
||||
// The current user matches the loaded user but not the user last used by this cache.
|
||||
$this->purge();
|
||||
$this->purge_current_user();
|
||||
$this->currentuserid = $new;
|
||||
// Update the session id just in case!
|
||||
$this->sessionid = session_id();
|
||||
$this->set_session_id();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session data.
|
||||
*
|
||||
* @param bool $force If true the session data will be loaded from the store again.
|
||||
* @return array An array of session data.
|
||||
* Purges the session cache of all data belonging to the current user.
|
||||
*/
|
||||
protected function get_session_data($force = false) {
|
||||
if ($this->sessionid === null) {
|
||||
$this->sessionid = session_id();
|
||||
}
|
||||
if (is_array($this->session) && !$force) {
|
||||
return $this->session;
|
||||
}
|
||||
$session = parent::get($this->sessionid);
|
||||
if ($session === false) {
|
||||
$session = array();
|
||||
}
|
||||
// We have to write here to ensure that the lastaccess time is recorded.
|
||||
// And also in order to ensure the session entry exists as when we save it on __destruct
|
||||
// $CFG is likely to have already been destroyed.
|
||||
$this->save_session($session);
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the session data.
|
||||
*
|
||||
* This function also updates the last access time.
|
||||
*
|
||||
* @param array $session
|
||||
* @return bool
|
||||
*/
|
||||
protected function save_session(array $session) {
|
||||
$session['lastaccess'] = time();
|
||||
$this->session = $session;
|
||||
return parent::set($this->sessionid, $this->session);
|
||||
public function purge_current_user() {
|
||||
$keys = $this->get_store()->find_all($this->get_key_prefix());
|
||||
$this->get_store()->delete_many($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1656,7 +1659,7 @@ class cache_session extends cache {
|
||||
* In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
|
||||
* @param int $strictness One of IGNORE_MISSING | MUST_EXIST
|
||||
* @return mixed|false The data from the cache or false if the key did not exist within the cache.
|
||||
* @throws moodle_exception
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get($key, $strictness = IGNORE_MISSING) {
|
||||
// Check the tracked user.
|
||||
@@ -1664,10 +1667,8 @@ class cache_session extends cache {
|
||||
// 2. Parse the key.
|
||||
$parsedkey = $this->parse_key($key);
|
||||
// 3. Get it from the store.
|
||||
$result = false;
|
||||
$session = $this->get_session_data();
|
||||
if (array_key_exists($parsedkey, $session)) {
|
||||
$result = $session[$parsedkey];
|
||||
$result = $this->get_store()->get($parsedkey);
|
||||
if ($result !== false) {
|
||||
if ($result instanceof cache_ttl_wrapper) {
|
||||
if ($result->has_expired()) {
|
||||
$this->get_store()->delete($parsedkey);
|
||||
@@ -1681,10 +1682,9 @@ class cache_session extends cache {
|
||||
}
|
||||
}
|
||||
// 4. Load if from the loader/datasource if we don't already have it.
|
||||
$setaftervalidation = false;
|
||||
if ($result === false) {
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_miss('**static session**', $this->get_definition()->get_id());
|
||||
cache_helper::record_cache_miss($this->storetype, $this->get_definition()->get_id());
|
||||
}
|
||||
if ($this->get_loader() !== false) {
|
||||
// We must pass the original (unparsed) key to the next loader in the chain.
|
||||
@@ -1694,19 +1694,18 @@ class cache_session extends cache {
|
||||
} else if ($this->get_datasource() !== false) {
|
||||
$result = $this->get_datasource()->load_for_cache($key);
|
||||
}
|
||||
$setaftervalidation = ($result !== false);
|
||||
// 5. Set it to the store if we got it from the loader/datasource.
|
||||
if ($result !== false) {
|
||||
$this->set($key, $result);
|
||||
}
|
||||
} else if ($this->perfdebug) {
|
||||
cache_helper::record_cache_hit('**static session**', $this->get_definition()->get_id());
|
||||
cache_helper::record_cache_hit($this->storetype, $this->get_definition()->get_id());
|
||||
}
|
||||
// 5. Validate strictness.
|
||||
if ($strictness === MUST_EXIST && $result === false) {
|
||||
throw new moodle_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
}
|
||||
// 6. Set it to the store if we got it from the loader/datasource.
|
||||
if ($setaftervalidation) {
|
||||
$this->set($key, $result);
|
||||
}
|
||||
// 7. Make sure we don't pass back anything that could be a reference.
|
||||
// 6. Make sure we don't pass back anything that could be a reference.
|
||||
// We don't want people modifying the data in the cache.
|
||||
if (!is_scalar($result)) {
|
||||
// If data is an object it will be a reference.
|
||||
@@ -1737,8 +1736,14 @@ class cache_session extends cache {
|
||||
*/
|
||||
public function set($key, $data) {
|
||||
$this->check_tracked_user();
|
||||
$loader = $this->get_loader();
|
||||
if ($loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$loader->set($key, $data);
|
||||
}
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set('**static session**', $this->get_definition()->get_id());
|
||||
cache_helper::record_cache_set($this->storetype, $this->get_definition()->get_id());
|
||||
}
|
||||
if (is_object($data) && $data instanceof cacheable_object) {
|
||||
$data = new cache_cached_object($data);
|
||||
@@ -1750,12 +1755,10 @@ class cache_session extends cache {
|
||||
$data = $this->unref($data);
|
||||
}
|
||||
// We dont' support native TTL here as we consolidate data for sessions.
|
||||
if ($this->has_a_ttl()) {
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
$data = new cache_ttl_wrapper($data, $this->get_definition()->get_ttl());
|
||||
}
|
||||
$session = $this->get_session_data();
|
||||
$session[$this->parse_key($key)] = $data;
|
||||
return $this->save_session($session);
|
||||
return $this->get_store()->set($this->parse_key($key), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1767,15 +1770,12 @@ class cache_session extends cache {
|
||||
* @return bool True of success, false otherwise.
|
||||
*/
|
||||
public function delete($key, $recurse = true) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkey = $this->parse_key($key);
|
||||
if ($recurse && $this->get_loader() !== false) {
|
||||
// Delete from the bottom of the stack first.
|
||||
$this->get_loader()->delete($key, $recurse);
|
||||
}
|
||||
$session = $this->get_session_data();
|
||||
unset($session[$parsedkey]);
|
||||
return $this->save_session($session);
|
||||
return $this->get_store()->delete($parsedkey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1794,15 +1794,72 @@ class cache_session extends cache {
|
||||
* @return array An array of key value pairs for the items that could be retrieved from the cache.
|
||||
* If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
|
||||
* Otherwise any key that did not exist will have a data value of false within the results.
|
||||
* @throws moodle_exception
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_many(array $keys, $strictness = IGNORE_MISSING) {
|
||||
$this->check_tracked_user();
|
||||
$return = array();
|
||||
$parsedkeys = array();
|
||||
$keymap = array();
|
||||
foreach ($keys as $key) {
|
||||
$return[$key] = $this->get($key, $strictness);
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$parsedkeys[$key] = $parsedkey;
|
||||
$keymap[$parsedkey] = $key;
|
||||
}
|
||||
$result = $this->get_store()->get_many($parsedkeys);
|
||||
$return = array();
|
||||
$missingkeys = array();
|
||||
$hasmissingkeys = false;
|
||||
foreach ($result as $parsedkey => $value) {
|
||||
$key = $keymap[$parsedkey];
|
||||
if ($value instanceof cache_ttl_wrapper) {
|
||||
/* @var cache_ttl_wrapper $value */
|
||||
if ($value->has_expired()) {
|
||||
$this->delete($keymap[$parsedkey]);
|
||||
$value = false;
|
||||
} else {
|
||||
$value = $value->data;
|
||||
}
|
||||
}
|
||||
if ($value instanceof cache_cached_object) {
|
||||
/* @var cache_cached_object $value */
|
||||
$value = $value->restore_object();
|
||||
}
|
||||
$return[$key] = $value;
|
||||
if ($value === false) {
|
||||
$hasmissingkeys = true;
|
||||
$missingkeys[$parsedkey] = $key;
|
||||
}
|
||||
}
|
||||
if ($hasmissingkeys) {
|
||||
// We've got missing keys - we've got to check any loaders or data sources.
|
||||
$loader = $this->get_loader();
|
||||
$datasource = $this->get_datasource();
|
||||
if ($loader !== false) {
|
||||
foreach ($loader->get_many($missingkeys) as $key => $value) {
|
||||
if ($value !== false) {
|
||||
$return[$key] = $value;
|
||||
unset($missingkeys[$parsedkeys[$key]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$hasmissingkeys = count($missingkeys) > 0;
|
||||
if ($datasource !== false && $hasmissingkeys) {
|
||||
// We're still missing keys but we've got a datasource.
|
||||
foreach ($datasource->load_many_for_cache($missingkeys) as $key => $value) {
|
||||
if ($value !== false) {
|
||||
$return[$key] = $value;
|
||||
unset($missingkeys[$parsedkeys[$key]]);
|
||||
}
|
||||
}
|
||||
$hasmissingkeys = count($missingkeys) > 0;
|
||||
}
|
||||
}
|
||||
if ($hasmissingkeys && $strictness === MUST_EXIST) {
|
||||
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1814,18 +1871,12 @@ class cache_session extends cache {
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys, $recurse = true) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkeys = array_map(array($this, 'parse_key'), $keys);
|
||||
if ($recurse && $this->get_loader() !== false) {
|
||||
// Delete from the bottom of the stack first.
|
||||
$this->get_loader()->delete_many($keys, $recurse);
|
||||
}
|
||||
$session = $this->get_session_data();
|
||||
foreach ($parsedkeys as $parsedkey) {
|
||||
unset($session[$parsedkey]);
|
||||
}
|
||||
$this->save_session($session);
|
||||
return count($keys);
|
||||
return $this->get_store()->delete_many($parsedkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1853,8 +1904,15 @@ class cache_session extends cache {
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
$this->check_tracked_user();
|
||||
$session = $this->get_session_data();
|
||||
$simulatettl = $this->has_a_ttl();
|
||||
$loader = $this->get_loader();
|
||||
if ($loader !== false) {
|
||||
// We have a loader available set it there as well.
|
||||
// We have to let the loader do its own parsing of data as it may be unique.
|
||||
$loader->set_many($keyvaluearray);
|
||||
}
|
||||
$data = array();
|
||||
$definitionid = $this->get_definition()->get_ttl();
|
||||
$simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
|
||||
foreach ($keyvaluearray as $key => $value) {
|
||||
if (is_object($value) && $value instanceof cacheable_object) {
|
||||
$value = new cache_cached_object($value);
|
||||
@@ -1866,16 +1924,17 @@ class cache_session extends cache {
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
if ($simulatettl) {
|
||||
$value = new cache_ttl_wrapper($value, $this->get_definition()->get_ttl());
|
||||
$value = new cache_ttl_wrapper($value, $definitionid);
|
||||
}
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$session[$parsedkey] = $value;
|
||||
$data[$key] = array(
|
||||
'key' => $this->parse_key($key),
|
||||
'value' => $value
|
||||
);
|
||||
}
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_set($this->storetype, $this->get_definition()->get_id());
|
||||
cache_helper::record_cache_set($this->storetype, $definitionid);
|
||||
}
|
||||
$this->save_session($session);
|
||||
return count($keyvaluearray);
|
||||
return $this->get_store()->set_many($data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1884,13 +1943,9 @@ class cache_session extends cache {
|
||||
* @return bool True on success, false otherwise
|
||||
*/
|
||||
public function purge() {
|
||||
// 1. Purge the session object.
|
||||
$this->session = array();
|
||||
// 2. Delete the record for this users session from the store.
|
||||
$this->get_store()->delete($this->sessionid);
|
||||
// 3. Optionally purge any stacked loaders in the same way.
|
||||
$this->get_store()->purge();
|
||||
if ($this->get_loader()) {
|
||||
$this->get_loader()->delete($this->sessionid);
|
||||
$this->get_loader()->purge();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1919,21 +1974,27 @@ class cache_session extends cache {
|
||||
public function has($key, $tryloadifpossible = false) {
|
||||
$this->check_tracked_user();
|
||||
$parsedkey = $this->parse_key($key);
|
||||
$session = $this->get_session_data();
|
||||
$has = false;
|
||||
if ($this->has_a_ttl()) {
|
||||
$store = $this->get_store();
|
||||
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
|
||||
// The data has a TTL and the store doesn't support it natively.
|
||||
// We must fetch the data and expect a ttl wrapper.
|
||||
if (array_key_exists($parsedkey, $session)) {
|
||||
$data = $session[$parsedkey];
|
||||
$has = ($data instanceof cache_ttl_wrapper && !$data->has_expired());
|
||||
}
|
||||
$data = $store->get($parsedkey);
|
||||
$has = ($data instanceof cache_ttl_wrapper && !$data->has_expired());
|
||||
} else if (!$this->store_supports_key_awareness()) {
|
||||
// The store doesn't support key awareness, get the data and check it manually... puke.
|
||||
// Either no TTL is set of the store supports its handling natively.
|
||||
$data = $store->get($parsedkey);
|
||||
$has = ($data !== false);
|
||||
} else {
|
||||
$has = array_key_exists($parsedkey, $session);
|
||||
// The store supports key awareness, this is easy!
|
||||
// Either no TTL is set of the store supports its handling natively.
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$has = $store->has($parsedkey);
|
||||
}
|
||||
if (!$has && $tryloadifpossible) {
|
||||
$result = null;
|
||||
if ($this->get_loader() !== false) {
|
||||
$result = $this->get_loader()->get($key);
|
||||
$result = $this->get_loader()->get($parsedkey);
|
||||
} else if ($this->get_datasource() !== null) {
|
||||
$result = $this->get_datasource()->load_for_cache($key);
|
||||
}
|
||||
@@ -1960,25 +2021,18 @@ class cache_session extends cache {
|
||||
*/
|
||||
public function has_all(array $keys) {
|
||||
$this->check_tracked_user();
|
||||
$session = $this->get_session_data();
|
||||
foreach ($keys as $key) {
|
||||
$has = false;
|
||||
$parsedkey = $this->parse_key($key);
|
||||
if ($this->has_a_ttl()) {
|
||||
// The data has a TTL and the store doesn't support it natively.
|
||||
// We must fetch the data and expect a ttl wrapper.
|
||||
if (array_key_exists($parsedkey, $session)) {
|
||||
$data = $session[$parsedkey];
|
||||
$has = ($data instanceof cache_ttl_wrapper && !$data->has_expired());
|
||||
if (($this->has_a_ttl() && !$this->store_supports_native_ttl()) || !$this->store_supports_key_awareness()) {
|
||||
foreach ($keys as $key) {
|
||||
if (!$this->has($key)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$has = array_key_exists($parsedkey, $session);
|
||||
}
|
||||
if (!$has) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
// The cache must be key aware and if support native ttl if it a ttl is set.
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$store = $this->get_store();
|
||||
return $store->has_all(array_map(array($this, 'parse_key'), $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1995,26 +2049,17 @@ class cache_session extends cache {
|
||||
* @return bool True if the cache has at least one of the given keys
|
||||
*/
|
||||
public function has_any(array $keys) {
|
||||
$this->check_tracked_user();
|
||||
$session = $this->get_session_data();
|
||||
foreach ($keys as $key) {
|
||||
$has = false;
|
||||
$parsedkey = $this->parse_key($key);
|
||||
if ($this->has_a_ttl()) {
|
||||
// The data has a TTL and the store doesn't support it natively.
|
||||
// We must fetch the data and expect a ttl wrapper.
|
||||
if (array_key_exists($parsedkey, $session)) {
|
||||
$data = $session[$parsedkey];
|
||||
$has = ($data instanceof cache_ttl_wrapper && !$data->has_expired());
|
||||
if (($this->has_a_ttl() && !$this->store_supports_native_ttl()) || !$this->store_supports_key_awareness()) {
|
||||
foreach ($keys as $key) {
|
||||
if ($this->has($key)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$has = array_key_exists($parsedkey, $session);
|
||||
}
|
||||
if ($has) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
/* @var cache_store|cache_is_key_aware $store */
|
||||
$store = $this->get_store();
|
||||
return $store->has_any(array_map(array($this, 'parse_key'), $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -353,23 +353,19 @@ class cachestore_file extends cache_store implements cache_is_key_aware, cache_i
|
||||
if (!$readfile) {
|
||||
return false;
|
||||
}
|
||||
// Check the filesize first, likely not needed but important none the less.
|
||||
$filesize = filesize($file);
|
||||
if (!$filesize) {
|
||||
return false;
|
||||
}
|
||||
// Open ensuring the file for writing, truncating it and setting the pointer to the start.
|
||||
// Open ensuring the file for reading in binary format.
|
||||
if (!$handle = fopen($file, 'rb')) {
|
||||
return false;
|
||||
}
|
||||
// Lock it up!
|
||||
// We don't care if this succeeds or not, on some systems it will, on some it won't, meah either way.
|
||||
flock($handle, LOCK_SH);
|
||||
// HACK ALERT
|
||||
// There is a problem when reading from the file during PHPUNIT tests. For one reason or another the filesize is not correct
|
||||
// Doesn't happen during normal operation, just during unit tests.
|
||||
// Read it.
|
||||
$data = fread($handle, $filesize+128);
|
||||
$data = '';
|
||||
// Read the data in 1Mb chunks. Small caches will not loop more than once. We don't use filesize as it may
|
||||
// be cached with a different value than what we need to read from the file.
|
||||
do {
|
||||
$data .= fread($handle, 1048576);
|
||||
} while (!feof($handle));
|
||||
// Unlock it.
|
||||
flock($handle, LOCK_UN);
|
||||
// Return it unserialised.
|
||||
|
||||
@@ -132,8 +132,8 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
|
||||
$this->connection = new Memcache;
|
||||
foreach ($this->servers as $server) {
|
||||
$this->connection->addServer($server[0], $server[1], true, $server[2]);
|
||||
// Test the connection to this server.
|
||||
}
|
||||
// Test the connection to the pool of servers.
|
||||
$this->isready = @$this->connection->set($this->parse_key('ping'), 'ping', MEMCACHE_COMPRESSED, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
}
|
||||
$this->connection->addServers($this->servers);
|
||||
}
|
||||
// Test the connection to the pool of servers.
|
||||
$this->isready = @$this->connection->set("ping", 'ping', 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
|
||||
/**
|
||||
* The maximum size for the store, or false if there isn't one.
|
||||
* @var bool
|
||||
* @var bool|int
|
||||
*/
|
||||
protected $maxsize = false;
|
||||
|
||||
@@ -202,7 +202,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
*/
|
||||
public function initialise(cache_definition $definition) {
|
||||
$this->storeid = $definition->generate_definition_hash();
|
||||
$this->store = &self::register_store_id($definition->get_id());
|
||||
$this->store = &self::register_store_id($this->name.'-'.$definition->get_id());
|
||||
$this->ttl = $definition->get_ttl();
|
||||
$maxsize = $definition->get_maxsize();
|
||||
if ($maxsize !== null) {
|
||||
@@ -210,6 +210,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
$this->maxsize = abs((int)$maxsize);
|
||||
$this->storecount = count($this->store);
|
||||
}
|
||||
$this->check_ttl();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,9 +239,17 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
public function get($key) {
|
||||
if (isset($this->store[$key])) {
|
||||
if ($this->ttl == 0) {
|
||||
return $this->store[$key][0];
|
||||
$value = $this->store[$key][0];
|
||||
if ($this->maxsize !== false) {
|
||||
// Make sure the element is now in the end of array.
|
||||
$this->set($key, $value);
|
||||
}
|
||||
return $value;
|
||||
} else if ($this->store[$key][1] >= (cache::now() - $this->ttl)) {
|
||||
return $this->store[$key][0];
|
||||
} else {
|
||||
// Element is present but has expired.
|
||||
$this->check_ttl();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -257,20 +266,32 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
*/
|
||||
public function get_many($keys) {
|
||||
$return = array();
|
||||
$maxtime = 0;
|
||||
if ($this->ttl != 0) {
|
||||
$maxtime = cache::now() - $this->ttl;
|
||||
}
|
||||
|
||||
$hasexpiredelements = false;
|
||||
foreach ($keys as $key) {
|
||||
$return[$key] = false;
|
||||
if (isset($this->store[$key])) {
|
||||
if ($this->ttl == 0) {
|
||||
$return[$key] = $this->store[$key][0];
|
||||
if ($this->maxsize !== false) {
|
||||
// Make sure the element is now in the end of array.
|
||||
$this->set($key, $return[$key], false);
|
||||
}
|
||||
} else if ($this->store[$key][1] >= $maxtime) {
|
||||
$return[$key] = $this->store[$key][0];
|
||||
} else {
|
||||
$hasexpiredelements = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($hasexpiredelements) {
|
||||
// There are some elements that are present but have expired.
|
||||
$this->check_ttl();
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -279,24 +300,27 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
*
|
||||
* @param string $key The key to use.
|
||||
* @param mixed $data The data to set.
|
||||
* @param bool $testmaxsize If set to true then we test the maxsize arg and reduce if required.
|
||||
* @param bool $testmaxsize If set to true then we test the maxsize arg and reduce if required. If this is set to false you will
|
||||
* need to perform these checks yourself. This allows for bulk set's to be performed and maxsize tests performed once.
|
||||
* @return bool True if the operation was a success false otherwise.
|
||||
*/
|
||||
public function set($key, $data, $testmaxsize = true) {
|
||||
$testmaxsize = ($testmaxsize && $this->maxsize !== false);
|
||||
if ($testmaxsize) {
|
||||
$increment = (!isset($this->store[$key]));
|
||||
$increment = $this->maxsize !== false && !isset($this->store[$key]);
|
||||
if (($this->maxsize !== false && !$increment) || $this->ttl != 0) {
|
||||
// Make sure the element is added to the end of $this->store array.
|
||||
unset($this->store[$key]);
|
||||
}
|
||||
if ($this->ttl == 0) {
|
||||
$this->store[$key][0] = $data;
|
||||
if ($this->ttl === 0) {
|
||||
$this->store[$key] = array($data, 0);
|
||||
} else {
|
||||
$this->store[$key] = array($data, cache::now());
|
||||
}
|
||||
if ($testmaxsize && $increment) {
|
||||
if ($increment) {
|
||||
$this->storecount++;
|
||||
if ($this->storecount > $this->maxsize) {
|
||||
$this->reduce_for_maxsize();
|
||||
}
|
||||
}
|
||||
if ($testmaxsize && $this->storecount > $this->maxsize) {
|
||||
$this->reduce_for_maxsize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -311,12 +335,26 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
*/
|
||||
public function set_many(array $keyvaluearray) {
|
||||
$count = 0;
|
||||
$increment = 0;
|
||||
foreach ($keyvaluearray as $pair) {
|
||||
$this->set($pair['key'], $pair['value'], false);
|
||||
$key = $pair['key'];
|
||||
$data = $pair['value'];
|
||||
$count++;
|
||||
if ($this->maxsize !== false || $this->ttl !== 0) {
|
||||
// Make sure the element is added to the end of $this->store array.
|
||||
$this->delete($key);
|
||||
$increment++;
|
||||
} else if (!isset($this->store[$key])) {
|
||||
$increment++;
|
||||
}
|
||||
if ($this->ttl === 0) {
|
||||
$this->store[$key] = array($data, 0);
|
||||
} else {
|
||||
$this->store[$key] = array($data, cache::now());
|
||||
}
|
||||
}
|
||||
if ($this->maxsize !== false) {
|
||||
$this->storecount += $count;
|
||||
$this->storecount += $increment;
|
||||
if ($this->storecount > $this->maxsize) {
|
||||
$this->reduce_for_maxsize();
|
||||
}
|
||||
@@ -348,6 +386,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
* @return bool
|
||||
*/
|
||||
public function has_all(array $keys) {
|
||||
$maxtime = 0;
|
||||
if ($this->ttl != 0) {
|
||||
$maxtime = cache::now() - $this->ttl;
|
||||
}
|
||||
@@ -370,6 +409,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
* @return bool
|
||||
*/
|
||||
public function has_any(array $keys) {
|
||||
$maxtime = 0;
|
||||
if ($this->ttl != 0) {
|
||||
$maxtime = cache::now() - $this->ttl;
|
||||
}
|
||||
@@ -389,12 +429,14 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
* @return bool Returns true if the operation was a success, false otherwise.
|
||||
*/
|
||||
public function delete($key) {
|
||||
$result = isset($this->store[$key]);
|
||||
if (!isset($this->store[$key])) {
|
||||
return false;
|
||||
}
|
||||
unset($this->store[$key]);
|
||||
if ($this->maxsize !== false) {
|
||||
$this->storecount--;
|
||||
}
|
||||
return $result;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,17 +446,18 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
* @return int The number of items successfully deleted.
|
||||
*/
|
||||
public function delete_many(array $keys) {
|
||||
$count = 0;
|
||||
// The number of items that have actually being removed.
|
||||
$reduction = 0;
|
||||
foreach ($keys as $key) {
|
||||
if (isset($this->store[$key])) {
|
||||
$count++;
|
||||
$reduction++;
|
||||
}
|
||||
unset($this->store[$key]);
|
||||
}
|
||||
if ($this->maxsize !== false) {
|
||||
$this->storecount -= $count;
|
||||
$this->storecount -= $reduction;
|
||||
}
|
||||
return $count;
|
||||
return $reduction;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,12 +532,40 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired elements.
|
||||
* @return int number of removed elements
|
||||
*/
|
||||
protected function check_ttl() {
|
||||
if ($this->ttl === 0) {
|
||||
return 0;
|
||||
}
|
||||
$maxtime = cache::now() - $this->ttl;
|
||||
$count = 0;
|
||||
for ($value = reset($this->store); $value !== false; $value = next($this->store)) {
|
||||
if ($value[1] >= $maxtime) {
|
||||
// We know that elements are sorted by ttl so no need to continue.
|
||||
break;
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
if ($count) {
|
||||
// Remove first $count elements as they are expired.
|
||||
$this->store = array_slice($this->store, $count, null, true);
|
||||
if ($this->maxsize !== false) {
|
||||
$this->storecount -= $count;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all of the keys being stored in the cache store instance.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function find_all() {
|
||||
$this->check_ttl();
|
||||
return array_keys($this->store);
|
||||
}
|
||||
|
||||
@@ -502,6 +573,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
* Finds all of the keys whose keys start with the given prefix.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @return array An array of keys.
|
||||
*/
|
||||
public function find_by_prefix($prefix) {
|
||||
$return = array();
|
||||
@@ -512,4 +584,12 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This store supports native TTL handling.
|
||||
* @return bool
|
||||
*/
|
||||
public function store_supports_native_ttl() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,60 +49,66 @@ class cachestore_session_test extends cachestore_tests {
|
||||
* Test the maxsize option.
|
||||
*/
|
||||
public function test_maxsize() {
|
||||
$defid = 'phpunit/testmaxsize';
|
||||
$config = cache_config_phpunittest::instance();
|
||||
$config->phpunit_add_definition($defid, array(
|
||||
$config->phpunit_add_definition('phpunit/one', array(
|
||||
'mode' => cache_store::MODE_SESSION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'testmaxsize',
|
||||
'area' => 'one',
|
||||
'maxsize' => 3
|
||||
));
|
||||
$definition = cache_definition::load($defid, $config->get_definition_by_id($defid));
|
||||
$instance = cachestore_session::initialise_test_instance($definition);
|
||||
|
||||
$this->assertTrue($instance->set('key1', 'value1'));
|
||||
$this->assertTrue($instance->set('key2', 'value2'));
|
||||
$this->assertTrue($instance->set('key3', 'value3'));
|
||||
$config->phpunit_add_definition('phpunit/two', array(
|
||||
'mode' => cache_store::MODE_SESSION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'two',
|
||||
'maxsize' => 3
|
||||
));
|
||||
|
||||
$this->assertTrue($instance->has('key1'));
|
||||
$this->assertTrue($instance->has('key2'));
|
||||
$this->assertTrue($instance->has('key3'));
|
||||
$cacheone = cache::make('phpunit', 'one');
|
||||
|
||||
$this->assertTrue($instance->set('key4', 'value4'));
|
||||
$this->assertTrue($instance->set('key5', 'value5'));
|
||||
$this->assertTrue($cacheone->set('key1', 'value1'));
|
||||
$this->assertTrue($cacheone->set('key2', 'value2'));
|
||||
$this->assertTrue($cacheone->set('key3', 'value3'));
|
||||
|
||||
$this->assertFalse($instance->has('key1'));
|
||||
$this->assertFalse($instance->has('key2'));
|
||||
$this->assertTrue($instance->has('key3'));
|
||||
$this->assertTrue($instance->has('key4'));
|
||||
$this->assertTrue($instance->has('key5'));
|
||||
$this->assertTrue($cacheone->has('key1'));
|
||||
$this->assertTrue($cacheone->has('key2'));
|
||||
$this->assertTrue($cacheone->has('key3'));
|
||||
|
||||
$this->assertFalse($instance->get('key1'));
|
||||
$this->assertFalse($instance->get('key2'));
|
||||
$this->assertEquals('value3', $instance->get('key3'));
|
||||
$this->assertEquals('value4', $instance->get('key4'));
|
||||
$this->assertEquals('value5', $instance->get('key5'));
|
||||
$this->assertTrue($cacheone->set('key4', 'value4'));
|
||||
$this->assertTrue($cacheone->set('key5', 'value5'));
|
||||
|
||||
$this->assertFalse($cacheone->has('key1'));
|
||||
$this->assertFalse($cacheone->has('key2'));
|
||||
$this->assertTrue($cacheone->has('key3'));
|
||||
$this->assertTrue($cacheone->has('key4'));
|
||||
$this->assertTrue($cacheone->has('key5'));
|
||||
|
||||
$this->assertFalse($cacheone->get('key1'));
|
||||
$this->assertFalse($cacheone->get('key2'));
|
||||
$this->assertEquals('value3', $cacheone->get('key3'));
|
||||
$this->assertEquals('value4', $cacheone->get('key4'));
|
||||
$this->assertEquals('value5', $cacheone->get('key5'));
|
||||
|
||||
// Test adding one more.
|
||||
$this->assertTrue($instance->set('key6', 'value6'));
|
||||
$this->assertFalse($instance->get('key3'));
|
||||
$this->assertTrue($cacheone->set('key6', 'value6'));
|
||||
$this->assertFalse($cacheone->get('key3'));
|
||||
|
||||
// Test reducing and then adding to make sure we don't lost one.
|
||||
$this->assertTrue($instance->delete('key6'));
|
||||
$this->assertTrue($instance->set('key7', 'value7'));
|
||||
$this->assertEquals('value4', $instance->get('key4'));
|
||||
$this->assertTrue($cacheone->delete('key6'));
|
||||
$this->assertTrue($cacheone->set('key7', 'value7'));
|
||||
$this->assertEquals('value4', $cacheone->get('key4'));
|
||||
|
||||
// Set the same key three times to make sure it doesn't count overrides.
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$this->assertTrue($instance->set('key8', 'value8'));
|
||||
$this->assertTrue($cacheone->set('key8', 'value8'));
|
||||
}
|
||||
$this->assertEquals('value7', $instance->get('key7'), 'Overrides are incorrectly incrementing size');
|
||||
$this->assertEquals('value7', $cacheone->get('key7'), 'Overrides are incorrectly incrementing size');
|
||||
|
||||
// Test adding many.
|
||||
$this->assertEquals(3, $instance->set_many(array(
|
||||
array('key' => 'keyA', 'value' => 'valueA'),
|
||||
array('key' => 'keyB', 'value' => 'valueB'),
|
||||
array('key' => 'keyC', 'value' => 'valueC')
|
||||
$this->assertEquals(3, $cacheone->set_many(array(
|
||||
'keyA' => 'valueA',
|
||||
'keyB' => 'valueB',
|
||||
'keyC' => 'valueC'
|
||||
)));
|
||||
$this->assertEquals(array(
|
||||
'key4' => false,
|
||||
@@ -112,8 +118,82 @@ class cachestore_session_test extends cachestore_tests {
|
||||
'keyA' => 'valueA',
|
||||
'keyB' => 'valueB',
|
||||
'keyC' => 'valueC'
|
||||
), $instance->get_many(array(
|
||||
), $cacheone->get_many(array(
|
||||
'key4', 'key5', 'key6', 'key7', 'keyA', 'keyB', 'keyC'
|
||||
)));
|
||||
|
||||
$cachetwo = cache::make('phpunit', 'two');
|
||||
|
||||
// Test adding many.
|
||||
$this->assertEquals(3, $cacheone->set_many(array(
|
||||
'keyA' => 'valueA',
|
||||
'keyB' => 'valueB',
|
||||
'keyC' => 'valueC'
|
||||
)));
|
||||
|
||||
$this->assertEquals(3, $cachetwo->set_many(array(
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'key3' => 'value3'
|
||||
)));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'keyA' => 'valueA',
|
||||
'keyB' => 'valueB',
|
||||
'keyC' => 'valueC'
|
||||
), $cacheone->get_many(array(
|
||||
'keyA', 'keyB', 'keyC'
|
||||
)));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'key3' => 'value3'
|
||||
), $cachetwo->get_many(array(
|
||||
'key1', 'key2', 'key3'
|
||||
)));
|
||||
|
||||
// Test that that cache deletes element that was least recently accessed.
|
||||
$this->assertEquals('valueA', $cacheone->get('keyA'));
|
||||
$cacheone->set('keyD', 'valueD');
|
||||
$this->assertEquals('valueA', $cacheone->get('keyA'));
|
||||
$this->assertFalse($cacheone->get('keyB'));
|
||||
$this->assertEquals(array('keyD' => 'valueD', 'keyC' => 'valueC'), $cacheone->get_many(array('keyD', 'keyC')));
|
||||
$cacheone->set('keyE', 'valueE');
|
||||
$this->assertFalse($cacheone->get('keyB'));
|
||||
$this->assertFalse($cacheone->get('keyA'));
|
||||
$this->assertEquals(array('keyA' => false, 'keyE' => 'valueE', 'keyD' => 'valueD', 'keyC' => 'valueC'),
|
||||
$cacheone->get_many(array('keyA', 'keyE', 'keyD', 'keyC')));
|
||||
// Overwrite keyE (moves it to the end of array), and set keyF.
|
||||
$cacheone->set_many(array('keyE' => 'valueE', 'keyF' => 'valueF'));
|
||||
$this->assertEquals(array('keyC' => 'valueC', 'keyE' => 'valueE', 'keyD' => false, 'keyF' => 'valueF'),
|
||||
$cacheone->get_many(array('keyC', 'keyE', 'keyD', 'keyF')));
|
||||
}
|
||||
|
||||
public function test_ttl() {
|
||||
$config = cache_config_phpunittest::instance();
|
||||
$config->phpunit_add_definition('phpunit/three', array(
|
||||
'mode' => cache_store::MODE_SESSION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'three',
|
||||
'maxsize' => 3,
|
||||
'ttl' => 3
|
||||
));
|
||||
|
||||
$cachethree = cache::make('phpunit', 'three');
|
||||
|
||||
// Make sure that when cache with ttl is full the elements that were added first are deleted first regardless of access time.
|
||||
$cachethree->set('key1', 'value1');
|
||||
$cachethree->set('key2', 'value2');
|
||||
$cachethree->set('key3', 'value3');
|
||||
$cachethree->set('key4', 'value4');
|
||||
$this->assertFalse($cachethree->get('key1'));
|
||||
$this->assertEquals('value4', $cachethree->get('key4'));
|
||||
$cachethree->set('key5', 'value5');
|
||||
$this->assertFalse($cachethree->get('key2'));
|
||||
$this->assertEquals('value4', $cachethree->get('key4'));
|
||||
$cachethree->set_many(array('key6' => 'value6', 'key7' => 'value7'));
|
||||
$this->assertEquals(array('key3' => false, 'key4' => false, 'key5' => 'value5', 'key6' => 'value6', 'key7' => 'value7'),
|
||||
$cachethree->get_many(array('key3', 'key4', 'key5', 'key6', 'key7')));
|
||||
}
|
||||
}
|
||||
@@ -1126,9 +1126,9 @@ class core_cache_testcase extends advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that multiple loaders work ok.
|
||||
* Test that multiple application loaders work ok.
|
||||
*/
|
||||
public function test_multiple_loaders() {
|
||||
public function test_multiple_application_loaders() {
|
||||
$instance = cache_config_phpunittest::instance(true);
|
||||
$instance->phpunit_add_file_store('phpunittest1');
|
||||
$instance->phpunit_add_file_store('phpunittest2');
|
||||
@@ -1173,6 +1173,93 @@ class core_cache_testcase extends advanced_testcase {
|
||||
$this->assertFalse($result['a']);
|
||||
$this->assertEquals('B', $result['b']);
|
||||
$this->assertFalse($result['c']);
|
||||
|
||||
// Test non-recursive deletes.
|
||||
$this->assertTrue($cache->set('test', 'test'));
|
||||
$this->assertSame('test', $cache->get('test'));
|
||||
$this->assertTrue($cache->delete('test', false));
|
||||
// We should still have it on a deeper loader.
|
||||
$this->assertSame('test', $cache->get('test'));
|
||||
// Test non-recusive with many functions.
|
||||
$this->assertSame(3, $cache->set_many(array(
|
||||
'one' => 'one',
|
||||
'two' => 'two',
|
||||
'three' => 'three'
|
||||
)));
|
||||
$this->assertSame('one', $cache->get('one'));
|
||||
$this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
|
||||
$this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
|
||||
$this->assertSame('one', $cache->get('one'));
|
||||
$this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that multiple application loaders work ok.
|
||||
*/
|
||||
public function test_multiple_session_loaders() {
|
||||
/* @var cache_config_phpunittest $instance */
|
||||
$instance = cache_config_phpunittest::instance(true);
|
||||
$instance->phpunit_add_session_store('phpunittest1');
|
||||
$instance->phpunit_add_session_store('phpunittest2');
|
||||
$instance->phpunit_add_definition('phpunit/multi_loader', array(
|
||||
'mode' => cache_store::MODE_SESSION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'multi_loader'
|
||||
));
|
||||
$instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
|
||||
$instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
|
||||
|
||||
$cache = cache::make('phpunit', 'multi_loader');
|
||||
$this->assertInstanceOf('cache_session', $cache);
|
||||
$this->assertFalse($cache->get('test'));
|
||||
$this->assertTrue($cache->set('test', 'test'));
|
||||
$this->assertEquals('test', $cache->get('test'));
|
||||
$this->assertTrue($cache->delete('test'));
|
||||
$this->assertFalse($cache->get('test'));
|
||||
$this->assertTrue($cache->set('test', 'test'));
|
||||
$this->assertTrue($cache->purge());
|
||||
$this->assertFalse($cache->get('test'));
|
||||
|
||||
// Test the many commands.
|
||||
$this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
|
||||
$result = $cache->get_many(array('a', 'b', 'c'));
|
||||
$this->assertInternalType('array', $result);
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertArrayHasKey('a', $result);
|
||||
$this->assertArrayHasKey('b', $result);
|
||||
$this->assertArrayHasKey('c', $result);
|
||||
$this->assertEquals('A', $result['a']);
|
||||
$this->assertEquals('B', $result['b']);
|
||||
$this->assertEquals('C', $result['c']);
|
||||
$this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
|
||||
$this->assertEquals(2, $cache->delete_many(array('a', 'c')));
|
||||
$result = $cache->get_many(array('a', 'b', 'c'));
|
||||
$this->assertInternalType('array', $result);
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertArrayHasKey('a', $result);
|
||||
$this->assertArrayHasKey('b', $result);
|
||||
$this->assertArrayHasKey('c', $result);
|
||||
$this->assertFalse($result['a']);
|
||||
$this->assertEquals('B', $result['b']);
|
||||
$this->assertFalse($result['c']);
|
||||
|
||||
// Test non-recursive deletes.
|
||||
$this->assertTrue($cache->set('test', 'test'));
|
||||
$this->assertSame('test', $cache->get('test'));
|
||||
$this->assertTrue($cache->delete('test', false));
|
||||
// We should still have it on a deeper loader.
|
||||
$this->assertSame('test', $cache->get('test'));
|
||||
// Test non-recusive with many functions.
|
||||
$this->assertSame(3, $cache->set_many(array(
|
||||
'one' => 'one',
|
||||
'two' => 'two',
|
||||
'three' => 'three'
|
||||
)));
|
||||
$this->assertSame('one', $cache->get('one'));
|
||||
$this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
|
||||
$this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
|
||||
$this->assertSame('one', $cache->get('one'));
|
||||
$this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1448,4 +1535,4 @@ class core_cache_testcase extends advanced_testcase {
|
||||
$this->assertInstanceOf('cache_request', $cache);
|
||||
$this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,24 @@ class cache_config_phpunittest extends cache_config_writer {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcefully adds a session store.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function phpunit_add_session_store($name) {
|
||||
$this->configstores[$name] = array(
|
||||
'name' => $name,
|
||||
'plugin' => 'session',
|
||||
'configuration' => array(),
|
||||
'features' => 14,
|
||||
'modes' => 2,
|
||||
'default' => true,
|
||||
'class' => 'cachestore_session',
|
||||
'lock' => 'cachelock_file_default',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcefully injects a definition => store mapping.
|
||||
*
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
// format.php - course format featuring single activity
|
||||
// included from view.php
|
||||
|
||||
$module = $course->format;
|
||||
require_once($CFG->dirroot.'/mod/'.$module.'/locallib.php');
|
||||
|
||||
$strgroups = get_string('groups');
|
||||
$strgroupmy = get_string('groupmy');
|
||||
$editing = $PAGE->user_is_editing();
|
||||
|
||||
$moduleformat = $module.'_course_format_display';
|
||||
if (function_exists($moduleformat)) {
|
||||
$moduleformat($USER,$course);
|
||||
} else {
|
||||
echo $OUTPUT->notification('The module '. $module. ' does not support single activity course format');
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains main class for the course format SCORM
|
||||
*
|
||||
* @since 2.0
|
||||
* @package format_scorm
|
||||
* @copyright 2009 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->dirroot. '/course/format/lib.php');
|
||||
|
||||
/**
|
||||
* Main class for the Scorm course format
|
||||
*
|
||||
* @package format_scorm
|
||||
* @copyright 2012 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class format_scorm extends format_base {
|
||||
|
||||
/**
|
||||
* The URL to use for the specified course
|
||||
*
|
||||
* @param int|stdClass $section Section object from database or just field course_sections.section
|
||||
* if null the course view page is returned
|
||||
* @param array $options options for view URL. At the moment core uses:
|
||||
* 'navigation' (bool) if true and section has no separate page, the function returns null
|
||||
* 'sr' (int) used by multipage formats to specify to which section to return
|
||||
* @return null|moodle_url
|
||||
*/
|
||||
public function get_view_url($section, $options = array()) {
|
||||
if (!empty($options['navigation']) && $section !== null) {
|
||||
return null;
|
||||
}
|
||||
return new moodle_url('/course/view.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all of the course sections into the navigation
|
||||
*
|
||||
* @param global_navigation $navigation
|
||||
* @param navigation_node $node The course node within the navigation
|
||||
*/
|
||||
public function extend_course_navigation($navigation, navigation_node $node) {
|
||||
// Scorm course format does not extend course navigation
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of blocks to be automatically added for the newly created course
|
||||
*
|
||||
* @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT
|
||||
* each of values is an array of block names (for left and right side columns)
|
||||
*/
|
||||
public function get_default_blocks() {
|
||||
return array(
|
||||
BLOCK_POS_LEFT => array(),
|
||||
BLOCK_POS_RIGHT => array('news_items', 'recent_activity', 'calendar_upcoming')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows course format to execute code on moodle_page::set_course()
|
||||
*
|
||||
* If user is on course view page and there is no scorm module added to the course
|
||||
* and the user has 'moodle/course:update' capability, redirect to create module
|
||||
* form. This function is executed before the output starts
|
||||
*
|
||||
* @param moodle_page $page instance of page calling set_course
|
||||
*/
|
||||
public function page_set_course(moodle_page $page) {
|
||||
global $PAGE;
|
||||
if ($PAGE == $page && $page->has_set_url() &&
|
||||
$page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) {
|
||||
$modinfo = get_fast_modinfo($this->courseid);
|
||||
if (empty($modinfo->instances['scorm'])
|
||||
&& has_capability('moodle/course:update', context_course::instance($this->courseid))) {
|
||||
// Redirect to create a new activity
|
||||
$url = new moodle_url('/course/modedit.php',
|
||||
array('course' => $this->courseid, 'section' => 0, 'add' => 'scorm'));
|
||||
redirect($url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1736,35 +1736,44 @@ function reorder_sections($sections, $origin_position, $target_position) {
|
||||
* Move the module object $mod to the specified $section
|
||||
* If $beforemod exists then that is the module
|
||||
* before which $modid should be inserted
|
||||
* All parameters are objects
|
||||
*
|
||||
* @param stdClass|cm_info $mod
|
||||
* @param stdClass|section_info $section
|
||||
* @param int|stdClass $beforemod id or object with field id corresponding to the module
|
||||
* before which the module needs to be included. Null for inserting in the
|
||||
* end of the section
|
||||
* @return int new value for module visibility (0 or 1)
|
||||
*/
|
||||
function moveto_module($mod, $section, $beforemod=NULL) {
|
||||
global $OUTPUT, $DB;
|
||||
|
||||
/// Remove original module from original section
|
||||
// Current module visibility state - return value of this function.
|
||||
$modvisible = $mod->visible;
|
||||
|
||||
// Remove original module from original section.
|
||||
if (! delete_mod_from_section($mod->id, $mod->section)) {
|
||||
echo $OUTPUT->notification("Could not delete module from existing section");
|
||||
}
|
||||
|
||||
// if moving to a hidden section then hide module
|
||||
// If moving to a hidden section then hide module.
|
||||
if ($mod->section != $section->id) {
|
||||
if (!$section->visible && $mod->visible) {
|
||||
// Set this in the object because it is sent as a response to ajax calls.
|
||||
$mod->visible = 0;
|
||||
// Module was visible but must become hidden after moving to hidden section.
|
||||
$modvisible = 0;
|
||||
set_coursemodule_visible($mod->id, 0);
|
||||
// Set visibleold to 1 so module will be visible when section is made visible.
|
||||
$DB->set_field('course_modules', 'visibleold', 1, array('id' => $mod->id));
|
||||
}
|
||||
if ($section->visible && !$mod->visible) {
|
||||
// Hidden module was moved to the visible section, restore the module visibility from visibleold.
|
||||
set_coursemodule_visible($mod->id, $mod->visibleold);
|
||||
// Set this in the object because it is sent as a response to ajax calls.
|
||||
$mod->visible = $mod->visibleold;
|
||||
$modvisible = $mod->visibleold;
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the module into the new section
|
||||
// Add the module into the new section.
|
||||
course_add_cm_to_section($section->course, $mod->id, $section->section, $beforemod);
|
||||
return true;
|
||||
return $modvisible;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,16 @@ require_once("../config.php");
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
require_once($CFG->libdir.'/coursecatlib.php');
|
||||
|
||||
/**
|
||||
* Limit the total number of categories where user has 'moodle/course:manage'
|
||||
* permission in order for "Move categories" dropdown to be displayed on this page.
|
||||
* If number of categories exceeds this limit, user can always use edit category
|
||||
* form to change the parent. Otherwise the page size becomes too big.
|
||||
*/
|
||||
if (!defined('COURSECAT_QUICKMOVE_LIMIT')) {
|
||||
define('COURSECAT_QUICKMOVE_LIMIT', 200);
|
||||
}
|
||||
|
||||
// Category id.
|
||||
$id = optional_param('categoryid', 0, PARAM_INT);
|
||||
// Which page to show.
|
||||
@@ -350,6 +360,8 @@ if (!empty($searchcriteria)) {
|
||||
echo $OUTPUT->heading(new lang_string('searchresults'));
|
||||
} else if (!$coursecat->id) {
|
||||
// Print out the categories with all the knobs.
|
||||
$manageablecategories = coursecat::make_categories_list('moodle/category:manage');
|
||||
$displaymovecategoryto = !empty($manageablecategories) && (count($manageablecategories) <= COURSECAT_QUICKMOVE_LIMIT);
|
||||
$table = new html_table;
|
||||
$table->id = 'coursecategories';
|
||||
$table->attributes['class'] = 'admintable generaltable editcourse';
|
||||
@@ -357,17 +369,21 @@ if (!empty($searchcriteria)) {
|
||||
get_string('categories'),
|
||||
get_string('courses'),
|
||||
get_string('edit'),
|
||||
get_string('movecategoryto'),
|
||||
);
|
||||
if ($displaymovecategoryto) {
|
||||
$table->head[] = get_string('movecategoryto');
|
||||
}
|
||||
$table->colclasses = array(
|
||||
'leftalign name',
|
||||
'centeralign count',
|
||||
'centeralign icons',
|
||||
'leftalign actions'
|
||||
);
|
||||
if ($displaymovecategoryto) {
|
||||
$table->colclasses[] = 'leftalign actions';
|
||||
}
|
||||
$table->data = array();
|
||||
|
||||
print_category_edit($table, $coursecat);
|
||||
print_category_edit($table, $coursecat, -1, false, false, $displaymovecategoryto);
|
||||
|
||||
echo html_writer::table($table);
|
||||
} else {
|
||||
@@ -655,8 +671,9 @@ echo $OUTPUT->footer();
|
||||
* @param int $depth The depth of the category.
|
||||
* @param bool $up True if this category can be moved up.
|
||||
* @param bool $down True if this category can be moved down.
|
||||
* @param bool $displaymovecategoryto whether to display a dropdown for quick category move.
|
||||
*/
|
||||
function print_category_edit(html_table $table, coursecat $category, $depth = -1, $up = false, $down = false) {
|
||||
function print_category_edit(html_table $table, coursecat $category, $depth = -1, $up = false, $down = false, $displaymovecategoryto = true) {
|
||||
global $OUTPUT;
|
||||
|
||||
static $str = null;
|
||||
@@ -744,7 +761,7 @@ function print_category_edit(html_table $table, coursecat $category, $depth = -1
|
||||
}
|
||||
|
||||
$actions = '';
|
||||
if (has_capability('moodle/category:manage', $categorycontext)) {
|
||||
if ($displaymovecategoryto && has_capability('moodle/category:manage', $categorycontext)) {
|
||||
$popupurl = new moodle_url('/course/manage.php', array('movecat' => $category->id, 'sesskey' => sesskey()));
|
||||
$tempdisplaylist = array(0 => get_string('top')) + coursecat::make_categories_list('moodle/category:manage', $category->id);
|
||||
$select = new single_select($popupurl, 'movetocat', $tempdisplaylist, $category->parent, null, "moveform$category->id");
|
||||
@@ -752,16 +769,19 @@ function print_category_edit(html_table $table, coursecat $category, $depth = -1
|
||||
$actions = $OUTPUT->render($select);
|
||||
}
|
||||
|
||||
$table->data[] = new html_table_row(array(
|
||||
$thisrowdata = array(
|
||||
// Category name.
|
||||
new html_table_cell($categoryname),
|
||||
// Course count.
|
||||
new html_table_cell($category->coursecount),
|
||||
// Icons.
|
||||
new html_table_cell(join(' ', $icons)),
|
||||
);
|
||||
if ($displaymovecategoryto) {
|
||||
// Actions.
|
||||
new html_table_cell($actions)
|
||||
));
|
||||
$thisrowdata[] = new html_table_cell($actions);
|
||||
}
|
||||
$table->data[] = new html_table_row($thisrowdata);
|
||||
}
|
||||
|
||||
if ($categories = $category->get_children()) {
|
||||
@@ -779,7 +799,7 @@ function print_category_edit(html_table $table, coursecat $category, $depth = -1
|
||||
$down = $last ? false : true;
|
||||
$first = false;
|
||||
|
||||
print_category_edit($table, $cat, $depth+1, $up, $down);
|
||||
print_category_edit($table, $cat, $depth+1, $up, $down, $displaymovecategoryto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,8 +133,8 @@ switch($requestmethod) {
|
||||
$beforemod = NULL;
|
||||
}
|
||||
|
||||
moveto_module($cm, $section, $beforemod);
|
||||
echo json_encode(array('visible' => $cm->visible));
|
||||
$isvisible = moveto_module($cm, $section, $beforemod);
|
||||
echo json_encode(array('visible' => $isvisible));
|
||||
break;
|
||||
case 'gettitle':
|
||||
require_capability('moodle/course:manageactivities', $modcontext);
|
||||
|
||||
@@ -856,8 +856,6 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
// Perform the move
|
||||
moveto_module($cm, $newsection);
|
||||
|
||||
// reset of get_fast_modinfo is usually called the code calling moveto_module so call it here
|
||||
get_fast_modinfo(0, 0, true);
|
||||
$cms = get_fast_modinfo($course)->get_cms();
|
||||
$cm = reset($cms);
|
||||
|
||||
@@ -883,11 +881,8 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
// Perform a second move as some issues were only seen on the second move
|
||||
$newsection = get_fast_modinfo($course)->get_section_info(2);
|
||||
$oldsectionid = $cm->section;
|
||||
$result = moveto_module($cm, $newsection);
|
||||
$this->assertTrue($result);
|
||||
moveto_module($cm, $newsection);
|
||||
|
||||
// reset of get_fast_modinfo is usually called the code calling moveto_module so call it here
|
||||
get_fast_modinfo(0, 0, true);
|
||||
$cms = get_fast_modinfo($course)->get_cms();
|
||||
$cm = reset($cms);
|
||||
|
||||
@@ -1197,12 +1192,9 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$forumcm = $modinfo->cms[$forum->cmid];
|
||||
$pagecm = $modinfo->cms[$page->cmid];
|
||||
|
||||
// Move the forum and the page to a hidden section.
|
||||
moveto_module($forumcm, $hiddensection);
|
||||
moveto_module($pagecm, $hiddensection);
|
||||
|
||||
// Reset modinfo cache.
|
||||
get_fast_modinfo(0, 0, true);
|
||||
// Move the forum and the page to a hidden section, make sure moveto_module returns 0 as new visibility state.
|
||||
$this->assertEquals(0, moveto_module($forumcm, $hiddensection));
|
||||
$this->assertEquals(0, moveto_module($pagecm, $hiddensection));
|
||||
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
|
||||
@@ -1228,29 +1220,26 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($quizcm->visible, 1);
|
||||
|
||||
// Move forum and page back to visible section.
|
||||
// Make sure the visibility is restored to the original value (visible for forum and hidden for page).
|
||||
$visiblesection = $modinfo->get_section_info(2);
|
||||
moveto_module($forumcm, $visiblesection);
|
||||
moveto_module($pagecm, $visiblesection);
|
||||
$this->assertEquals(1, moveto_module($forumcm, $visiblesection));
|
||||
$this->assertEquals(0, moveto_module($pagecm, $visiblesection));
|
||||
|
||||
// Reset modinfo cache.
|
||||
get_fast_modinfo(0, 0, true);
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
|
||||
// Verify that forum has been made visible.
|
||||
// Double check that forum has been made visible.
|
||||
$forumcm = $modinfo->cms[$forum->cmid];
|
||||
$this->assertEquals($forumcm->visible, 1);
|
||||
|
||||
// Verify that page has stayed invisible.
|
||||
// Double check that page has stayed invisible.
|
||||
$pagecm = $modinfo->cms[$page->cmid];
|
||||
$this->assertEquals($pagecm->visible, 0);
|
||||
|
||||
// Move the page in the same section (this is what mod duplicate does_
|
||||
moveto_module($pagecm, $visiblesection, $forumcm);
|
||||
// Move the page in the same section (this is what mod duplicate does).
|
||||
// Visibility of page remains 0.
|
||||
$this->assertEquals(0, moveto_module($pagecm, $visiblesection, $forumcm));
|
||||
|
||||
// Reset modinfo cache.
|
||||
get_fast_modinfo(0, 0, true);
|
||||
|
||||
// Verify that the the page is still hidden
|
||||
// Double check that the the page is still hidden.
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$pagecm = $modinfo->cms[$page->cmid];
|
||||
$this->assertEquals($pagecm->visible, 0);
|
||||
@@ -1288,13 +1277,10 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($section->id, $pagecm->section);
|
||||
|
||||
|
||||
// Move the forum and the page to a hidden section.
|
||||
moveto_module($pagecm, $section, $forumcm);
|
||||
// Move the page inside the hidden section. Make sure it is hidden.
|
||||
$this->assertEquals(0, moveto_module($pagecm, $section, $forumcm));
|
||||
|
||||
// Reset modinfo cache.
|
||||
get_fast_modinfo(0, 0, true);
|
||||
|
||||
// Verify that the the page is still hidden
|
||||
// Double check that the the page is still hidden.
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$pagecm = $modinfo->cms[$page->cmid];
|
||||
$this->assertEquals($pagecm->visible, 0);
|
||||
|
||||
@@ -219,8 +219,10 @@
|
||||
redirect($CFG->wwwroot .'/');
|
||||
}
|
||||
|
||||
$ajaxenabled = ajaxenabled();
|
||||
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled() && ajaxenabled()) {
|
||||
if ($completion->is_enabled() && $ajaxenabled) {
|
||||
$PAGE->requires->string_for_js('completion-title-manual-y', 'completion');
|
||||
$PAGE->requires->string_for_js('completion-title-manual-n', 'completion');
|
||||
$PAGE->requires->string_for_js('completion-alt-manual-y', 'completion');
|
||||
@@ -241,7 +243,7 @@
|
||||
$PAGE->set_heading($course->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
if ($completion->is_enabled() && ajaxenabled()) {
|
||||
if ($completion->is_enabled() && $ajaxenabled) {
|
||||
// This value tracks whether there has been a dynamic change to the page.
|
||||
// It is used so that if a user does this - (a) set some tickmarks, (b)
|
||||
// go to another page, (c) clicks Back button - the page will
|
||||
|
||||
@@ -176,25 +176,31 @@ class core_files_externallib_testcase extends advanced_testcase {
|
||||
$this->assertNotEmpty($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting a list of files with and without a context ID.
|
||||
*/
|
||||
public function test_get_files() {
|
||||
global $USER, $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Set the current user to be the administrator.
|
||||
$this->setAdminUser();
|
||||
$USER->email = '[email protected]';
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$record = new stdClass();
|
||||
$record->course = $course->id;
|
||||
$record->name = "Mod data upload test";
|
||||
|
||||
$record->intro = "Some intro of some sort";
|
||||
|
||||
// Create a database module.
|
||||
$module = $this->getDataGenerator()->create_module('data', $record);
|
||||
|
||||
// Create a new field in the database activity.
|
||||
$field = data_get_field_new('file', $module);
|
||||
|
||||
// Add more detail about the field.
|
||||
$fielddetail = new stdClass();
|
||||
$fielddetail->d = $module->id;
|
||||
$fielddetail->mode = 'add';
|
||||
@@ -208,15 +214,15 @@ class core_files_externallib_testcase extends advanced_testcase {
|
||||
$field->insert_field();
|
||||
$recordid = data_add_record($module);
|
||||
|
||||
$timemodified = $DB->get_field('data_records', 'timemodified', array('id' => $recordid));
|
||||
|
||||
// File information for the database module record.
|
||||
$datacontent = array();
|
||||
$datacontent['fieldid'] = $field->field->id;
|
||||
$datacontent['recordid'] = $recordid;
|
||||
$datacontent['content'] = 'Simple4.txt';
|
||||
|
||||
// Insert the information about the file.
|
||||
$contentid = $DB->insert_record('data_content', $datacontent);
|
||||
|
||||
// Required information for uploading a file.
|
||||
$context = context_module::instance($module->id);
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
$component = 'mod_data';
|
||||
@@ -233,12 +239,18 @@ class core_files_externallib_testcase extends advanced_testcase {
|
||||
$filerecord['filepath'] = '/';
|
||||
$filerecord['filename'] = $filename;
|
||||
|
||||
// Create an area to upload the file.
|
||||
$fs = get_file_storage();
|
||||
// Create a file from the string that we made earlier.
|
||||
$file = $fs->create_file_from_string($filerecord, $filecontent);
|
||||
$timemodified = $file->get_timemodified();
|
||||
|
||||
// Use the web service function to return the information about the file that we just uploaded.
|
||||
// The first time is with a valid context ID.
|
||||
$filename = '';
|
||||
$testfilelisting = core_files_external::get_files($context->id, $component, $filearea, $itemid, '/', $filename);
|
||||
|
||||
// With the information that we have provided we should get an object exactly like the one below.
|
||||
$testdata = array();
|
||||
$testdata['parents'] = array();
|
||||
$testdata['parents']['0'] = array('contextid' => 1,
|
||||
@@ -275,18 +287,19 @@ class core_files_externallib_testcase extends advanced_testcase {
|
||||
$testdata['files']['0'] = array('contextid' => 20,
|
||||
'component' => 'mod_data',
|
||||
'filearea' => 'content',
|
||||
'itemid' => 1,
|
||||
'itemid' => '1',
|
||||
'filepath' => '/',
|
||||
'filename' => 'Simple4.txt',
|
||||
'url' => 'http://www.example.com/moodle/pluginfile.php/20/mod_data/content/1/Simple4.txt',
|
||||
'isdir' => null,
|
||||
'isdir' => false,
|
||||
'timemodified' => $timemodified);
|
||||
|
||||
// Make sure that they are the same.
|
||||
$this->assertEquals($testfilelisting, $testdata);
|
||||
|
||||
// Try again but without the context.
|
||||
// Try again but without the context. Minus one signals the function to use other variables to obtain the context.
|
||||
$nocontext = -1;
|
||||
$modified = 0;
|
||||
// Context level and instance ID are used to determine what the context is.
|
||||
$contextlevel = 'module';
|
||||
$instanceid = $module->id;
|
||||
$testfilelisting = core_files_external::get_files($nocontext, $component, $filearea, $itemid, '/', $filename, $modified, $contextlevel, $instanceid);
|
||||
|
||||
@@ -1582,15 +1582,15 @@ class grade_report_grader extends grade_report {
|
||||
* @return bool
|
||||
*/
|
||||
public function is_fixed_students() {
|
||||
global $USER, $CFG;
|
||||
global $CFG;
|
||||
return $CFG->grade_report_fixedstudents &&
|
||||
(check_browser_version('MSIE', '7.0') ||
|
||||
check_browser_version('Firefox', '2.0') ||
|
||||
check_browser_version('Gecko', '2006010100') ||
|
||||
check_browser_version('Camino', '1.0') ||
|
||||
check_browser_version('Opera', '6.0') ||
|
||||
check_browser_version('Chrome', '6') ||
|
||||
check_browser_version('Safari', '300'));
|
||||
(core_useragent::check_ie_version('7.0') ||
|
||||
core_useragent::check_firefox_version('2.0') ||
|
||||
core_useragent::check_gecko_version('2006010100') ||
|
||||
core_useragent::check_camino_version('1.0') ||
|
||||
core_useragent::check_opera_version('6.0') ||
|
||||
core_useragent::check_chrome_version('6') ||
|
||||
core_useragent::check_safari_version('300'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -152,7 +152,8 @@ $currenttab = 'groups';
|
||||
require('tabs.php');
|
||||
|
||||
$disabled = 'disabled="disabled"';
|
||||
if (ajaxenabled()) {
|
||||
$ajaxenabled = ajaxenabled();
|
||||
if ($ajaxenabled) {
|
||||
// Some buttons are enabled if single group selected
|
||||
$showaddmembersform_disabled = $singlegroup ? '' : $disabled;
|
||||
$showeditgroupsettingsform_disabled = $singlegroup ? '' : $disabled;
|
||||
@@ -178,7 +179,7 @@ echo '<tr>'."\n";
|
||||
echo "<td>\n";
|
||||
echo '<p><label for="groups"><span id="groupslabel">'.get_string('groups').':</span><span id="thegrouping"> </span></label></p>'."\n";
|
||||
|
||||
if (ajaxenabled()) { // TODO: move this to JS init!
|
||||
if ($ajaxenabled) { // TODO: move this to JS init!
|
||||
$onchange = 'M.core_group.membersCombo.refreshMembers();';
|
||||
} else {
|
||||
$onchange = '';
|
||||
@@ -275,7 +276,7 @@ echo '</table>'."\n";
|
||||
echo '</div>'."\n";
|
||||
echo '</form>'."\n";
|
||||
|
||||
if (ajaxenabled()) {
|
||||
if ($ajaxenabled) {
|
||||
$PAGE->requires->js_init_call('M.core_group.init_index', array($CFG->wwwroot, $courseid));
|
||||
$PAGE->requires->js_init_call('M.core_group.groupslist', array($preventgroupremoval));
|
||||
}
|
||||
|
||||
@@ -64,8 +64,9 @@ function groups_add_member($grouporid, $userorid, $component=null, $itemid=0) {
|
||||
$group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
//check if the user a participant of the group course
|
||||
if (!is_enrolled(context_course::instance($group->courseid), $userid)) {
|
||||
// Check if the user a participant of the group course.
|
||||
$context = context_course::instance($group->courseid);
|
||||
if (!is_enrolled($context, $userid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -99,16 +100,23 @@ function groups_add_member($grouporid, $userorid, $component=null, $itemid=0) {
|
||||
|
||||
$DB->insert_record('groups_members', $member);
|
||||
|
||||
//update group info
|
||||
// Update group info, and group object.
|
||||
$DB->set_field('groups', 'timemodified', $member->timeadded, array('id'=>$groupid));
|
||||
$group->timemodified = $member->timeadded;
|
||||
|
||||
//trigger groups events
|
||||
$eventdata = new stdClass();
|
||||
$eventdata->groupid = $groupid;
|
||||
$eventdata->userid = $userid;
|
||||
$eventdata->component = $member->component;
|
||||
$eventdata->itemid = $member->itemid;
|
||||
events_trigger('groups_member_added', $eventdata);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => $context,
|
||||
'objectid' => $groupid,
|
||||
'relateduserid' => $userid,
|
||||
'other' => array(
|
||||
'component' => $member->component,
|
||||
'itemid' => $member->itemid
|
||||
)
|
||||
);
|
||||
$event = \core\event\group_member_added::create($params);
|
||||
$event->add_record_snapshot('groups', $group);
|
||||
$event->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -174,10 +182,8 @@ function groups_remove_member($grouporid, $userorid) {
|
||||
|
||||
if (is_object($userorid)) {
|
||||
$userid = $userorid->id;
|
||||
$user = $userorid;
|
||||
} else {
|
||||
$userid = $userorid;
|
||||
$user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
if (is_object($grouporid)) {
|
||||
@@ -194,14 +200,20 @@ function groups_remove_member($grouporid, $userorid) {
|
||||
|
||||
$DB->delete_records('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
|
||||
|
||||
//update group info
|
||||
$DB->set_field('groups', 'timemodified', time(), array('id'=>$groupid));
|
||||
// Update group info.
|
||||
$time = time();
|
||||
$DB->set_field('groups', 'timemodified', $time, array('id' => $groupid));
|
||||
$group->timemodified = $time;
|
||||
|
||||
//trigger groups events
|
||||
$eventdata = new stdClass();
|
||||
$eventdata->groupid = $groupid;
|
||||
$eventdata->userid = $userid;
|
||||
events_trigger('groups_member_removed', $eventdata);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => context_course::instance($group->courseid),
|
||||
'objectid' => $groupid,
|
||||
'relateduserid' => $userid
|
||||
);
|
||||
$event = \core\event\group_member_removed::create($params);
|
||||
$event->add_record_snapshot('groups', $group);
|
||||
$event->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -257,8 +269,14 @@ function groups_create_group($data, $editform = false, $editoroptions = false) {
|
||||
// Invalidate the grouping cache for the course
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($course->id));
|
||||
|
||||
//trigger groups events
|
||||
events_trigger('groups_group_created', $group);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => $context,
|
||||
'objectid' => $group->id
|
||||
);
|
||||
$event = \core\event\group_created::create($params);
|
||||
$event->add_record_snapshot('groups', $group);
|
||||
$event->trigger();
|
||||
|
||||
return $group->id;
|
||||
}
|
||||
@@ -289,8 +307,6 @@ function groups_create_grouping($data, $editoroptions=null) {
|
||||
}
|
||||
|
||||
$id = $DB->insert_record('groupings', $data);
|
||||
|
||||
//trigger groups events
|
||||
$data->id = $id;
|
||||
|
||||
if ($editoroptions !== null) {
|
||||
@@ -304,7 +320,14 @@ function groups_create_grouping($data, $editoroptions=null) {
|
||||
// Invalidate the grouping cache for the course
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
|
||||
|
||||
events_trigger('groups_grouping_created', $data);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => context_course::instance($data->courseid),
|
||||
'objectid' => $id
|
||||
);
|
||||
$event = \core\event\grouping_created::create($params);
|
||||
$event->set_legacy_eventdata($data);
|
||||
$event->trigger();
|
||||
|
||||
return $id;
|
||||
}
|
||||
@@ -376,9 +399,14 @@ function groups_update_group($data, $editform = false, $editoroptions = false) {
|
||||
groups_update_group_icon($group, $data, $editform);
|
||||
}
|
||||
|
||||
//trigger groups events
|
||||
events_trigger('groups_group_updated', $group);
|
||||
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => $context,
|
||||
'objectid' => $group->id
|
||||
);
|
||||
$event = \core\event\group_updated::create($params);
|
||||
$event->add_record_snapshot('groups', $group);
|
||||
$event->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -408,8 +436,14 @@ function groups_update_grouping($data, $editoroptions=null) {
|
||||
// Invalidate the group data.
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
|
||||
|
||||
//trigger groups events
|
||||
events_trigger('groups_grouping_updated', $data);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => context_course::instance($data->courseid),
|
||||
'objectid' => $data->id
|
||||
);
|
||||
$event = \core\event\grouping_updated::create($params);
|
||||
$event->set_legacy_eventdata($data);
|
||||
$event->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -454,8 +488,14 @@ function groups_delete_group($grouporid) {
|
||||
// Invalidate the grouping cache for the course
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($group->courseid));
|
||||
|
||||
//trigger groups events
|
||||
events_trigger('groups_group_deleted', $group);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => $context,
|
||||
'objectid' => $groupid
|
||||
);
|
||||
$event = \core\event\group_deleted::create($params);
|
||||
$event->add_record_snapshot('groups', $group);
|
||||
$event->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -499,8 +539,14 @@ function groups_delete_grouping($groupingorid) {
|
||||
// Invalidate the grouping cache for the course
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($grouping->courseid));
|
||||
|
||||
//trigger groups events
|
||||
events_trigger('groups_grouping_deleted', $grouping);
|
||||
// Trigger group event.
|
||||
$params = array(
|
||||
'context' => $context,
|
||||
'objectid' => $groupingid
|
||||
);
|
||||
$event = \core\event\grouping_deleted::create($params);
|
||||
$event->add_record_snapshot('groupings', $grouping);
|
||||
$event->trigger();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -521,23 +567,27 @@ function groups_delete_group_members($courseid, $userid=0, $showfeedback=false)
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = array('courseid'=>$courseid);
|
||||
// Select * so that the function groups_remove_member() gets the whole record.
|
||||
$groups = $DB->get_recordset('groups', array('courseid' => $courseid));
|
||||
foreach ($groups as $group) {
|
||||
if ($userid) {
|
||||
$userids = array($userid);
|
||||
} else {
|
||||
$userids = $DB->get_fieldset_select('groups_members', 'userid', 'groupid = :groupid', array('groupid' => $group->id));
|
||||
}
|
||||
|
||||
if ($userid) {
|
||||
$usersql = "AND userid = :userid";
|
||||
$params['userid'] = $userid;
|
||||
} else {
|
||||
$usersql = "";
|
||||
foreach ($userids as $id) {
|
||||
groups_remove_member($group, $id);
|
||||
}
|
||||
}
|
||||
|
||||
$groupssql = "SELECT id FROM {groups} g WHERE g.courseid = :courseid";
|
||||
$DB->delete_records_select('groups_members', "groupid IN ($groupssql) $usersql", $params);
|
||||
|
||||
//trigger groups events
|
||||
// TODO MDL-41312 Remove events_trigger_legacy('groups_members_removed').
|
||||
// This event is kept here for backwards compatibility, because it cannot be
|
||||
// translated to a new event as it is wrong.
|
||||
$eventdata = new stdClass();
|
||||
$eventdata->courseid = $courseid;
|
||||
$eventdata->userid = $userid;
|
||||
events_trigger('groups_members_removed', $eventdata);
|
||||
events_trigger_legacy('groups_members_removed', $eventdata);
|
||||
|
||||
if ($showfeedback) {
|
||||
echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groupmembers', 'group'), 'notifysuccess');
|
||||
@@ -557,13 +607,20 @@ function groups_delete_groupings_groups($courseid, $showfeedback=false) {
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
$groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
|
||||
$DB->delete_records_select('groupings_groups', "groupid IN ($groupssql)", array($courseid));
|
||||
$results = $DB->get_recordset_select('groupings_groups', "groupid IN ($groupssql)",
|
||||
array($courseid), '', 'groupid, groupingid');
|
||||
|
||||
foreach ($results as $result) {
|
||||
groups_unassign_grouping($result->groupingid, $result->groupid, false);
|
||||
}
|
||||
|
||||
// Invalidate the grouping cache for the course
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
|
||||
|
||||
//trigger groups events
|
||||
events_trigger('groups_groupings_groups_removed', $courseid);
|
||||
// TODO MDL-41312 Remove events_trigger_legacy('groups_groupings_groups_removed').
|
||||
// This event is kept here for backwards compatibility, because it cannot be
|
||||
// translated to a new event as it is wrong.
|
||||
events_trigger_legacy('groups_groupings_groups_removed', $courseid);
|
||||
|
||||
// no need to show any feedback here - we delete usually first groupings and then groups
|
||||
|
||||
@@ -580,31 +637,18 @@ function groups_delete_groupings_groups($courseid, $showfeedback=false) {
|
||||
function groups_delete_groups($courseid, $showfeedback=false) {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
// delete any uses of groups
|
||||
// Any associated files are deleted as part of groups_delete_groupings_groups
|
||||
groups_delete_groupings_groups($courseid, $showfeedback);
|
||||
groups_delete_group_members($courseid, 0, $showfeedback);
|
||||
|
||||
// delete group pictures and descriptions
|
||||
$context = context_course::instance($courseid);
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($context->id, 'group');
|
||||
|
||||
// delete group calendar events
|
||||
$groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
|
||||
$DB->delete_records_select('event', "groupid IN ($groupssql)", array($courseid));
|
||||
|
||||
$context = context_course::instance($courseid);
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($context->id, 'group');
|
||||
|
||||
$DB->delete_records('groups', array('courseid'=>$courseid));
|
||||
$groups = $DB->get_recordset('groups', array('courseid' => $courseid));
|
||||
foreach ($groups as $group) {
|
||||
groups_delete_group($group);
|
||||
}
|
||||
|
||||
// Invalidate the grouping cache for the course
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
|
||||
|
||||
// trigger groups events
|
||||
events_trigger('groups_groups_deleted', $courseid);
|
||||
// TODO MDL-41312 Remove events_trigger_legacy('groups_groups_deleted').
|
||||
// This event is kept here for backwards compatibility, because it cannot be
|
||||
// translated to a new event as it is wrong.
|
||||
events_trigger_legacy('groups_groups_deleted', $courseid);
|
||||
|
||||
if ($showfeedback) {
|
||||
echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groups', 'group'), 'notifysuccess');
|
||||
@@ -623,28 +667,18 @@ function groups_delete_groups($courseid, $showfeedback=false) {
|
||||
function groups_delete_groupings($courseid, $showfeedback=false) {
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
// delete any uses of groupings
|
||||
$sql = "DELETE FROM {groupings_groups}
|
||||
WHERE groupingid in (SELECT id FROM {groupings} g WHERE g.courseid = ?)";
|
||||
$DB->execute($sql, array($courseid));
|
||||
$groupings = $DB->get_recordset_select('groupings', 'courseid = ?', array($courseid));
|
||||
foreach ($groupings as $grouping) {
|
||||
groups_delete_grouping($grouping);
|
||||
}
|
||||
|
||||
// remove the default groupingid from course
|
||||
$DB->set_field('course', 'defaultgroupingid', 0, array('id'=>$courseid));
|
||||
// remove the groupingid from all course modules
|
||||
$DB->set_field('course_modules', 'groupingid', 0, array('course'=>$courseid));
|
||||
|
||||
// Delete all files associated with groupings for this course
|
||||
$context = context_course::instance($courseid);
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($context->id, 'grouping');
|
||||
|
||||
$DB->delete_records('groupings', array('courseid'=>$courseid));
|
||||
|
||||
// Invalidate the grouping cache for the course
|
||||
// Invalidate the grouping cache for the course.
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
|
||||
|
||||
// trigger groups events
|
||||
events_trigger('groups_groupings_deleted', $courseid);
|
||||
// TODO MDL-41312 Remove events_trigger_legacy('groups_groupings_deleted').
|
||||
// This event is kept here for backwards compatibility, because it cannot be
|
||||
// translated to a new event as it is wrong.
|
||||
events_trigger_legacy('groups_groupings_deleted', $courseid);
|
||||
|
||||
if ($showfeedback) {
|
||||
echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groupings', 'group'), 'notifysuccess');
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for group lib.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/group/lib.php');
|
||||
|
||||
/**
|
||||
* Group lib testcase.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_group_lib_testcase extends advanced_testcase {
|
||||
|
||||
public function test_member_added_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
groups_add_member($group->id, $user->id, 'mod_workshop', '123');
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$expected = new stdClass();
|
||||
$expected->groupid = $group->id;
|
||||
$expected->userid = $user->id;
|
||||
$expected->component = 'mod_workshop';
|
||||
$expected->itemid = '123';
|
||||
$this->assertEventLegacyData($expected, $event);
|
||||
$this->assertSame('groups_member_added', $event->get_legacy_eventname());
|
||||
$this->assertInstanceOf('\core\event\group_member_added', $event);
|
||||
$this->assertEquals($user->id, $event->relateduserid);
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_member_removed_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
$this->getDataGenerator()->create_group_member(array('userid' => $user->id, 'groupid' => $group->id));
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
groups_remove_member($group->id, $user->id);
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$expected = new stdClass();
|
||||
$expected->groupid = $group->id;
|
||||
$expected->userid = $user->id;
|
||||
$this->assertEventLegacyData($expected, $event);
|
||||
$this->assertSame('groups_member_removed', $event->get_legacy_eventname());
|
||||
$this->assertInstanceOf('\core\event\group_member_removed', $event);
|
||||
$this->assertEquals($user->id, $event->relateduserid);
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_group_created_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
$group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\core\event\group_created', $event);
|
||||
$this->assertEventLegacyData($group, $event);
|
||||
$this->assertSame('groups_group_created', $event->get_legacy_eventname());
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_grouping_created_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
$group = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\core\event\grouping_created', $event);
|
||||
|
||||
// 'Repairing' the object for comparison because of type of variables being wrong.
|
||||
$group->id = (int) $group->id;
|
||||
$group->timemodified = (int) $group->timemodified;
|
||||
$group->timecreated = (int) $group->timecreated;
|
||||
unset($group->idnumber);
|
||||
unset($group->configdata);
|
||||
$this->assertEventLegacyData($group, $event);
|
||||
$this->assertSame('groups_grouping_created', $event->get_legacy_eventname());
|
||||
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_group_updated_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
$data = new stdClass();
|
||||
$data->id = $group->id;
|
||||
$data->courseid = $course->id;
|
||||
$data->name = 'Backend team';
|
||||
groups_update_group($data);
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\core\event\group_updated', $event);
|
||||
$group->name = $data->name;
|
||||
$this->assertEventLegacyData($group, $event);
|
||||
$this->assertSame('groups_group_updated', $event->get_legacy_eventname());
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_grouping_updated_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$group = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
$data = new stdClass();
|
||||
$data->id = $group->id;
|
||||
$data->courseid = $course->id;
|
||||
$data->name = 'Backend team';
|
||||
$mostaccuratetimemodified = time();
|
||||
groups_update_grouping($data);
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\core\event\grouping_updated', $event);
|
||||
|
||||
// 'Repairing' the object for comparison because of type of variables being wrong.
|
||||
$data->id = (int) $group->id;
|
||||
$data->timemodified = $mostaccuratetimemodified;
|
||||
$this->assertEventLegacyData($data, $event);
|
||||
$this->assertSame('groups_grouping_updated', $event->get_legacy_eventname());
|
||||
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_group_deleted_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
groups_delete_group($group->id);
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\core\event\group_deleted', $event);
|
||||
$this->assertEventLegacyData($group, $event);
|
||||
$this->assertSame('groups_group_deleted', $event->get_legacy_eventname());
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_grouping_deleted_event() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$group = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
groups_delete_grouping($group->id);
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\core\event\grouping_deleted', $event);
|
||||
$this->assertEventLegacyData($group, $event);
|
||||
$this->assertSame('groups_grouping_deleted', $event->get_legacy_eventname());
|
||||
$this->assertEquals(context_course::instance($course->id), $event->get_context());
|
||||
$this->assertEquals($group->id, $event->objectid);
|
||||
}
|
||||
|
||||
public function test_groups_delete_group_members() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
|
||||
$group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
|
||||
// Test deletion of all the users.
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
|
||||
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
groups_delete_group_members($course->id);
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
|
||||
// Test deletion of a specific user.
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
|
||||
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
groups_delete_group_members($course->id, $user2->id);
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
}
|
||||
|
||||
public function test_groups_remove_member() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
|
||||
$group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
|
||||
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
groups_remove_member($group1->id, $user1->id);
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
groups_remove_member($group1->id, $user2->id);
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user2->id)));
|
||||
groups_remove_member($group2->id, $user1->id);
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group2->id, 'userid' => $user1->id)));
|
||||
}
|
||||
|
||||
public function test_groups_delete_groupings_groups() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$group1c2 = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));
|
||||
$grouping1 = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$grouping2 = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$grouping1c2 = $this->getDataGenerator()->create_grouping(array('courseid' => $course2->id));
|
||||
|
||||
$this->getDataGenerator()->create_grouping_group(array('groupingid' => $grouping1->id, 'groupid' => $group1->id));
|
||||
$this->getDataGenerator()->create_grouping_group(array('groupingid' => $grouping1->id, 'groupid' => $group2->id));
|
||||
$this->getDataGenerator()->create_grouping_group(array('groupingid' => $grouping2->id, 'groupid' => $group1->id));
|
||||
$this->getDataGenerator()->create_grouping_group(array('groupingid' => $grouping1c2->id, 'groupid' => $group1c2->id));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups', array('groupid' => $group2->id, 'groupingid' => $grouping1->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping2->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups',
|
||||
array('groupid' => $group1c2->id, 'groupingid' => $grouping1c2->id)));
|
||||
groups_delete_groupings_groups($course->id);
|
||||
$this->assertFalse($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
$this->assertFalse($DB->record_exists('groupings_groups', array('groupid' => $group2->id, 'groupingid' => $grouping1->id)));
|
||||
$this->assertFalse($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping2->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups',
|
||||
array('groupid' => $group1c2->id, 'groupingid' => $grouping1c2->id)));
|
||||
}
|
||||
|
||||
public function test_groups_delete_groups() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$group1c2 = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));
|
||||
$grouping1 = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$grouping2 = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
|
||||
$this->getDataGenerator()->create_grouping_group(array('groupid' => $group1->id, 'groupingid' => $grouping1->id));
|
||||
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $group1->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $group2->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $group1c2->id, 'courseid' => $course2->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings', array('id' => $grouping1->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
groups_delete_groups($course->id);
|
||||
$this->assertFalse($DB->record_exists('groups', array('id' => $group1->id, 'courseid' => $course->id)));
|
||||
$this->assertFalse($DB->record_exists('groups', array('id' => $group2->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $group1c2->id, 'courseid' => $course2->id)));
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $group1->id, 'userid' => $user1->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings', array('id' => $grouping1->id, 'courseid' => $course->id)));
|
||||
$this->assertFalse($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
}
|
||||
|
||||
public function test_groups_delete_groupings() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
|
||||
$grouping1 = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$grouping2 = $this->getDataGenerator()->create_grouping(array('courseid' => $course->id));
|
||||
$grouping1c2 = $this->getDataGenerator()->create_grouping(array('courseid' => $course2->id));
|
||||
$this->getDataGenerator()->create_grouping_group(array('groupid' => $group1->id, 'groupingid' => $grouping1->id));
|
||||
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $group1->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings', array('id' => $grouping1->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings', array('id' => $grouping2->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings', array('id' => $grouping1c2->id, 'courseid' => $course2->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
groups_delete_groupings($course->id);
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $group1->id, 'courseid' => $course->id)));
|
||||
$this->assertFalse($DB->record_exists('groupings', array('id' => $grouping1->id, 'courseid' => $course->id)));
|
||||
$this->assertFalse($DB->record_exists('groupings', array('id' => $grouping2->id, 'courseid' => $course->id)));
|
||||
$this->assertTrue($DB->record_exists('groupings', array('id' => $grouping1c2->id, 'courseid' => $course2->id)));
|
||||
$this->assertFalse($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
}
|
||||
}
|
||||
@@ -250,6 +250,9 @@ $string['skipmodifdays'] = 'Skip courses not modified since';
|
||||
$string['skipmodifdayshelp'] = 'Choose to skip courses that have not been modified since a number of days';
|
||||
$string['skipmodifprev'] = 'Skip courses not modified since previous backup';
|
||||
$string['skipmodifprevhelp'] = 'Choose whether or not to skip courses that have not been modified since previous backup';
|
||||
$string['title'] = 'Title';
|
||||
$string['totalcategorysearchresults'] = 'Total categories: {$a}';
|
||||
$string['totalcoursesearchresults'] = 'Total courses: {$a}';
|
||||
$string['userinfo'] = 'Userinfo';
|
||||
$string['module'] = 'Module';
|
||||
$string['morecoursesearchresults'] = 'More than {$a} courses found, showing first {$a} results';
|
||||
|
||||
@@ -67,6 +67,14 @@ $string['errorremovenotpermitted'] = 'You do not have permission to remove autom
|
||||
$string['errorselectone'] = 'Please select a single group before choosing this option';
|
||||
$string['errorselectsome'] = 'Please select one or more groups before choosing this option';
|
||||
$string['evenallocation'] = 'Note: To keep group allocation even, the actual number of members per group differs from the number you specified.';
|
||||
$string['event_group_created'] = 'Group created';
|
||||
$string['event_group_deleted'] = 'Group deleted';
|
||||
$string['event_group_member_added'] = 'Group member added';
|
||||
$string['event_group_member_removed'] = 'Group member removed';
|
||||
$string['event_group_updated'] = 'Group updated';
|
||||
$string['event_grouping_created'] = 'Grouping created';
|
||||
$string['event_grouping_deleted'] = 'Grouping deleted';
|
||||
$string['event_grouping_updated'] = 'Grouping updated';
|
||||
$string['existingmembers'] = 'Existing members: {$a}';
|
||||
$string['filtergroups'] = 'Filter groups by:';
|
||||
$string['group'] = 'Group';
|
||||
|
||||
@@ -869,6 +869,7 @@ $string['chooselogs'] = 'Choose which logs you want to see';
|
||||
$string['choosereportfilter'] = 'Choose a filter for the report';
|
||||
$string['choosetheme'] = 'Choose theme';
|
||||
$string['chooseuser'] = 'Choose a user';
|
||||
$string['eventcontentviewed'] = 'Content viewed';
|
||||
$string['icqnumber'] = 'ICQ number';
|
||||
$string['icon'] = 'Icon';
|
||||
$string['idnumber'] = 'ID number';
|
||||
|
||||
@@ -30,7 +30,7 @@ $string['alltagpages'] = 'All tag pages';
|
||||
$string['count'] = 'Count';
|
||||
$string['delete'] = 'Delete';
|
||||
$string['deleted'] = 'Deleted';
|
||||
$string['deletedcoursetags'] = 'Deleted - course tags';
|
||||
$string['deletedcoursetags'] = 'Deleted - Course tags';
|
||||
$string['description'] = 'Description';
|
||||
$string['edittag'] = 'Edit this tag';
|
||||
$string['entertags'] = 'Enter tags separated by commas';
|
||||
|
||||
@@ -329,6 +329,9 @@ function uninstall_plugin($type, $name) {
|
||||
// Finally purge all caches.
|
||||
purge_all_caches();
|
||||
|
||||
// Invalidate the hash used for upgrade detections.
|
||||
set_config('allversionshash', '');
|
||||
|
||||
echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ function ajaxenabled(array $browsers = null) {
|
||||
if (!empty($browsers)) {
|
||||
$valid = false;
|
||||
foreach ($browsers as $brand => $version) {
|
||||
if (check_browser_version($brand, $version)) {
|
||||
if (core_useragent::check_browser_version($brand, $version)) {
|
||||
$valid = true;
|
||||
}
|
||||
}
|
||||
@@ -61,11 +61,11 @@ function ajaxenabled(array $browsers = null) {
|
||||
}
|
||||
}
|
||||
|
||||
$ie = check_browser_version('MSIE', 6.0);
|
||||
$ff = check_browser_version('Gecko', 20051106);
|
||||
$op = check_browser_version('Opera', 9.0);
|
||||
$sa = check_browser_version('Safari', 412);
|
||||
$ch = check_browser_version('Chrome', 6);
|
||||
$ie = core_useragent::check_browser_version('MSIE', 6.0);
|
||||
$ff = core_useragent::check_browser_version('Gecko', 20051106);
|
||||
$op = core_useragent::check_browser_version('Opera', 9.0);
|
||||
$sa = core_useragent::check_browser_version('Safari', 412);
|
||||
$ch = core_useragent::check_browser_version('Chrome', 6);
|
||||
|
||||
if (!$ie && !$ff && !$op && !$sa && !$ch) {
|
||||
/** @see http://en.wikipedia.org/wiki/User_agent */
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for (some of) ../ajaxlib.php.
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/ajax/ajaxlib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for ../ajaxlib.php functions.
|
||||
*
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_ajaxlib_testcase extends advanced_testcase {
|
||||
|
||||
var $user_agents = array(
|
||||
'MSIE' => array(
|
||||
'5.5' => array('Windows 2000' => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)'),
|
||||
'6.0' => array('Windows XP SP2' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'),
|
||||
'7.0' => array('Windows XP SP2' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)')
|
||||
),
|
||||
'Firefox' => array(
|
||||
'1.0.6' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6'),
|
||||
'1.5' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8) Gecko/20051107 Firefox/1.5'),
|
||||
'1.5.0.1' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1'),
|
||||
'2.0' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1',
|
||||
'Ubuntu Linux AMD64' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)')
|
||||
),
|
||||
'Safari' => array(
|
||||
'312' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312'),
|
||||
'2.0' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412 (KHTML, like Gecko) Safari/412')
|
||||
),
|
||||
'Opera' => array(
|
||||
'8.51' => array('Windows XP' => 'Opera/8.51 (Windows NT 5.1; U; en)'),
|
||||
'9.0' => array('Windows XP' => 'Opera/9.0 (Windows NT 5.1; U; en)',
|
||||
'Debian Linux' => 'Opera/9.01 (X11; Linux i686; U; en)')
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Uses the array of user agents to test ajax_lib::ajaxenabled
|
||||
*/
|
||||
function test_ajaxenabled() {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$CFG->enableajax = 1;
|
||||
|
||||
// Should be true
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
|
||||
$this->assertTrue(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['1.5']['Windows XP'];
|
||||
$this->assertTrue(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['2.0']['Mac OS X'];
|
||||
$this->assertTrue(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
|
||||
$this->assertTrue(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['6.0']['Windows XP SP2'];
|
||||
$this->assertTrue(ajaxenabled());
|
||||
|
||||
// Should be false
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['1.0.6']['Windows XP'];
|
||||
$this->assertFalse(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['312']['Mac OS X'];
|
||||
$this->assertFalse(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['8.51']['Windows XP'];
|
||||
$this->assertFalse(ajaxenabled());
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['5.5']['Windows 2000'];
|
||||
$this->assertFalse(ajaxenabled());
|
||||
|
||||
// Test array of tested browsers
|
||||
$tested_browsers = array('MSIE' => 6.0, 'Gecko' => 20061111);
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
|
||||
$this->assertTrue(ajaxenabled($tested_browsers));
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['7.0']['Windows XP SP2'];
|
||||
$this->assertTrue(ajaxenabled($tested_browsers));
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['2.0']['Mac OS X'];
|
||||
$this->assertFalse(ajaxenabled($tested_browsers));
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
|
||||
$this->assertFalse(ajaxenabled($tested_browsers));
|
||||
|
||||
$tested_browsers = array('Safari' => 412, 'Opera' => 9.0);
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
|
||||
$this->assertFalse(ajaxenabled($tested_browsers));
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['7.0']['Windows XP SP2'];
|
||||
$this->assertFalse(ajaxenabled($tested_browsers));
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['2.0']['Mac OS X'];
|
||||
$this->assertTrue(ajaxenabled($tested_browsers));
|
||||
|
||||
$_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
|
||||
$this->assertTrue(ajaxenabled($tested_browsers));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?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/>.
|
||||
/**
|
||||
* Abstract event for content viewing.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2013 Ankit Agarwal
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
|
||||
/**
|
||||
* Class content_viewed.
|
||||
*
|
||||
* Base class for a content view event. Each plugin must extend this to create their own content view event.
|
||||
*
|
||||
* An example usage:-
|
||||
* $event = \report_participation\event\content_viewed::create(array('courseid' => $course->id,
|
||||
* 'other' => array('content' => 'participants'));
|
||||
* $event->set_page_detail();
|
||||
* $event->set_legacy_logdata(array($course->id, "course", "report participation",
|
||||
* "report/participation/index.php?id=$course->id", $course->id));
|
||||
* $event->trigger();
|
||||
* where \report_participation\event\content_viewed extends \core\event\content_viewed
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2013 Ankit Agarwal
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class content_viewed extends base {
|
||||
|
||||
/** @var null|array $legacylogdata Legacy log data */
|
||||
protected $legacylogdata = null;
|
||||
|
||||
/**
|
||||
* Set basic properties of the event.
|
||||
*/
|
||||
protected function init() {
|
||||
global $PAGE;
|
||||
|
||||
$this->data['crud'] = 'r';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->context = $PAGE->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set basic page properties.
|
||||
*/
|
||||
public function set_page_detail() {
|
||||
global $PAGE;
|
||||
if (!isset($this->data['other'])) {
|
||||
$this->data['other'] = array();
|
||||
}
|
||||
$this->data['other'] = array_merge(array('url' => $PAGE->url->out_as_local_url(false),
|
||||
'heading' => $PAGE->heading,
|
||||
'title' => $PAGE->title), $this->data['other']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns localised general event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventcontentviewed', 'moodle');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns non-localised description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return 'User with id ' . $this->userid . ' viewed content ' . $this->get_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set legacy logdata.
|
||||
*
|
||||
* @param array $legacydata legacy logdata.
|
||||
*/
|
||||
public function set_legacy_logdata(array $legacydata) {
|
||||
$this->legacylogdata = $legacydata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get legacy logdata.
|
||||
*
|
||||
* @return null|array legacy log data.
|
||||
*/
|
||||
protected function get_legacy_logdata() {
|
||||
return $this->legacylogdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception when validation does not pass.
|
||||
* @return void
|
||||
*/
|
||||
protected function validate_data() {
|
||||
if (debugging('', DEBUG_DEVELOPER)) {
|
||||
// Make sure this class is never used without a content identifier.
|
||||
if (empty($this->other['content'])) {
|
||||
throw new \coding_exception('content_viewed event must define content identifier.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group created event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group created event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_created extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} created the group {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
return $this->get_record_snapshot('groups', $this->objectid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_group_created';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_group_created', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groups';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group deleted event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group deleted event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_deleted extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} deleted the group {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
return $this->get_record_snapshot('groups', $this->objectid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_group_deleted';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_group_deleted', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groups';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group member added event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group member added event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_member_added extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} added user {$this->relateduserid} to group {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->groupid = $this->objectid;
|
||||
$eventdata->userid = $this->relateduserid;
|
||||
$eventdata->component = $this->other['component'];
|
||||
$eventdata->itemid = $this->other['itemid'];
|
||||
return $eventdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_member_added';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_group_member_added', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groups';
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
* @return void
|
||||
*/
|
||||
protected function validate_data() {
|
||||
if (!isset($this->other['component']) || !isset($this->other['itemid'])) {
|
||||
throw new \coding_exception('The component and itemid need to be set in $other, even if empty.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group member removed event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group member removed event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_member_removed extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} removed user {$this->relateduserid} from group {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->groupid = $this->objectid;
|
||||
$eventdata->userid = $this->relateduserid;
|
||||
return $eventdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_member_removed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_group_member_removed', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groups';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group updated event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group updated event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_updated extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} updated the group {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
return $this->get_record_snapshot('groups', $this->objectid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_group_updated';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_group_updated', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groups';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group grouping created event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group grouping created event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grouping_created extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Legacy data.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $legacydata;
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} created the grouping {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
return $this->legacydata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_grouping_created';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_grouping_created', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/groupings/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groupings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set legacy data.
|
||||
*
|
||||
* @param mixed $legacydata.
|
||||
* @return void
|
||||
*/
|
||||
public function set_legacy_eventdata($legacydata) {
|
||||
$this->legacydata = $legacydata;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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/>.
|
||||
|
||||
/**
|
||||
* core_group grouping deleted event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group grouping deleted event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grouping_deleted extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Legacy data.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $legacydata;
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} deleted the grouping {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
return $this->get_record_snapshot('groupings', $this->objectid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_grouping_deleted';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_grouping_deleted', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/groupings/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groupings';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* core_group grouping updated event.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\event;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* core_group grouping updated event class.
|
||||
*
|
||||
* @package core_group
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grouping_updated extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Legacy data.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $legacydata;
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "User {$this->userid} updated the grouping {$this->objectid}.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy event data if get_legacy_eventname() is not empty.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function get_legacy_eventdata() {
|
||||
return $this->legacydata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the legacy event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_legacy_eventname() {
|
||||
return 'groups_grouping_updated';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('event_grouping_updated', 'group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/group/groupings/index.php', array('id' => $this->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['level'] = self::LEVEL_OTHER;
|
||||
$this->data['objecttable'] = 'groupings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set legacy data.
|
||||
*
|
||||
* @param mixed $legacydata.
|
||||
* @return void
|
||||
*/
|
||||
public function set_legacy_eventdata($legacydata) {
|
||||
$this->legacydata = $legacydata;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class user_loggedin extends \core\event\base {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_legacy_logdata() {
|
||||
protected function get_legacy_logdata() {
|
||||
return array(SITEID, 'user', 'login', "view.php?id=" . $this->data['objectid'] . "&course=".SITEID,
|
||||
$this->data['objectid'], 0, $this->data['objectid']);
|
||||
}
|
||||
@@ -60,7 +60,7 @@ class user_loggedin extends \core\event\base {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return new get_string('event_user_loggedin', 'auth');
|
||||
return get_string('event_user_loggedin', 'auth');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -238,6 +238,36 @@ class core_text {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the last occurrence of a character in a string within another.
|
||||
* UTF-8 ONLY safe mb_strrchr().
|
||||
*
|
||||
* @param string $haystack The string from which to get the last occurrence of needle.
|
||||
* @param string $needle The string to find in haystack.
|
||||
* @param boolean $part If true, returns the portion before needle, else return the portion after (including needle).
|
||||
* @return string|false False when not found.
|
||||
* @since 2.4.6, 2.5.2, 2.6
|
||||
*/
|
||||
public static function strrchr($haystack, $needle, $part = false) {
|
||||
|
||||
if (function_exists('mb_strrchr')) {
|
||||
return mb_strrchr($haystack, $needle, $part, 'UTF-8');
|
||||
}
|
||||
|
||||
$pos = self::strrpos($haystack, $needle);
|
||||
if ($pos === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$length = null;
|
||||
if ($part) {
|
||||
$length = $pos;
|
||||
$pos = 0;
|
||||
}
|
||||
|
||||
return self::substr($haystack, $pos, $length, 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Multibyte safe strlen() function, uses mbstring or iconv for UTF-8, falls back to typo3.
|
||||
*
|
||||
@@ -331,7 +361,7 @@ class core_text {
|
||||
* @return int the numeric position of the last occurrence of needle in haystack
|
||||
*/
|
||||
public static function strrpos($haystack, $needle) {
|
||||
if (function_exists('mb_strpos')) {
|
||||
if (function_exists('mb_strrpos')) {
|
||||
return mb_strrpos($haystack, $needle, null, 'UTF-8');
|
||||
} else {
|
||||
return iconv_strrpos($haystack, $needle, 'UTF-8');
|
||||
|
||||
@@ -0,0 +1,751 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Environment class to aid with the detection and establishment of the working environment.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2013 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* The user agent class.
|
||||
*
|
||||
* It's important to note that we do not like browser sniffing and its use in core code is highly discouraged.
|
||||
* No new uses of this API will be integrated unless there is absolutely no alternative.
|
||||
*
|
||||
* This API supports the few browser checks we do have in core, all of which one day will hopefully be removed.
|
||||
* The API will remain to support any third party use out there, however at some point like all code it will be deprecated.
|
||||
*
|
||||
* Use sparingly and only with good cause!
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2013 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_useragent {
|
||||
|
||||
/**
|
||||
* The default for devices, think of as a computer.
|
||||
*/
|
||||
const DEVICETYPE_DEFAULT = 'default';
|
||||
/**
|
||||
* Legacy devices, or at least legacy browsers. These are older devices/browsers
|
||||
* that don't support standards.
|
||||
*/
|
||||
const DEVICETYPE_LEGACY = 'legacy';
|
||||
/**
|
||||
* Mobile devices like your cell phone or hand held gaming device.
|
||||
*/
|
||||
const DEVICETYPE_MOBILE = 'mobile';
|
||||
/**
|
||||
* Tables, larger than hand held, but still easily portable and smaller than a laptop.
|
||||
*/
|
||||
const DEVICETYPE_TABLET = 'tablet';
|
||||
|
||||
/**
|
||||
* An instance of this class.
|
||||
* @var core_useragent
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* The device types we track.
|
||||
* @var array
|
||||
*/
|
||||
public static $devicetypes = array(
|
||||
self::DEVICETYPE_DEFAULT,
|
||||
self::DEVICETYPE_LEGACY,
|
||||
self::DEVICETYPE_MOBILE,
|
||||
self::DEVICETYPE_TABLET
|
||||
);
|
||||
|
||||
/**
|
||||
* The current requests user agent string if there was one.
|
||||
* @var string|bool|null Null until initialised, false if none available, or string when available.
|
||||
*/
|
||||
protected $useragent = null;
|
||||
|
||||
/**
|
||||
* The users device type, one of self::DEVICETYPE_*.
|
||||
* @var string null until initialised
|
||||
*/
|
||||
protected $devicetype = null;
|
||||
|
||||
/**
|
||||
* Custom device types entered into the admin interface.
|
||||
* @var array
|
||||
*/
|
||||
protected $devicetypecustoms = array();
|
||||
|
||||
/**
|
||||
* True if the user agent supports the display of svg images. False if not.
|
||||
* @var bool|null Null until initialised, then true or false.
|
||||
*/
|
||||
protected $supportssvg = null;
|
||||
|
||||
/**
|
||||
* Get an instance of the user agent object.
|
||||
*
|
||||
* @param bool $reload If set to true the user agent will be reset and all ascertations remade.
|
||||
* @param string $forceuseragent The string to force as the user agent, don't use unless absolutely unavoidable.
|
||||
* @return core_useragent
|
||||
*/
|
||||
public static function instance($reload = false, $forceuseragent = null) {
|
||||
if (!self::$instance || $reload) {
|
||||
self::$instance = new core_useragent($forceuseragent);
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new user agent object. Publically you must use the instance method above.
|
||||
*
|
||||
* @param string|null $forceuseragent Optional a user agent to force.
|
||||
*/
|
||||
protected function __construct($forceuseragent = null) {
|
||||
global $CFG;
|
||||
if (!empty($CFG->devicedetectregex)) {
|
||||
$this->devicetypecustoms = json_decode($CFG->devicedetectregex);
|
||||
}
|
||||
if ($forceuseragent !== null) {
|
||||
$this->useragent = $forceuseragent;
|
||||
} else if (!empty($_SERVER['HTTP_USER_AGENT'])) {
|
||||
$this->useragent = $_SERVER['HTTP_USER_AGENT'];
|
||||
} else {
|
||||
$this->useragent = false;
|
||||
$this->devicetype = self::DEVICETYPE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user agent string.
|
||||
* @return bool|string The user agent string or false if one isn't available.
|
||||
*/
|
||||
public static function get_user_agent_string() {
|
||||
$instance = self::instance();
|
||||
return $instance->useragent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device type we believe is being used.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_device_type() {
|
||||
$instance = self::instance();
|
||||
if ($instance->devicetype === null) {
|
||||
return $instance->guess_device_type();
|
||||
}
|
||||
return $instance->devicetype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses the device type the user agent is running on.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function guess_device_type() {
|
||||
global $CFG;
|
||||
if (empty($CFG->enabledevicedetection)) {
|
||||
$this->devicetype = self::DEVICETYPE_DEFAULT;
|
||||
return $this->devicetype;
|
||||
}
|
||||
foreach ($this->devicetypecustoms as $value => $regex) {
|
||||
if (preg_match($regex, $this->useragent)) {
|
||||
$this->devicetype = $value;
|
||||
return $this->devicetype;
|
||||
}
|
||||
}
|
||||
if ($this->is_useragent_mobile()) {
|
||||
$this->devicetype = 'mobile';
|
||||
} else if ($this->is_useragent_tablet()) {
|
||||
$this->devicetype = 'tablet';
|
||||
} else if (substr($this->useragent, 0, 34) === 'Mozilla/4.0 (compatible; MSIE 6.0;') {
|
||||
// Safe way to check for IE6 and not get false positives for some IE 7/8 users.
|
||||
$this->devicetype = 'legacy';
|
||||
} else {
|
||||
$this->devicetype = self::DEVICETYPE_DEFAULT;
|
||||
}
|
||||
return $this->devicetype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user appears to be on a mobile device.
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_useragent_mobile() {
|
||||
// Mobile detection PHP direct copy from open source detectmobilebrowser.com.
|
||||
$phonesregex = '/android .+ mobile|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i';
|
||||
$modelsregex = '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i';
|
||||
return (preg_match($phonesregex, $this->useragent) || preg_match($modelsregex, substr($this->useragent, 0, 4)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user appears to be on a tablet.
|
||||
* @return int
|
||||
*/
|
||||
protected function is_useragent_tablet() {
|
||||
$tabletregex = '/Tablet browser|android|iPad|iProd|GT-P1000|GT-I9000|SHW-M180S|SGH-T849|SCH-I800|Build\/ERE27|sholest/i';
|
||||
return (preg_match($tabletregex, $this->useragent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of known device types.
|
||||
*
|
||||
* @param bool $includecustomtypes If set to true we'll include types that have been added by the admin.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_device_type_list($includecustomtypes = true) {
|
||||
$types = self::$devicetypes;
|
||||
if ($includecustomtypes) {
|
||||
$instance = self::instance();
|
||||
$types = array_merge($types, array_keys($instance->devicetypecustoms));
|
||||
}
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the theme to use for the given device type.
|
||||
*
|
||||
* This used to be get_selected_theme_for_device_type.
|
||||
* @param null|string $devicetype The device type to find out for. Defaults to the device the user is using,
|
||||
* @return bool
|
||||
*/
|
||||
public static function get_device_type_theme($devicetype = null) {
|
||||
global $CFG;
|
||||
if ($devicetype === null) {
|
||||
$devicetype = self::get_device_type();
|
||||
}
|
||||
$themevarname = self::get_device_type_cfg_var_name($devicetype);
|
||||
if (empty($CFG->$themevarname)) {
|
||||
return false;
|
||||
}
|
||||
return $CFG->$themevarname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CFG var used to find the theme to use for the given device.
|
||||
*
|
||||
* Used to be get_device_cfg_var_name.
|
||||
*
|
||||
* @param null|string $devicetype The device type to find out for. Defaults to the device the user is using,
|
||||
* @return string
|
||||
*/
|
||||
public static function get_device_type_cfg_var_name($devicetype = null) {
|
||||
if ($devicetype == self::DEVICETYPE_DEFAULT || empty($devicetype)) {
|
||||
return 'theme';
|
||||
}
|
||||
return 'theme' . $devicetype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the device type the user is currently using.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_user_device_type() {
|
||||
$device = self::get_device_type();
|
||||
$switched = get_user_preferences('switchdevice'.$device, false);
|
||||
if ($switched != false) {
|
||||
return $switched;
|
||||
}
|
||||
return $device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the device type we think the user is using to what ever was given.
|
||||
* @param string $newdevice
|
||||
* @return bool
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public static function set_user_device_type($newdevice) {
|
||||
$devicetype = self::get_device_type();
|
||||
if ($newdevice == $devicetype) {
|
||||
unset_user_preference('switchdevice'.$devicetype);
|
||||
return true;
|
||||
} else {
|
||||
$devicetypes = self::get_device_type_list();
|
||||
if (in_array($newdevice, $devicetypes)) {
|
||||
set_user_preference('switchdevice'.$devicetype, $newdevice);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
throw new coding_exception('Invalid device type provided to set_user_device_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user agent matches the given brand and the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string $brand The branch to check for.
|
||||
* @param scalar $version The version if we need to find out if it is equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_browser_version($brand, $version = null) {
|
||||
switch ($brand) {
|
||||
|
||||
case 'MSIE':
|
||||
// Internet Explorer.
|
||||
return self::check_ie_version($version);
|
||||
|
||||
case 'Firefox':
|
||||
// Mozilla Firefox browsers.
|
||||
return self::check_firefox_version($version);
|
||||
|
||||
case 'Chrome':
|
||||
return self::check_chrome_version($version);
|
||||
|
||||
case 'Opera':
|
||||
// Opera.
|
||||
return self::check_opera_version($version);
|
||||
|
||||
case 'Safari':
|
||||
// Desktop version of Apple Safari browser - no mobile or touch devices.
|
||||
return self::check_safari_version($version);
|
||||
|
||||
case 'Safari iOS':
|
||||
// Safari on iPhone, iPad and iPod touch.
|
||||
return self::check_safari_ios_version($version);
|
||||
|
||||
case 'WebKit':
|
||||
// WebKit based browser - everything derived from it (Safari, Chrome, iOS, Android and other mobiles).
|
||||
return self::check_webkit_version($version);
|
||||
|
||||
case 'Gecko':
|
||||
// Gecko based browsers.
|
||||
return self::check_gecko_version($version);
|
||||
|
||||
case 'WebKit Android':
|
||||
// WebKit browser on Android.
|
||||
return self::check_webkit_android_version($version);
|
||||
|
||||
case 'Camino':
|
||||
// OSX browser using Gecke engine.
|
||||
return self::check_camino_version($version);
|
||||
}
|
||||
// Who knows?! doesn't pass anyway.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is camino based and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* Camino browser is at the end of its life, its no longer being developed or supported, just don't worry about it.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
protected static function check_camino_version($version = null) {
|
||||
// OSX browser using Gecko engine.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Camino') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
if (preg_match("/Camino\/([0-9\.]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Firefox based and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_firefox_version($version = null) {
|
||||
// Mozilla Firefox browsers.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Firefox') === false && strpos($useragent, 'Iceweasel') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified..
|
||||
}
|
||||
if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[2], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Gecko based and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_gecko_version($version = null) {
|
||||
// Gecko based browsers.
|
||||
// Do not look for dates any more, we expect real Firefox version here.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
$version = 1;
|
||||
} else if ($version > 20000000) {
|
||||
// This is just a guess, it is not supposed to be 100% accurate!
|
||||
if (preg_match('/^201/', $version)) {
|
||||
$version = 3.6;
|
||||
} else if (preg_match('/^200[7-9]/', $version)) {
|
||||
$version = 3;
|
||||
} else if (preg_match('/^2006/', $version)) {
|
||||
$version = 2;
|
||||
} else {
|
||||
$version = 1.5;
|
||||
}
|
||||
}
|
||||
if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $useragent, $match)) {
|
||||
// Use real Firefox version if specified in user agent string.
|
||||
if (version_compare($match[2], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (preg_match("/Gecko\/([0-9\.]+)/i", $useragent, $match)) {
|
||||
// Gecko might contain date or Firefox revision, let's just guess the Firefox version from the date.
|
||||
$browserver = $match[1];
|
||||
if ($browserver > 20000000) {
|
||||
// This is just a guess, it is not supposed to be 100% accurate!
|
||||
if (preg_match('/^201/', $browserver)) {
|
||||
$browserver = 3.6;
|
||||
} else if (preg_match('/^200[7-9]/', $browserver)) {
|
||||
$browserver = 3;
|
||||
} else if (preg_match('/^2006/', $version)) {
|
||||
$browserver = 2;
|
||||
} else {
|
||||
$browserver = 1.5;
|
||||
}
|
||||
}
|
||||
if (version_compare($browserver, $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is IE and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_ie_version($version = null) {
|
||||
// Internet Explorer.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Opera') !== false) {
|
||||
// Reject Opera.
|
||||
return false;
|
||||
}
|
||||
// In case of IE we have to deal with BC of the version parameter.
|
||||
if (is_null($version)) {
|
||||
$version = 5.5; // Anything older is not considered a browser at all!
|
||||
}
|
||||
// IE uses simple versions, let's cast it to float to simplify the logic here.
|
||||
$version = round($version, 1);
|
||||
// See: http://www.useragentstring.com/pages/Internet%20Explorer/.
|
||||
if (preg_match("/MSIE ([0-9\.]+)/", $useragent, $match)) {
|
||||
$browser = $match[1];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// IE8 and later versions may pretend to be IE7 for intranet sites, use Trident version instead,
|
||||
// the Trident should always describe the capabilities of IE in any emulation mode.
|
||||
if ($browser === '7.0' and preg_match("/Trident\/([0-9\.]+)/", $useragent, $match)) {
|
||||
$browser = $match[1] + 4; // NOTE: Hopefully this will work also for future IE versions.
|
||||
}
|
||||
$browser = round($browser, 1);
|
||||
return ($browser >= $version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Opera and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_opera_version($version = null) {
|
||||
// Opera.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Opera') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
// Recent Opera useragents have Version/ with the actual version, e.g.:
|
||||
// Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.289 Version/12.01
|
||||
// That's Opera 12.01, not 9.8.
|
||||
if (preg_match("/Version\/([0-9\.]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (preg_match("/Opera\/([0-9\.]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Webkit based and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_webkit_version($version = null) {
|
||||
// WebKit based browser - everything derived from it (Safari, Chrome, iOS, Android and other mobiles).
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'AppleWebKit') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
if (preg_match("/AppleWebKit\/([0-9.]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Safari based and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_safari_version($version = null) {
|
||||
// Desktop version of Apple Safari browser - no mobile or touch devices.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'AppleWebKit') === false) {
|
||||
return false;
|
||||
}
|
||||
// Look for AppleWebKit, excluding strings with OmniWeb, Shiira and SymbianOS and any other mobile devices.
|
||||
if (strpos($useragent, 'OmniWeb')) {
|
||||
// Reject OmniWeb.
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Shiira')) {
|
||||
// Reject Shiira.
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'SymbianOS')) {
|
||||
// Reject SymbianOS.
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Android')) {
|
||||
// Reject Androids too.
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'iPhone') or strpos($useragent, 'iPad') or strpos($useragent, 'iPod')) {
|
||||
// No Apple mobile devices here - editor does not work, course ajax is not touch compatible, etc.
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Chrome')) { // Reject chrome browsers - it needs to be tested explicitly.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
if (preg_match("/AppleWebKit\/([0-9.]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Chrome based and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_chrome_version($version = null) {
|
||||
// Chrome.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Chrome') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
if (preg_match("/Chrome\/(.*)[ ]+/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Webkit based and on Android and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_webkit_android_version($version = null) {
|
||||
// WebKit browser on Android.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'Linux; U; Android') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
if (preg_match("/AppleWebKit\/([0-9]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user agent is Safari on iOS and that the version is equal to or greater than that specified.
|
||||
*
|
||||
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_safari_ios_version($version = null) {
|
||||
// Safari on iPhone, iPad and iPod touch.
|
||||
$useragent = self::get_user_agent_string();
|
||||
if ($useragent === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos($useragent, 'AppleWebKit') === false or strpos($useragent, 'Safari') === false) {
|
||||
return false;
|
||||
}
|
||||
if (!strpos($useragent, 'iPhone') and !strpos($useragent, 'iPad') and !strpos($useragent, 'iPod')) {
|
||||
return false;
|
||||
}
|
||||
if (empty($version)) {
|
||||
return true; // No version specified.
|
||||
}
|
||||
if (preg_match("/AppleWebKit\/([0-9]+)/i", $useragent, $match)) {
|
||||
if (version_compare($match[1], $version) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user agent matches a given brand.
|
||||
*
|
||||
* Known brand: 'Windows','Linux','Macintosh','SGI','SunOS','HP-UX'
|
||||
*
|
||||
* @param string $brand
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_browser_operating_system($brand) {
|
||||
$useragent = self::get_user_agent_string();
|
||||
return ($useragent !== false && preg_match("/$brand/i", $useragent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of CSS classes to represent the user agent.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_browser_version_classes() {
|
||||
$classes = array();
|
||||
if (self::check_ie_version('0')) {
|
||||
$classes[] = 'ie';
|
||||
for ($i = 12; $i >= 6; $i--) {
|
||||
if (self::check_ie_version($i)) {
|
||||
$classes[] = 'ie'.$i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (self::check_firefox_version() || self::check_gecko_version() || self::check_camino_version()) {
|
||||
$classes[] = 'gecko';
|
||||
if (preg_match('/rv\:([1-2])\.([0-9])/', self::get_user_agent_string(), $matches)) {
|
||||
$classes[] = "gecko{$matches[1]}{$matches[2]}";
|
||||
}
|
||||
} else if (self::check_webkit_version()) {
|
||||
$classes[] = 'safari';
|
||||
if (self::check_safari_ios_version()) {
|
||||
$classes[] = 'ios';
|
||||
} else if (self::check_webkit_android_version()) {
|
||||
$classes[] = 'android';
|
||||
}
|
||||
} else if (self::check_opera_version()) {
|
||||
$classes[] = 'opera';
|
||||
}
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user agent supports the display of SVG images.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function supports_svg() {
|
||||
// IE 5 - 8 don't support SVG at all.
|
||||
$instance = self::instance();
|
||||
if ($instance->supportssvg === null) {
|
||||
if ($instance->useragent === false) {
|
||||
// Can't be sure, just say no.
|
||||
$instance->supportssvg = false;
|
||||
} else if (self::check_ie_version() and !self::check_ie_version('9')) {
|
||||
// IE < 9 doesn't support SVG. Say no.
|
||||
$instance->supportssvg = false;
|
||||
} else if (preg_match('#Android +[0-2]\.#', $instance->useragent)) {
|
||||
// Android < 3 doesn't support SVG. Say no.
|
||||
$instance->supportssvg = false;
|
||||
} else if (self::check_opera_version()) {
|
||||
// Opera 12 still does not support SVG well enough. Say no.
|
||||
$instance->supportssvg = false;
|
||||
} else {
|
||||
// Presumed fine.
|
||||
$instance->supportssvg = true;
|
||||
}
|
||||
}
|
||||
return $instance->supportssvg;
|
||||
}
|
||||
}
|
||||
@@ -2750,7 +2750,7 @@
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="backupid" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="backupid the log record belongs to"/>
|
||||
<FIELD NAME="loglevel" TYPE="int" LENGTH="4" NOTNULL="true" SEQUENCE="false" COMMENT="level of the log (debug...error)"/>
|
||||
<FIELD NAME="message" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="text logged"/>
|
||||
<FIELD NAME="message" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="text logged"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="timestamp this log entry was created"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
|
||||
@@ -2327,5 +2327,41 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2013081200.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2013082300.01) {
|
||||
// Define the table 'backup_logs' and the field 'message' which we will be changing from a char to a text field.
|
||||
$table = new xmldb_table('backup_logs');
|
||||
$field = new xmldb_field('message', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'loglevel');
|
||||
|
||||
// Perform the change.
|
||||
$dbman->change_field_type($table, $field);
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2013082300.01);
|
||||
}
|
||||
|
||||
// Convert SCORM course format courses to singleactivity.
|
||||
if ($oldversion < 2013082700.00) {
|
||||
// First set relevant singleactivity settings.
|
||||
$formatoptions = new stdClass();
|
||||
$formatoptions->format = 'singleactivity';
|
||||
$formatoptions->sectionid = 0;
|
||||
$formatoptions->name = 'activitytype';
|
||||
$formatoptions->value = 'scorm';
|
||||
|
||||
$courses = $DB->get_recordset('course', array('format' => 'scorm'), 'id');
|
||||
foreach ($courses as $course) {
|
||||
$formatoptions->courseid = $course->id;
|
||||
$DB->insert_record('course_format_options', $formatoptions);
|
||||
}
|
||||
$courses->close();
|
||||
|
||||
// Now update course format for these courses.
|
||||
$sql = "UPDATE {course}
|
||||
SET format = 'singleactivity', modinfo = '', sectioncache = ''
|
||||
WHERE format = 'scorm'";
|
||||
$DB->execute($sql);
|
||||
upgrade_main_savepoint(true, 2013082700.00);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<TABLES>
|
||||
<TABLE NAME="test_table1" COMMENT="Just a test table">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="incorrect_next_field"/> <!-- missing TYPE -->
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" DEFAULT="Moodle" PREVIOUS="course" NEXT="secondname"/>
|
||||
<FIELD NAME="secondname" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="intro"/>
|
||||
<FIELD NAME="intro" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="secondname" NEXT="avatar"/>
|
||||
<FIELD NAME="avatar" TYPE="binary" LENGTH="medium" NOTNULL="false" SEQUENCE="false" PREVIOUS="intro" NEXT="grade"/>
|
||||
<FIELD NAME="grade" TYPE="number" LENGTH="20" DECIMALS="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="avatar"/>
|
||||
<FIELD NAME="id" LENGTH="10" NOTNULL="true" SEQUENCE="true"/> <!-- missing TYPE -->
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" DEFAULT="Moodle"/>
|
||||
<FIELD NAME="secondname" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="intro" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="avatar" TYPE="binary" LENGTH="medium" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="grade" TYPE="number" LENGTH="20" DECIMALS="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
<TABLES>
|
||||
<TABLE NAME="test_table1" COMMENT="Just a test table">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="course"/>
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" DEFAULT="Moodle" PREVIOUS="course" NEXT="secondname"/>
|
||||
<FIELD NAME="secondname" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="intro"/>
|
||||
<FIELD NAME="intro" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="secondname" NEXT="avatar"/>
|
||||
<FIELD NAME="avatar" TYPE="binary" LENGTH="medium" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" PREVIOUS="intro" NEXT="grade"/>
|
||||
<FIELD NAME="grade" TYPE="number" LENGTH="20" DECIMALS="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="avatar" NEXT="path"/>
|
||||
<FIELD NAME="path" TYPE="char" LENGTH="255" NOTNULL="true" PREVIOUS="grade"/>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" DEFAULT="Moodle"/>
|
||||
<FIELD NAME="secondname" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="intro" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="avatar" TYPE="binary" LENGTH="medium" NOTNULL="false" UNSIGNED="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="grade" TYPE="number" LENGTH="20" DECIMALS="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="path" TYPE="char" LENGTH="255" NOTNULL="true"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="course" UNIQUE="false" FIELDS="course" NEXT="path"/>
|
||||
<INDEX NAME="path" UNIQUE="false" FIELDS="path" HINTS="varchar_pattern_ops,unknownxyz" PREVIOUS="course"/>
|
||||
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
|
||||
<INDEX NAME="path" UNIQUE="false" FIELDS="path" HINTS="varchar_pattern_ops,unknownxyz"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
|
||||
@@ -4419,3 +4419,117 @@ function get_plugin_list_with_file($plugintype, $file, $include = false) {
|
||||
DEBUG_DEVELOPER);
|
||||
return core_component::get_plugin_list_with_file($plugintype, $file, $include);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if is the browser operating system matches the specified brand.
|
||||
*
|
||||
* Known brand: 'Windows','Linux','Macintosh','SGI','SunOS','HP-UX'
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @param string $brand The operating system identifier being tested
|
||||
* @return bool true if the given brand below to the detected operating system
|
||||
*/
|
||||
function check_browser_operating_system($brand) {
|
||||
debugging('check_browser_operating_system has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::check_browser_operating_system($brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if is a browser matches the specified
|
||||
* brand and is equal or better version.
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @param string $brand The browser identifier being tested
|
||||
* @param int $version The version of the browser, if not specified any version (except 5.5 for IE for BC reasons)
|
||||
* @return bool true if the given version is below that of the detected browser
|
||||
*/
|
||||
function check_browser_version($brand, $version = null) {
|
||||
debugging('check_browser_version has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::check_browser_version($brand, $version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a device/browser combination is mobile, tablet, legacy, default or the result of
|
||||
* an optional admin specified regular expression. If enabledevicedetection is set to no or not set
|
||||
* it returns default
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @return string device type
|
||||
*/
|
||||
function get_device_type() {
|
||||
debugging('get_device_type has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::get_device_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the device types supporting by Moodle
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @param boolean $incusertypes includes types specified using the devicedetectregex admin setting
|
||||
* @return array $types
|
||||
*/
|
||||
function get_device_type_list($incusertypes = true) {
|
||||
debugging('get_device_type_list has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::get_device_type_list($incusertypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the theme selected for a particular device or false if none selected.
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @param string $devicetype
|
||||
* @return string|false The name of the theme to use for the device or the false if not set
|
||||
*/
|
||||
function get_selected_theme_for_device_type($devicetype = null) {
|
||||
debugging('get_selected_theme_for_device_type has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::get_device_type_theme($devicetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the device type theme var in $CFG because there is not a convention to allow backwards compatibility.
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @param string $devicetype
|
||||
* @return string The config variable to use to determine the theme
|
||||
*/
|
||||
function get_device_cfg_var_name($devicetype = null) {
|
||||
debugging('get_device_cfg_var_name has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::get_device_type_cfg_var_name($devicetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user to switch the device they are seeing the theme for.
|
||||
* This allows mobile users to switch back to the default theme, or theme for any other device.
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @param string $newdevice The device the user is currently using.
|
||||
* @return string The device the user has switched to
|
||||
*/
|
||||
function set_user_device_type($newdevice) {
|
||||
debugging('set_user_device_type has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::set_user_device_type($newdevice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device the user is currently using, or if the user has chosen to switch devices
|
||||
* for the current device type the type they have switched to.
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @return string The device the user is currently using or wishes to use
|
||||
*/
|
||||
function get_user_device_type() {
|
||||
debugging('get_user_device_type has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::get_user_device_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one or several CSS class names that match the user's browser. These can be put
|
||||
* in the body tag of the page to apply browser-specific rules without relying on CSS hacks
|
||||
*
|
||||
* @deprecated since 2.6
|
||||
* @return array An array of browser version classes
|
||||
*/
|
||||
function get_browser_version_classes() {
|
||||
debugging('get_browser_version_classes has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER);
|
||||
return core_useragent::get_browser_version_classes();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor installation steps.
|
||||
*
|
||||
* @package editor_atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Enable this text editor by default.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function xmldb_editor_atto_install() {
|
||||
global $CFG;
|
||||
// Get the current list of editors.
|
||||
$currentconfig = $CFG->texteditors;
|
||||
if (is_null($currentconfig)) {
|
||||
$currentconfig = '';
|
||||
}
|
||||
$editors = explode(',', $currentconfig);
|
||||
// Insert atto in the second position.
|
||||
array_splice($editors, 1, 0, array('atto'));
|
||||
// Remove duplicates.
|
||||
$editors = array_unique($editors);
|
||||
// Set the new config.
|
||||
unset_config('texteditors');
|
||||
set_config('texteditors', implode(',', $editors));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -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,12 +15,13 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'format_scorm', language 'en', branch 'MOODLE_20_STABLE'
|
||||
* Yui Editor
|
||||
*
|
||||
* @package format_scorm
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package editor_atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['sectionname'] = 'SCORM';
|
||||
$string['pluginname'] = 'SCORM format';
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$subplugins = array('atto' => 'lib/editor/atto/plugins');
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'editor_atto', language 'en'.
|
||||
*
|
||||
* @package editor_atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'Atto HTML editor';
|
||||
@@ -0,0 +1,128 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* YUI text editor integration.
|
||||
*
|
||||
* @package editor_atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* This is the texteditor implementation.
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class atto_texteditor extends texteditor {
|
||||
|
||||
/**
|
||||
* Is the current browser supported by this editor?
|
||||
*
|
||||
* Of course!
|
||||
* @return bool
|
||||
*/
|
||||
public function supported_by_browser() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of supported text formats.
|
||||
* @return array
|
||||
*/
|
||||
public function get_supported_formats() {
|
||||
// FORMAT_MOODLE is not supported here, sorry.
|
||||
return array(FORMAT_HTML => FORMAT_HTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text format preferred by this editor.
|
||||
* @return int
|
||||
*/
|
||||
public function get_preferred_format() {
|
||||
return FORMAT_HTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this editor support picking from repositories?
|
||||
* @return bool
|
||||
*/
|
||||
public function supports_repositories() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this editor for give element.
|
||||
*
|
||||
* @param string $elementid
|
||||
* @param array $options
|
||||
* @param null $fpoptions
|
||||
*/
|
||||
public function use_editor($elementid, array $options=null, $fpoptions=null) {
|
||||
global $PAGE, $CFG;
|
||||
$PAGE->requires->yui_module('moodle-editor_atto-editor',
|
||||
'M.editor_atto.init',
|
||||
array($this->get_init_params($elementid, $options, $fpoptions)), true);
|
||||
require_once($CFG->libdir . '/pluginlib.php');
|
||||
|
||||
$pluginman = plugin_manager::instance();
|
||||
$plugins = $pluginman->get_subplugins_of_plugin('editor_atto');
|
||||
|
||||
$sortedplugins = array();
|
||||
|
||||
foreach ($plugins as $id => $plugin) {
|
||||
$sortorder = component_callback($plugin->type . '_' . $plugin->name, 'sort_order', array($elementid));
|
||||
$sortedplugins[$sortorder] = $plugin;
|
||||
}
|
||||
|
||||
ksort($sortedplugins);
|
||||
foreach ($sortedplugins as $plugin) {
|
||||
component_callback($plugin->type . '_' . $plugin->name, 'init_editor', array($elementid));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a params array to init the editor.
|
||||
*
|
||||
* @param string $elementid
|
||||
* @param array $options
|
||||
* @param array $fpoptions
|
||||
*/
|
||||
protected function get_init_params($elementid, array $options=null, array $fpoptions=null) {
|
||||
global $PAGE;
|
||||
|
||||
$directionality = get_string('thisdirection', 'langconfig');
|
||||
$strtime = get_string('strftimetime');
|
||||
$strdate = get_string('strftimedaydate');
|
||||
$lang = current_language();
|
||||
$contentcss = $PAGE->theme->editor_css_url()->out(false);
|
||||
|
||||
$params = array(
|
||||
'elementid' => $elementid,
|
||||
'content_css' => $contentcss,
|
||||
'language' => $lang,
|
||||
'directionality' => $directionality,
|
||||
'filepickeroptions' => array()
|
||||
);
|
||||
if ($fpoptions) {
|
||||
$params['filepickeroptions'] = $fpoptions;
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'atto_bold', language 'en'.
|
||||
*
|
||||
* @package atto_bold
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'Bold';
|
||||
$string['bold'] = 'Bold';
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_bold
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Initialise this plugin
|
||||
* @param string $elementid
|
||||
*/
|
||||
function atto_bold_init_editor($elementid) {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$icon = $OUTPUT->pix_icon('bold', get_string('bold', 'atto_bold'), 'atto_bold', array('class'=>'icon'));
|
||||
|
||||
$PAGE->requires->yui_module('moodle-atto_bold-button',
|
||||
'M.atto_bold.init',
|
||||
array(array('elementid'=>$elementid, 'icon'=>$icon)),
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order this plugin should be displayed in the toolbar
|
||||
* @return int
|
||||
*/
|
||||
function atto_bold_sort_order() {
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 446 B |
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="bold.svg" preserveAspectRatio="xMinYMid meet">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="15.839192"
|
||||
inkscape:cx="-8.2482624"
|
||||
inkscape:cy="15.312045"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1122"
|
||||
inkscape:window-height="685"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="57"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1036.3622)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:64px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Comic Sans MS;-inkscape-font-specification:Arial Bold"
|
||||
x="7.2604713"
|
||||
y="1049.6475"
|
||||
id="text2984"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2986"
|
||||
x="7.2604713"
|
||||
y="1049.6475"
|
||||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#999999;fill-opacity:1;font-family:Arial;-inkscape-font-specification:Arial Bold">b</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -15,16 +15,15 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Version details
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package format
|
||||
* @subpackage scorm
|
||||
* @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
|
||||
* @package atto_bold
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2013050100; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2013050100; // Requires this Moodle version
|
||||
$plugin->component = 'format_scorm'; // Full name of the plugin (used for diagnostics)
|
||||
$plugin->version = 2013080900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2013050100; // Requires this Moodle version.
|
||||
$plugin->component = 'atto_bold'; // Full name of the plugin (used for diagnostics).
|
||||
@@ -0,0 +1,40 @@
|
||||
YUI.add('moodle-atto_bold-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor bold plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_bold = M.atto_bold || {
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
document.execCommand('bold', false, null);
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'bold', params.icon, click);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node"]});
|
||||
@@ -0,0 +1 @@
|
||||
YUI.add("moodle-atto_bold-button",function(e,t){M.atto_bold=M.atto_bold||{init:function(e){var t=function(e,t){e.preventDefault(),M.editor_atto.is_active(t)||M.editor_atto.focus(t),document.execCommand("bold",!1,null)};M.editor_atto.add_toolbar_button(e.elementid,"bold",e.icon,t)}}},"@VERSION@",{requires:["node"]});
|
||||
@@ -0,0 +1,40 @@
|
||||
YUI.add('moodle-atto_bold-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor bold plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_bold = M.atto_bold || {
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
document.execCommand('bold', false, null);
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'bold', params.icon, click);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node"]});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "moodle-atto_bold-button",
|
||||
"builds": {
|
||||
"moodle-atto_bold-button": {
|
||||
"jsfiles": [
|
||||
"button.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor bold plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_bold = M.atto_bold || {
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
document.execCommand('bold', false, null);
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'bold', params.icon, click);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"moodle-atto_bold-button": {
|
||||
"requires": ["node"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'atto_clear', language 'en'.
|
||||
*
|
||||
* @package atto_clear
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'Clear formatting';
|
||||
$string['clear'] = 'Clear formatting';
|
||||
@@ -0,0 +1,52 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_clear
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Initialise this plugin
|
||||
* @param string $elementid
|
||||
*/
|
||||
function atto_clear_init_editor($elementid) {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$icon = $OUTPUT->pix_icon('clear',
|
||||
get_string('clear', 'atto_clear'),
|
||||
'atto_clear',
|
||||
array('class'=>'icon'));
|
||||
|
||||
$PAGE->requires->yui_module('moodle-atto_clear-button',
|
||||
'M.atto_clear.init',
|
||||
array(array('elementid'=>$elementid, 'icon'=>$icon)),
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order this plugin should be displayed in the toolbar
|
||||
* @return int
|
||||
*/
|
||||
function atto_clear_sort_order() {
|
||||
return 10;
|
||||
}
|
||||
|
After Width: | Height: | Size: 468 B |
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="clear.svg" preserveAspectRatio="xMinYMid meet">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="15.839192"
|
||||
inkscape:cx="-3.8870379"
|
||||
inkscape:cy="15.312045"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1122"
|
||||
inkscape:window-height="685"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="57"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:clear />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1036.3622)">
|
||||
<g
|
||||
id="g3756"
|
||||
transform="translate(0,-0.44194174)">
|
||||
<rect
|
||||
ry="0"
|
||||
transform="translate(0,1036.3622)"
|
||||
y="2.3629408"
|
||||
x="7.0079331"
|
||||
height="5.3664355"
|
||||
width="2.0203052"
|
||||
id="rect2982"
|
||||
style="fill:#999999;fill-opacity:1;stroke:#999999;stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
ry="0.4152233"
|
||||
y="1043.2078"
|
||||
x="3.9774756"
|
||||
height="2.7870839"
|
||||
width="8.0812302"
|
||||
id="rect2984"
|
||||
style="fill:#999999;fill-opacity:1;stroke:#999999;stroke-width:0.82672101;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<rect
|
||||
ry="0.053281363"
|
||||
y="1045.6699"
|
||||
x="4.4825521"
|
||||
height="3.1562684"
|
||||
width="7.0079417"
|
||||
id="rect3754"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#999999;stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_clear
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2013080900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2013050100; // Requires this Moodle version.
|
||||
$plugin->component = 'atto_clear'; // Full name of the plugin (used for diagnostics).
|
||||
@@ -0,0 +1,40 @@
|
||||
YUI.add('moodle-atto_clear-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor clear plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_clear = M.atto_clear || {
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
document.execCommand('removeFormat', false);
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'clear', params.icon, click);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node"]});
|
||||
@@ -0,0 +1 @@
|
||||
YUI.add("moodle-atto_clear-button",function(e,t){M.atto_clear=M.atto_clear||{init:function(e){var t=function(e,t){e.preventDefault(),M.editor_atto.is_active(t)||M.editor_atto.focus(t),document.execCommand("removeFormat",!1)};M.editor_atto.add_toolbar_button(e.elementid,"clear",e.icon,t)}}},"@VERSION@",{requires:["node"]});
|
||||
@@ -0,0 +1,40 @@
|
||||
YUI.add('moodle-atto_clear-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor clear plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_clear = M.atto_clear || {
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
document.execCommand('removeFormat', false);
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'clear', params.icon, click);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node"]});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "moodle-atto_clear-button",
|
||||
"builds": {
|
||||
"moodle-atto_clear-button": {
|
||||
"jsfiles": [
|
||||
"button.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor clear plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_clear = M.atto_clear || {
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
document.execCommand('removeFormat', false);
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'clear', params.icon, click);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"moodle-atto_clear-button": {
|
||||
"requires": ["node"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'atto_html', language 'en'.
|
||||
*
|
||||
* @package atto_html
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'HTML';
|
||||
$string['html'] = 'HTML';
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_html
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Initialise this plugin
|
||||
* @param string $elementid
|
||||
*/
|
||||
function atto_html_init_editor($elementid) {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$icon = $OUTPUT->pix_icon('html', get_string('html', 'atto_html'), 'atto_html', array('class'=>'icon'));
|
||||
|
||||
$PAGE->requires->yui_module('moodle-atto_html-button',
|
||||
'M.atto_html.init',
|
||||
array(array('elementid'=>$elementid, 'icon'=>$icon)),
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order this plugin should be displayed in the toolbar
|
||||
* @return int
|
||||
*/
|
||||
function atto_html_sort_order() {
|
||||
return 15;
|
||||
}
|
||||
|
After Width: | Height: | Size: 466 B |
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="html.svg" preserveAspectRatio="xMinYMid meet">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313709"
|
||||
inkscape:cx="-8.155614"
|
||||
inkscape:cy="13.234355"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1122"
|
||||
inkscape:window-height="685"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="57"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>media/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillMedia" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1036.3622)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:52.96332169000000079px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#999999;fill-opacity:1;stroke:none;font-family:Comic Sans MS;-inkscape-font-specification:Comic Sans MS"
|
||||
x="10.191385"
|
||||
y="836.76996"
|
||||
id="text2988"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(0.79843788,1.2524456)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2990"
|
||||
x="10.191385"
|
||||
y="836.76996"
|
||||
style="font-size:9.93062304999999945px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold;fill:#999999;fill-opacity:1"></></tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_html
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2013080900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2013050100; // Requires this Moodle version.
|
||||
$plugin->component = 'atto_html'; // Full name of the plugin (used for diagnostics).
|
||||
@@ -0,0 +1,59 @@
|
||||
YUI.add('moodle-atto_html-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor html plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_html = M.atto_html || {
|
||||
/**
|
||||
* Are we in html editing mode or not?
|
||||
*/
|
||||
ishtml : false,
|
||||
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
var textarea = Y.one('#' + elementid);
|
||||
var atto = Y.one('#' + elementid + 'editable');
|
||||
|
||||
if (M.atto_html.ishtml) {
|
||||
M.editor_atto.enable_all_widgets(elementid);
|
||||
atto.setHTML('');
|
||||
atto.append(textarea.get('value'));
|
||||
textarea.hide();
|
||||
atto.show();
|
||||
} else {
|
||||
M.editor_atto.disable_all_widgets(elementid);
|
||||
M.editor_atto.enable_widget(elementid, 'html');
|
||||
textarea.set('value', atto.getHTML());
|
||||
atto.hide();
|
||||
textarea.show();
|
||||
}
|
||||
|
||||
M.atto_html.ishtml = !M.atto_html.ishtml;
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'html', params.icon, click);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node"]});
|
||||
@@ -0,0 +1 @@
|
||||
YUI.add("moodle-atto_html-button",function(e,t){M.atto_html=M.atto_html||{ishtml:!1,init:function(t){var n=function(t,n){t.preventDefault();var r=e.one("#"+n),i=e.one("#"+n+"editable");M.atto_html.ishtml?(M.editor_atto.enable_all_widgets(n),i.setHTML(""),i.append(r.get("value")),r.hide(),i.show()):(M.editor_atto.disable_all_widgets(n),M.editor_atto.enable_widget(n,"html"),r.set("value",i.getHTML()),i.hide(),r.show()),M.atto_html.ishtml=!M.atto_html.ishtml};M.editor_atto.add_toolbar_button(t.elementid,"html",t.icon,n)}}},"@VERSION@",{requires:["node"]});
|
||||
@@ -0,0 +1,59 @@
|
||||
YUI.add('moodle-atto_html-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor html plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_html = M.atto_html || {
|
||||
/**
|
||||
* Are we in html editing mode or not?
|
||||
*/
|
||||
ishtml : false,
|
||||
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
var textarea = Y.one('#' + elementid);
|
||||
var atto = Y.one('#' + elementid + 'editable');
|
||||
|
||||
if (M.atto_html.ishtml) {
|
||||
M.editor_atto.enable_all_widgets(elementid);
|
||||
atto.setHTML('');
|
||||
atto.append(textarea.get('value'));
|
||||
textarea.hide();
|
||||
atto.show();
|
||||
} else {
|
||||
M.editor_atto.disable_all_widgets(elementid);
|
||||
M.editor_atto.enable_widget(elementid, 'html');
|
||||
textarea.set('value', atto.getHTML());
|
||||
atto.hide();
|
||||
textarea.show();
|
||||
}
|
||||
|
||||
M.atto_html.ishtml = !M.atto_html.ishtml;
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'html', params.icon, click);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node"]});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "moodle-atto_html-button",
|
||||
"builds": {
|
||||
"moodle-atto_html-button": {
|
||||
"jsfiles": [
|
||||
"button.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor html plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_html = M.atto_html || {
|
||||
/**
|
||||
* Are we in html editing mode or not?
|
||||
*/
|
||||
ishtml : false,
|
||||
|
||||
init : function(params) {
|
||||
var click = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
var textarea = Y.one('#' + elementid);
|
||||
var atto = Y.one('#' + elementid + 'editable');
|
||||
|
||||
if (M.atto_html.ishtml) {
|
||||
M.editor_atto.enable_all_widgets(elementid);
|
||||
atto.setHTML('');
|
||||
atto.append(textarea.get('value'));
|
||||
textarea.hide();
|
||||
atto.show();
|
||||
} else {
|
||||
M.editor_atto.disable_all_widgets(elementid);
|
||||
M.editor_atto.enable_widget(elementid, 'html');
|
||||
textarea.set('value', atto.getHTML());
|
||||
atto.hide();
|
||||
textarea.show();
|
||||
}
|
||||
|
||||
M.atto_html.ishtml = !M.atto_html.ishtml;
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'html', params.icon, click);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"moodle-atto_html-button": {
|
||||
"requires": [
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'atto_image', language 'en'.
|
||||
*
|
||||
* @package atto_image
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'Image';
|
||||
$string['image'] = 'Image';
|
||||
$string['createimage'] = 'Insert image';
|
||||
$string['enterurl'] = 'Enter URL';
|
||||
$string['enteralt'] = 'Enter alternative text';
|
||||
$string['browserepositories'] = 'Browse repositories...';
|
||||
$string['accessibilityhint'] = '<p>Web content accessibility guidelines (WCAG):<br/><ul><li><a href="http://www.w3.org/TR/WCAG20/#text-equiv" target="_blank">Text Alternatives</a></li></ul></p>';
|
||||
$string['width'] = 'Width';
|
||||
$string['height'] = 'Height';
|
||||
$string['preview'] = 'Preview';
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_image
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Initialise this plugin
|
||||
* @param string $elementid
|
||||
*/
|
||||
function atto_image_init_editor($elementid) {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$icon = $OUTPUT->pix_icon('image',
|
||||
get_string('image', 'atto_image'),
|
||||
'atto_image',
|
||||
array('class'=>'icon'));
|
||||
|
||||
$PAGE->requires->strings_for_js(array('createimage',
|
||||
'enterurl',
|
||||
'enteralt',
|
||||
'preview',
|
||||
'browserepositories',
|
||||
'accessibilityhint',
|
||||
'width',
|
||||
'height'), 'atto_image');
|
||||
$PAGE->requires->yui_module('moodle-atto_image-button',
|
||||
'M.atto_image.init',
|
||||
array(array('elementid'=>$elementid, 'icon'=>$icon)),
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order this plugin should be displayed in the toolbar
|
||||
* @return int
|
||||
*/
|
||||
function atto_image_sort_order() {
|
||||
return 13;
|
||||
}
|
||||
|
After Width: | Height: | Size: 506 B |
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="image.svg" preserveAspectRatio="xMinYMid meet">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="11.577509"
|
||||
inkscape:cy="9.3016902"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1122"
|
||||
inkscape:window-height="685"
|
||||
inkscape:window-x="162"
|
||||
inkscape:window-y="57"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1036.3622)">
|
||||
<rect
|
||||
style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#999999;stroke-opacity:1"
|
||||
id="rect2986"
|
||||
width="14.142136"
|
||||
height="13.131983"
|
||||
x="1.0101526"
|
||||
y="1.4159228"
|
||||
transform="translate(0,1036.3622)"
|
||||
ry="0.053281363" />
|
||||
<path
|
||||
style="fill:#999999;fill-opacity:1;stroke:none"
|
||||
d="m 13.794977,1041.1242 c 0,0.9241 -0.749059,1.6732 -1.673146,1.6732 -0.9241,0 -1.673146,-0.7491 -1.673146,-1.6732 0,-0.924 0.749059,-1.6731 1.673146,-1.6731 0.9241,0 1.673146,0.7491 1.673146,1.6731 z"
|
||||
id="path3761"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="translate(0,1036.3622)"
|
||||
style="fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:#999999;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 1.5711386,10.553572 c 1.7890625,-0.125 3.8205354,-3.734909 6.286004,-3.75 2.4654684,-0.015091 3.8591064,3.4375 6.4645754,3.75 0.01465,0.0018 0.02808,0.0059 0.03771,0.01557 0.0096,0.0096 0.01557,0.02295 0.01557,0.03771 l 0,3.018437 c 0,0.02952 -0.02376,0.05328 -0.05328,0.05328 l -12.7505794,0 c -0.029518,0 -0.053281,-0.02376 -0.053281,-0.05328 l 0,-3.018437 c 0,-0.01476 0.00594,-0.02808 0.015572,-0.03771 0.00963,-0.0096 0.022987,-0.01454 0.037709,-0.01557 z"
|
||||
id="rect3753"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="szssssssssss" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_image
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2013080900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2013050100; // Requires this Moodle version.
|
||||
$plugin->component = 'atto_image'; // Full name of the plugin (used for diagnostics).
|
||||
@@ -0,0 +1,184 @@
|
||||
YUI.add('moodle-atto_image-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor image plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_image = M.atto_image || {
|
||||
dialogue : null,
|
||||
selection : null,
|
||||
init : function(params) {
|
||||
var display_chooser = function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
M.atto_image.selection = M.editor_atto.get_selection();
|
||||
if (M.atto_image.selection !== false) {
|
||||
var dialogue;
|
||||
if (!M.atto_image.dialogue) {
|
||||
dialogue = new M.core.dialogue({
|
||||
visible: false,
|
||||
modal: true,
|
||||
close: true,
|
||||
draggable: true
|
||||
});
|
||||
} else {
|
||||
dialogue = M.atto_image.dialogue;
|
||||
}
|
||||
|
||||
dialogue.set('bodyContent', M.atto_image.get_form_content(elementid));
|
||||
dialogue.set('headerContent', M.util.get_string('createimage', 'atto_image'));
|
||||
dialogue.render();
|
||||
dialogue.centerDialogue();
|
||||
M.atto_image.dialogue = dialogue;
|
||||
|
||||
var selectedText = M.editor_atto.get_selection_text();
|
||||
var i = 0;
|
||||
|
||||
var images = [];
|
||||
for (i = 0; i < selectedText.childNodes.length; i++) {
|
||||
var child = selectedText.childNodes[0];
|
||||
if (images.length === 0) {
|
||||
if (child.nodeName.toLowerCase() === 'img') {
|
||||
images[0] = child;
|
||||
} else {
|
||||
if (child.getElementsByTagName) {
|
||||
images = child.getElementsByTagName('img');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (images.length > 0) {
|
||||
var image = Y.one(images[0]);
|
||||
var width = image.getAttribute('width');
|
||||
var height = image.getAttribute('height');
|
||||
if (width > 0) {
|
||||
Y.one('#atto_image_widthentry').set('value', width);
|
||||
}
|
||||
if (height > 0) {
|
||||
Y.one('#atto_image_heightentry').set('value', height);
|
||||
}
|
||||
Y.one('#atto_image_preview').set('src', image.get('src'));
|
||||
Y.one('#atto_image_preview').setStyle('display', 'inline');
|
||||
Y.one('#atto_image_altentry').set('value', image.get('alt'));
|
||||
Y.one('#atto_image_urlentry').set('value', image.get('src'));
|
||||
}
|
||||
dialogue.show();
|
||||
}
|
||||
};
|
||||
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'image', params.icon, display_chooser, this);
|
||||
},
|
||||
open_filepicker : function(e) {
|
||||
var elementid = this.getAttribute('data-editor');
|
||||
e.preventDefault();
|
||||
|
||||
M.editor_atto.show_filepicker(elementid, 'image', M.atto_image.filepicker_callback);
|
||||
},
|
||||
filepicker_callback : function(params) {
|
||||
if (params.url !== '') {
|
||||
var input = Y.one('#atto_image_urlentry');
|
||||
input.set('value', params.url);
|
||||
input = Y.one('#atto_image_altentry');
|
||||
input.set('value', params.file);
|
||||
|
||||
// Auto set the width and height.
|
||||
var image = new Image();
|
||||
image.onload = function() {
|
||||
Y.one('#atto_image_widthentry').set('value', this.width);
|
||||
Y.one('#atto_image_heightentry').set('value', this.height);
|
||||
Y.one('#atto_image_preview').set('src', this.src);
|
||||
Y.one('#atto_image_preview').setStyle('display', 'inline');
|
||||
};
|
||||
image.src = params.url;
|
||||
}
|
||||
},
|
||||
set_image : function(e) {
|
||||
e.preventDefault();
|
||||
M.atto_image.dialogue.hide();
|
||||
|
||||
var input = e.currentTarget.get('parentNode').one('#atto_image_urlentry');
|
||||
|
||||
var url = input.get('value');
|
||||
input = e.currentTarget.get('parentNode').one('#atto_image_altentry');
|
||||
var alt = input.get('value');
|
||||
input = e.currentTarget.get('parentNode').one('#atto_image_widthentry');
|
||||
var width = input.get('value');
|
||||
input = e.currentTarget.get('parentNode').one('#atto_image_heightentry');
|
||||
var height = input.get('value');
|
||||
if (url !== '' && alt !== '') {
|
||||
M.editor_atto.set_selection(M.atto_image.selection);
|
||||
var imagehtml = '<img src="' + Y.Escape.html(url) + '" alt="' + Y.Escape.html(alt) + '"';
|
||||
|
||||
if (width) {
|
||||
imagehtml += ' width="' + Y.Escape.html(width) + '"';
|
||||
}
|
||||
if (height) {
|
||||
imagehtml += ' height="' + Y.Escape.html(height) + '"';
|
||||
}
|
||||
imagehtml += '"/>';
|
||||
|
||||
if (document.selection && document.selection.createRange().pasteHTML) {
|
||||
document.selection.createRange().pasteHTML(imagehtml);
|
||||
} else {
|
||||
document.execCommand('insertHTML', false, imagehtml);
|
||||
}
|
||||
}
|
||||
},
|
||||
get_form_content : function(elementid) {
|
||||
var content = Y.Node.create('<form class="atto_form">' +
|
||||
'<label for="atto_image_urlentry">' + M.util.get_string('enterurl', 'atto_image') +
|
||||
'</label>' +
|
||||
'<input type="url" value="" id="atto_image_urlentry" size="32"/>' +
|
||||
'<label for="atto_image_altentry">' + M.util.get_string('enteralt', 'atto_image') +
|
||||
'</label>' +
|
||||
'<input type="text" value="" id="atto_image_altentry" size="32" required="true"/>' +
|
||||
'<label for="atto_image_widthentry">' + M.util.get_string('width', 'atto_image') +
|
||||
'</label>' +
|
||||
'<input type="text" value="" id="atto_image_widthentry" size="10"/>' +
|
||||
'<br/>' +
|
||||
'<label for="atto_image_heightentry">' + M.util.get_string('height', 'atto_image') +
|
||||
'</label>' +
|
||||
'<input type="text" value="" id="atto_image_heightentry" size="10"/>' +
|
||||
'<label for="atto_image_preview">' + M.util.get_string('preview', 'atto_image') +
|
||||
'</label>' +
|
||||
'<img src="#" width="200" id="atto_image_preview" alt="" style="display: none;"/>' +
|
||||
'<hr/>' +
|
||||
'<button id="openimagebrowser" data-editor="' + Y.Escape.html(elementid) + '">' +
|
||||
M.util.get_string('browserepositories', 'atto_image') +
|
||||
'</button>' +
|
||||
'<hr/>' +
|
||||
'<button id="atto_image_urlentrysubmit">' +
|
||||
M.util.get_string('createimage', 'atto_image') +
|
||||
'</button>' +
|
||||
'</form>' +
|
||||
'<hr/>' + M.util.get_string('accessibilityhint', 'atto_image'));
|
||||
|
||||
content.one('#atto_image_urlentrysubmit').on('click', M.atto_image.set_image);
|
||||
content.one('#openimagebrowser').on('click', M.atto_image.open_filepicker);
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node", "escape"]});
|
||||