diff --git a/admin/classes/table/editor_management_table.php b/admin/classes/table/editor_management_table.php new file mode 100644 index 00000000000..a8f566cceca --- /dev/null +++ b/admin/classes/table/editor_management_table.php @@ -0,0 +1,67 @@ +. + +namespace core_admin\table; + +use moodle_url; + +/** + * Tiny admin settings. + * + * @package core_admin + * @copyright 2023 Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class editor_management_table extends \core_admin\table\plugin_management_table { + protected function get_plugintype(): string { + return 'editor'; + } + + public function guess_base_url(): void { + $this->define_baseurl( + new moodle_url('/admin/settings.php', ['section' => 'manageeditors']) + ); + } + + protected function get_action_url(array $params = []): moodle_url { + return new moodle_url('/admin/editors.php', $params); + } + + protected function supports_ordering(): bool { + return true; + } + + protected function order_plugins(array $plugins): array { + global $CFG; + + // The Editor list is stored in an ordered string. + $activeeditors = explode(',', $CFG->texteditors); + + $sortedplugins = []; + foreach ($activeeditors as $editor) { + if (isset($plugins[$editor])) { + $sortedplugins[$editor] = $plugins[$editor]; + unset($plugins[$editor]); + } + } + + $otherplugins = parent::order_plugins($plugins); + return array_merge( + $sortedplugins, + $otherplugins + ); + } +} diff --git a/admin/classes/table/plugin_management_table.php b/admin/classes/table/plugin_management_table.php index 6a75bf318a5..712ef4e944d 100644 --- a/admin/classes/table/plugin_management_table.php +++ b/admin/classes/table/plugin_management_table.php @@ -65,6 +65,10 @@ abstract class plugin_management_table extends flexible_table implements dynamic return $plugin->is_enabled(); })); + $this->enabledplugincount = count(array_filter($this->plugins, function ($plugin) { + return $plugin->is_enabled(); + })); + $this->setup_column_configuration(); $this->set_filterset(new plugin_management_table_filterset()); $this->setup(); @@ -127,7 +131,7 @@ abstract class plugin_management_table extends flexible_table implements dynamic } else if (!$a->is_enabled() && $b->is_enabled()) { return 1; } - return strnatcasecmp($a->displayname, $b->displayname); + return strnatcasecmp($a->name, $b->name); }); return $plugins; @@ -166,6 +170,15 @@ abstract class plugin_management_table extends flexible_table implements dynamic return 'core_admin_set_plugin_state'; } + /** + * Get the web service method used to order plugins. + * + * @return null|string + */ + protected function get_sortorder_service(): ?string { + return null; + } + /** * Get the ID of the table. * @@ -189,6 +202,10 @@ abstract class plugin_management_table extends flexible_table implements dynamic $columns['enabled'] = get_string('pluginenabled', 'core_plugin'); } + if ($this->supports_ordering()) { + $columns['order'] = get_string('order', 'core'); + } + $columns['settings'] = get_string('settings', 'core'); $columns['uninstall'] = get_string('uninstallplugin', 'core_admin'); @@ -302,6 +319,77 @@ abstract class plugin_management_table extends flexible_table implements dynamic ); } + protected function col_order(stdClass $row): string { + global $OUTPUT; + + if (!$this->supports_ordering()) { + return ''; + } + + if (!$row->plugininfo->is_enabled()) { + return ''; + } + + if ($this->enabledplugincount <= 1) { + // There is only one row. + return ''; + } + + $hasup = true; + $hasdown = true; + + if (empty($this->currentrow)) { + // This is the top row. + $hasup = false; + } + + if ($this->currentrow === ($this->enabledplugincount - 1)) { + // This is the last row. + $hasdown = false; + } + + if ($this->get_sortorder_service()) { + $dataattributes = [ + 'data-method' => $this->get_sortorder_service(), + 'data-action' => 'move', + 'data-plugin' => $row->plugin, + ]; + } else { + $dataattributes = []; + } + + if ($hasup) { + $upicon = html_writer::link( + $this->get_action_url([ + 'sesskey' => sesskey(), + 'action' => 'up', + 'plugin' => $row->plugininfo->name, + ]), + $OUTPUT->pix_icon('t/up', get_string('moveup')), + array_merge($dataattributes, ['data-direction' => 'up']), + ); + } else { + $upicon = $OUTPUT->spacer(); + } + + if ($hasdown) { + $downicon = html_writer::link( + $this->get_action_url([ + 'sesskey' => sesskey(), + 'action' => 'down', + 'plugin' => $row->plugininfo->name, + ]), + $OUTPUT->pix_icon('t/down', get_string('movedown')), + array_merge($dataattributes, ['data-direction' => 'down']), + ); + } else { + $downicon = $OUTPUT->spacer(); + } + + // For now just add the up/down icons. + return html_writer::span($upicon . $downicon); + } + /** * Show the settings column content. * @@ -395,4 +483,13 @@ abstract class plugin_management_table extends flexible_table implements dynamic protected function supports_disabling(): bool { return $this->plugininfoclass::plugintype_supports_disabling(); } + + /** + * Whether this table should show ordering fields. + * + * @return bool + */ + protected function supports_ordering(): bool { + return false; + } } diff --git a/admin/editors.php b/admin/editors.php index aa4e91b4fa7..ee9e635695e 100644 --- a/admin/editors.php +++ b/admin/editors.php @@ -1,87 +1,95 @@ . /** - * Allows admin to configure editors. + * A page to manage editor plugins. + * + * @package core_admin + * @copyright 2023 Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once('../config.php'); -require_once($CFG->libdir.'/adminlib.php'); -require_once($CFG->libdir.'/tablelib.php'); +require_once($CFG->libdir . '/adminlib.php'); +require_once($CFG->libdir . '/tablelib.php'); -$action = required_param('action', PARAM_ALPHANUMEXT); -$editor = required_param('editor', PARAM_PLUGIN); -$confirm = optional_param('confirm', 0, PARAM_BOOL); +$action = required_param('action', PARAM_ALPHANUMEXT); +$plugin = required_param('plugin', PARAM_PLUGIN); -$PAGE->set_url('/admin/editors.php', array('action'=>$action, 'editor'=>$editor)); +$PAGE->set_url('/admin/editors.php', ['action' => $action, 'editor' => $plugin]); $PAGE->set_context(context_system::instance()); require_admin(); +require_sesskey(); -$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageeditors"; +$returnurl = new moodle_url('/admin/settings.php', ['section' => 'manageeditors']); -// get currently installed and enabled auth plugins -$available_editors = editors_get_available(); -if (!empty($editor) and empty($available_editors[$editor])) { - redirect ($returnurl); -} - -$active_editors = explode(',', $CFG->texteditors); -foreach ($active_editors as $key=>$active) { - if (empty($available_editors[$active])) { - unset($active_editors[$key]); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// process actions - -if (!confirm_sesskey()) { +// Get currently installed and enabled auth plugins. +$availableeditors = editors_get_available(); +if (!empty($plugin) && empty($availableeditors[$plugin])) { redirect($returnurl); } -$return = true; +$activeeditors = explode(',', $CFG->texteditors); +foreach ($activeeditors as $key => $active) { + if (empty($availableeditors[$active])) { + unset($activeeditors[$key]); + } +} + switch ($action) { case 'disable': // Remove from enabled list. $class = \core_plugin_manager::resolve_plugininfo_class('editor'); - $class::enable_plugin($editor, false); + $class::enable_plugin($plugin, false); break; case 'enable': // Add to enabled list. - if (!in_array($editor, $active_editors)) { + if (!in_array($plugin, $activeeditors)) { $class = \core_plugin_manager::resolve_plugininfo_class('editor'); - $class::enable_plugin($editor, true); + $class::enable_plugin($plugin, true); } break; case 'down': - $key = array_search($editor, $active_editors); - // check auth plugin is valid + $key = array_search($plugin, $activeeditors); if ($key !== false) { - // move down the list - if ($key < (count($active_editors) - 1)) { - $fsave = $active_editors[$key]; - $active_editors[$key] = $active_editors[$key + 1]; - $active_editors[$key + 1] = $fsave; - add_to_config_log('editor_position', $key, $key + 1, $editor); - set_config('texteditors', implode(',', $active_editors)); + // Move down the list. + if ($key < (count($activeeditors) - 1)) { + $fsave = $activeeditors[$key]; + $activeeditors[$key] = $activeeditors[$key + 1]; + $activeeditors[$key + 1] = $fsave; + add_to_config_log('editor_position', $key, $key + 1, $plugin); + set_config('texteditors', implode(',', $activeeditors)); core_plugin_manager::reset_caches(); } } break; case 'up': - $key = array_search($editor, $active_editors); - // check auth is valid + $key = array_search($plugin, $activeeditors); if ($key !== false) { - // move up the list + // Move up the list. if ($key >= 1) { - $fsave = $active_editors[$key]; - $active_editors[$key] = $active_editors[$key - 1]; - $active_editors[$key - 1] = $fsave; - add_to_config_log('editor_position', $key, $key - 1, $editor); - set_config('texteditors', implode(',', $active_editors)); + $fsave = $activeeditors[$key]; + $activeeditors[$key] = $activeeditors[$key - 1]; + $activeeditors[$key - 1] = $fsave; + add_to_config_log('editor_position', $key, $key - 1, $plugin); + set_config('texteditors', implode(',', $activeeditors)); core_plugin_manager::reset_caches(); } } @@ -91,6 +99,4 @@ switch ($action) { break; } -if ($return) { - redirect ($returnurl); -} +redirect($returnurl); diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php index 47331b47fcb..cc8b352aabd 100644 --- a/admin/settings/plugins.php +++ b/admin/settings/plugins.php @@ -154,7 +154,12 @@ if ($hassiteconfig) { /// Editor plugins $ADMIN->add('modules', new admin_category('editorsettings', new lang_string('editors', 'editor'))); $temp = new admin_settingpage('manageeditors', new lang_string('editorsettings', 'editor')); - $temp->add(new admin_setting_manageeditors()); + $temp->add(new \core_admin\admin\admin_setting_plugin_manager( + 'editor', + \core_admin\table\editor_management_table::class, + 'editorsui', + get_string('editorsettings', 'editor'), + )); $ADMIN->add('editorsettings', $temp); $plugins = core_plugin_manager::instance()->get_plugins_of_type('editor'); core_collator::asort_objects_by_property($plugins, 'displayname'); diff --git a/lib/adminlib.php b/lib/adminlib.php index a64723d9bb0..9a56b85ffe0 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -7239,184 +7239,6 @@ class admin_setting_manageauths extends admin_setting { } } - -/** - * Special class for authentication administration. - * - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class admin_setting_manageeditors extends admin_setting { - /** - * Calls parent::__construct with specific arguments - */ - public function __construct() { - $this->nosave = true; - parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', ''); - } - - /** - * Always returns true, does nothing - * - * @return true - */ - public function get_setting() { - return true; - } - - /** - * Always returns true, does nothing - * - * @return true - */ - public function get_defaultsetting() { - return true; - } - - /** - * Always returns '', does not write anything - * - * @return string Always returns '' - */ - public function write_setting($data) { - // do not write any setting - return ''; - } - - /** - * Checks if $query is one of the available editors - * - * @param string $query The string to search for - * @return bool Returns true if found, false if not - */ - public function is_related($query) { - if (parent::is_related($query)) { - return true; - } - - $editors_available = editors_get_available(); - foreach ($editors_available as $editor=>$editorstr) { - if (strpos($editor, $query) !== false) { - return true; - } - if (strpos(core_text::strtolower($editorstr), $query) !== false) { - return true; - } - } - return false; - } - - /** - * Builds the XHTML to display the control - * - * @param string $data Unused - * @param string $query - * @return string - */ - public function output_html($data, $query='') { - global $CFG, $OUTPUT; - - // display strings - $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable', - 'up', 'down', 'none')); - $struninstall = get_string('uninstallplugin', 'core_admin'); - - $txt->updown = "$txt->up/$txt->down"; - - $editors_available = editors_get_available(); - $active_editors = explode(',', $CFG->texteditors); - - $active_editors = array_reverse($active_editors); - foreach ($active_editors as $key=>$editor) { - if (empty($editors_available[$editor])) { - unset($active_editors[$key]); - } else { - $name = $editors_available[$editor]; - unset($editors_available[$editor]); - $editors_available[$editor] = $name; - } - } - if (empty($active_editors)) { - //$active_editors = array('textarea'); - } - $editors_available = array_reverse($editors_available, true); - $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true); - $return .= $OUTPUT->box_start('generalbox editorsui'); - - $table = new html_table(); - $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall); - $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign'); - $table->id = 'editormanagement'; - $table->attributes['class'] = 'admintable generaltable'; - $table->data = array(); - - // iterate through auth plugins and add to the display table - $updowncount = 1; - $editorcount = count($active_editors); - $url = "editors.php?sesskey=" . sesskey(); - foreach ($editors_available as $editor => $name) { - // hide/show link - $class = ''; - if (in_array($editor, $active_editors)) { - $hideshow = ""; - $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . ''; - $enabled = true; - $displayname = $name; - } - else { - $hideshow = ""; - $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . ''; - $enabled = false; - $displayname = $name; - $class = 'dimmed_text'; - } - - // up/down link (only if auth is enabled) - $updown = ''; - if ($enabled) { - if ($updowncount > 1) { - $updown .= ""; - $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . ' '; - } - else { - $updown .= $OUTPUT->spacer() . ' '; - } - if ($updowncount < $editorcount) { - $updown .= ""; - $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . ' '; - } - else { - $updown .= $OUTPUT->spacer() . ' '; - } - ++ $updowncount; - } - - // settings link - if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) { - $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor)); - $settings = "{$txt->settings}"; - } else { - $settings = ''; - } - - $uninstall = ''; - if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('editor_'.$editor, 'manage')) { - $uninstall = html_writer::link($uninstallurl, $struninstall); - } - - // Add a row to the table. - $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall)); - if ($class) { - $row->attributes['class'] = $class; - } - $table->data[] = $row; - } - $return .= html_writer::table($table); - $return .= get_string('configeditorplugins', 'editor').'
'.get_string('tablenosave', 'admin'); - $return .= $OUTPUT->box_end(); - return highlight($query, $return); - } -} - /** * Special class for antiviruses administration. * diff --git a/lib/editor/tiny/tests/behat/manage_subplugins.feature b/lib/editor/tiny/tests/behat/manage_subplugins.feature index 6919d15de22..c8d780ac127 100644 --- a/lib/editor/tiny/tests/behat/manage_subplugins.feature +++ b/lib/editor/tiny/tests/behat/manage_subplugins.feature @@ -7,7 +7,7 @@ Feature: An administrator can manage TinyMCE subplugins @javascript Scenario: An administrator can control the enabled state of TinyMCE subplugins using JavaScript Given I am logged in as "admin" - And I navigate to "Plugins > Text editors > TinyMCE > General settings" in site administration + And I navigate to "Plugins > Text editors > TinyMCE editor > General settings" in site administration When I click on "Disable the Tiny equation editor plugin" "link" Then I should see "The Tiny equation editor plugin has been disabled" And "Disable the Tiny equation editor plugin" "link" should not exist @@ -19,7 +19,7 @@ Feature: An administrator can manage TinyMCE subplugins Scenario: An administrator can control the enabled state of TinyMCE subplugins without JavaScript Given I am logged in as "admin" - And I navigate to "Plugins > Text editors > TinyMCE > General settings" in site administration + And I navigate to "Plugins > Text editors > TinyMCE editor > General settings" in site administration When I click on "Disable the Tiny equation editor plugin" "link" Then I should see "The Tiny equation editor plugin has been disabled" And "Disable the Tiny equation editor plugin" "link" should not exist