diff --git a/admin/tool/xmldb/actions/edit_table/edit_table.class.php b/admin/tool/xmldb/actions/edit_table/edit_table.class.php index 32f6fea00e0..00ed43a3da1 100644 --- a/admin/tool/xmldb/actions/edit_table/edit_table.class.php +++ b/admin/tool/xmldb/actions/edit_table/edit_table.class.php @@ -74,6 +74,7 @@ class edit_table extends XMLDBAction { * errormsg and output as necessary */ function invoke() { + global $OUTPUT, $PAGE; parent::invoke(); $result = true; @@ -197,6 +198,11 @@ class edit_table extends XMLDBAction { $o .= ''; $row = 0; foreach ($fields as $field) { + // Drag element up/down. + $move = (count($fields) > 1) ? html_writer::span($OUTPUT->render_from_template('core/drag_handle', + ['movetitle' => get_string('movecontent', 'moodle', $field->getName())]), '', + ['data-action' => 'move_updown_field', 'data-dir' => str_replace($CFG->dirroot, '', $dirpath), + 'data-table' => $table->getName(), 'data-field' => $field->getName()]) : ''; // The field name (link to edit - if the field has no uses) if (!$structure->getFieldUses($table->getName(), $field->getName())) { $f = '' . $field->getName() . ''; @@ -212,20 +218,6 @@ class edit_table extends XMLDBAction { $b .= '[' . $this->str['edit'] . ']'; } $b .= ''; // Print table row - $o .= ''; + $o .= ''; $row = ($row + 1) % 2; } $o .= '
'; - // The up button - if ($field->getPrevious()) { - $b .= '[' . $this->str['up'] . ']'; - } else { - $b .= '[' . $this->str['up'] . ']'; - } - $b .= ''; - // The down button - if ($field->getNext()) { - $b .= '[' . $this->str['down'] . ']'; - } else { - $b .= '[' . $this->str['down'] . ']'; - } - $b .= ''; // The delete button (if we have more than one and it isn't used if (count($fields) > 1 && !$structure->getFieldUses($table->getName(), $field->getName())) { @@ -243,10 +235,12 @@ class edit_table extends XMLDBAction { // The readable info $r = '' . $field->readableInfo() . '
' . $f . $b . $r . '
' . $move . + $f . $b . $r . '
'; + $PAGE->requires->js_call_amd('tool_xmldb/move', 'init', ['listfields', 'move_updown_field']); } // Add the keys list $keys = $table->getKeys(); @@ -255,6 +249,11 @@ class edit_table extends XMLDBAction { $o .= ''; $row = 0; foreach ($keys as $key) { + // Drag element up/down. + $move = (count($keys) > 1) ? html_writer::span($OUTPUT->render_from_template('core/drag_handle', + ['movetitle' => get_string('movecontent', 'moodle', $key->getName())]), '', + ['data-action' => 'move_updown_key', 'data-dir' => str_replace($CFG->dirroot, '', $dirpath), + 'data-table' => $table->getName(), 'data-key' => $key->getName()]) : ''; // The key name (link to edit - if the key has no uses) if (!$structure->getKeyUses($table->getName(), $key->getName())) { $k = '' . $key->getName() . ''; @@ -270,20 +269,6 @@ class edit_table extends XMLDBAction { $b .= '[' . $this->str['edit'] . ']'; } $b .= ''; // Print table row - $o .= ''; + $o .= ''; $row = ($row + 1) % 2; } $o .= '
'; - // The up button - if ($key->getPrevious()) { - $b .= '[' . $this->str['up'] . ']'; - } else { - $b .= '[' . $this->str['up'] . ']'; - } - $b .= ''; - // The down button - if ($key->getNext()) { - $b .= '[' . $this->str['down'] . ']'; - } else { - $b .= '[' . $this->str['down'] . ']'; - } - $b .= ''; // The delete button (if the key hasn't uses) if (!$structure->getKeyUses($table->getName(), $key->getName())) { $b .= '[' . $this->str['delete'] . ']'; @@ -296,10 +281,12 @@ class edit_table extends XMLDBAction { // The readable info $r = '' . $key->readableInfo() . '
' . $k . $b . $r .'
' . + $move . $k . $b . $r .'
'; + $PAGE->requires->js_call_amd('tool_xmldb/move', 'init', ['listkeys', 'move_updown_key']); } // Add the indexes list $indexes = $table->getIndexes(); @@ -308,6 +295,11 @@ class edit_table extends XMLDBAction { $o .= ''; $row = 0; foreach ($indexes as $index) { + // Drag element up/down. + $move = (count($indexes) > 1) ? html_writer::span($OUTPUT->render_from_template('core/drag_handle', + ['movetitle' => get_string('movecontent', 'moodle', $index->getName())]), '', + ['data-action' => 'move_updown_index', 'data-dir' => str_replace($CFG->dirroot, '', $dirpath), + 'data-table' => $table->getName(), 'data-index' => $index->getName()]) : ''; // The index name (link to edit) $i = '' . $index->getName() . ''; // Calculate buttons @@ -315,20 +307,6 @@ class edit_table extends XMLDBAction { // The edit button $b .= '[' . $this->str['edit'] . ']'; $b .= ''; // Print table row - $o .= ''; + $o .= ''; $row = ($row + 1) % 2; } $o .= '
'; - // The up button - if ($index->getPrevious()) { - $b .= '[' . $this->str['up'] . ']'; - } else { - $b .= '[' . $this->str['up'] . ']'; - } - $b .= ''; - // The down button - if ($index->getNext()) { - $b .= '[' . $this->str['down'] . ']'; - } else { - $b .= '[' . $this->str['down'] . ']'; - } - $b .= ''; // The delete button $b .= '[' . $this->str['delete'] . ']'; $b .= ''; @@ -337,10 +315,12 @@ class edit_table extends XMLDBAction { // The readable info $r = '' . $index->readableInfo() . '
' . $i . $b . $r .'
' . + $move . $i . $b . $r .'
'; + $PAGE->requires->js_call_amd('tool_xmldb/move', 'init', ['listindexes', 'move_updown_index']); } $this->output = $o; diff --git a/admin/tool/xmldb/actions/edit_xml_file/edit_xml_file.class.php b/admin/tool/xmldb/actions/edit_xml_file/edit_xml_file.class.php index f053c08c040..45df3aa1571 100644 --- a/admin/tool/xmldb/actions/edit_xml_file/edit_xml_file.class.php +++ b/admin/tool/xmldb/actions/edit_xml_file/edit_xml_file.class.php @@ -70,6 +70,7 @@ class edit_xml_file extends XMLDBAction { * errormsg and output as necessary */ function invoke() { + global $OUTPUT, $PAGE; parent::invoke(); $result = true; @@ -178,6 +179,11 @@ class edit_xml_file extends XMLDBAction { $o .= ''; $row = 0; foreach ($tables as $table) { + // Drag element for sortorder. + $move = html_writer::span($OUTPUT->render_from_template('core/drag_handle', + ['movetitle' => get_string('movecontent', 'moodle', $table->getName())]), '', + ['data-action' => 'move_updown_table', 'data-dir' => str_replace($CFG->dirroot, '', $dirpath), + 'data-table' => $table->getName()]); // The table name (link to edit table) $t = '' . $table->getName() . ''; // Calculate buttons @@ -185,20 +191,6 @@ class edit_xml_file extends XMLDBAction { // The edit button $b .= '[' . $this->str['edit'] . ']'; $b .= ''; // Print table row - $o .= ''; + $o .= ''; $row = ($row + 1) % 2; } $o .= '
'; - // The up button - if ($table->getPrevious()) { - $b .= '[' . $this->str['up'] . ']'; - } else { - $b .= '[' . $this->str['up'] . ']'; - } - $b .= ''; - // The down button - if ($table->getNext()) { - $b .= '[' . $this->str['down'] . ']'; - } else { - $b .= '[' . $this->str['down'] . ']'; - } - $b .= ''; // The delete button (if we have more than one and it isn't used) if (count($tables) > 1 && !$structure->getTableUses($table->getName())) { @@ -216,13 +208,16 @@ class edit_xml_file extends XMLDBAction { } $b .= '
' . $t . $b . '
' . + (count($tables) > 1 ? $move : '') . + $t . $b . '
'; } - // Add the back to main - $this->output = $o; + // Add the back to main. + $this->output = $o; + $PAGE->requires->js_call_amd('tool_xmldb/move', 'init', ['listtables', 'move_updown_table']); } } diff --git a/admin/tool/xmldb/amd/build/move.min.js b/admin/tool/xmldb/amd/build/move.min.js new file mode 100644 index 00000000000..341413f7de6 --- /dev/null +++ b/admin/tool/xmldb/amd/build/move.min.js @@ -0,0 +1 @@ +define(["jquery","core/sortable_list","core/ajax","core/notification"],function(a,b,c,d){return{init:function(e,f){var g=new b("#"+e+" tbody");g.getElementName=function(b){return a.Deferred().resolve(b.attr("data-name"))};var h;a("#"+e+" tbody tr").on(b.EVENTS.DRAGSTART,function(b,c){h=c.sourceList.children().index(c.element),setTimeout(function(){a(".sortable-list-is-dragged").width(c.element.width())},501)}).on(b.EVENTS.DROP,function(a,b){var e=b.targetList.children().index(b.element),g=b.element.find("[data-action="+f+"]");if(b.positionChanged&&g.length){var i={methodname:"tool_xmldb_invoke_move_action",args:{action:f,dir:g.attr("data-dir"),table:g.attr("data-table"),field:g.attr("data-field"),key:g.attr("data-key"),index:g.attr("data-index"),position:e-h}};c.call([i])[0].fail(d.exception)}})}}}); \ No newline at end of file diff --git a/admin/tool/xmldb/amd/src/move.js b/admin/tool/xmldb/amd/src/move.js new file mode 100644 index 00000000000..34aca098a72 --- /dev/null +++ b/admin/tool/xmldb/amd/src/move.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 . + +define(['jquery', 'core/sortable_list', 'core/ajax', 'core/notification'], function($, SortableList, Ajax, Notification) { + return { + init: function(tableid, moveaction) { + // Initialise sortable for the given list. + var sort = new SortableList('#' + tableid + ' tbody'); + sort.getElementName = function(element) { + return $.Deferred().resolve(element.attr('data-name')); + }; + var origIndex; + $('#' + tableid + ' tbody tr').on(SortableList.EVENTS.DRAGSTART, function(_, info) { + // Remember position of the element in the beginning of dragging. + origIndex = info.sourceList.children().index(info.element); + // Resize the "proxy" element to be the same width as the main element. + setTimeout(function() { + $('.sortable-list-is-dragged').width(info.element.width()); + }, 501); + }).on(SortableList.EVENTS.DROP, function(_, info) { + // When a list element was moved send AJAX request to the server. + var newIndex = info.targetList.children().index(info.element); + var t = info.element.find('[data-action=' + moveaction + ']'); + if (info.positionChanged && t.length) { + var request = { + methodname: 'tool_xmldb_invoke_move_action', + args: { + action: moveaction, + dir: t.attr('data-dir'), + table: t.attr('data-table'), + field: t.attr('data-field'), + key: t.attr('data-key'), + index: t.attr('data-index'), + position: newIndex - origIndex + } + }; + Ajax.call([request])[0].fail(Notification.exception); + } + }); + } + }; +}); diff --git a/admin/tool/xmldb/classes/external.php b/admin/tool/xmldb/classes/external.php new file mode 100644 index 00000000000..0aa839190a7 --- /dev/null +++ b/admin/tool/xmldb/classes/external.php @@ -0,0 +1,124 @@ +. + +/** + * Web services + * + * @package tool_xmldb + * @copyright 2018 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir . '/externallib.php'); + +/** + * tool_xmldb external function + * + * @package tool_xmldb + * @copyright 2018 Moodle + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_xmldb_external extends external_api { + + /** + * Parameters for the 'tool_xmldb_invoke_move_action' WS + * @return external_function_parameters + */ + public static function invoke_move_action_parameters() { + return new external_function_parameters([ + 'action' => new external_value(PARAM_ALPHAEXT, 'Action'), + 'dir' => new external_value(PARAM_PATH, 'Plugin that is being edited'), + 'table' => new external_value(PARAM_NOTAGS, 'Table name'), + 'field' => new external_value(PARAM_NOTAGS, 'Field name', VALUE_DEFAULT, ''), + 'key' => new external_value(PARAM_NOTAGS, 'Key name', VALUE_DEFAULT, ''), + 'index' => new external_value(PARAM_NOTAGS, 'Index name', VALUE_DEFAULT, ''), + 'position' => new external_value(PARAM_INT, 'How many positions to move by (negative - up, positive - down)'), + ]); + } + + /** + * WS 'tool_xmldb_invoke_move_action' that invokes a move action + * + * @param string $action + * @param string $dir + * @param string $table + * @param string $field + * @param string $key + * @param string $index + * @param int $position + * @throws coding_exception + */ + public static function invoke_move_action($action, $dir, $table, $field, $key, $index, $position) { + global $CFG, $XMLDB, $SESSION; + require_once($CFG->libdir.'/ddllib.php'); + require_once("$CFG->dirroot/$CFG->admin/tool/xmldb/actions/XMLDBAction.class.php"); + require_once("$CFG->dirroot/$CFG->admin/tool/xmldb/actions/XMLDBCheckAction.class.php"); + $params = self::validate_parameters(self::invoke_move_action_parameters(), [ + 'action' => $action, + 'dir' => $dir, + 'table' => $table, + 'field' => $field, + 'key' => $key, + 'index' => $index, + 'position' => $position + ]); + + if (!in_array($action, ['move_updown_table', 'move_updown_field', 'move_updown_key', 'move_updown_index'])) { + throw new coding_exception('Unsupported action'); + } + + $action = $params['action']; + $actionsroot = "$CFG->dirroot/$CFG->admin/tool/xmldb/actions"; + $actionclass = $action . '.class.php'; + $actionpath = "$actionsroot/$action/$actionclass"; + + if (file_exists($actionpath) && is_readable($actionpath)) { + require_once($actionpath); + } + if (!class_exists($action)) { + throw new coding_exception('Action class not found'); + } + + if (!isset($SESSION->xmldb)) { + $XMLDB = new stdClass; + } else { + $XMLDB = unserialize($SESSION->xmldb); + } + + $_POST['dir'] = $params['dir']; + $_POST['table'] = $params['table']; + $_POST['field'] = $params['field']; + $_POST['key'] = $params['key']; + $_POST['index'] = $params['index']; + $_POST['direction'] = ($params['position'] > 0) ? 'down' : 'up'; + for ($i = 0; $i < abs($params['position']); $i++) { + $a = new $action(); + $a->invoke(); + } + $SESSION->xmldb = serialize($XMLDB); + } + + /** + * Return structure for the 'tool_xmldb_invoke_move_action' WS + * @return null + */ + public static function invoke_move_action_returns() { + return null; + } + +} \ No newline at end of file diff --git a/admin/tool/xmldb/db/services.php b/admin/tool/xmldb/db/services.php new file mode 100644 index 00000000000..412923f0792 --- /dev/null +++ b/admin/tool/xmldb/db/services.php @@ -0,0 +1,35 @@ +. + +/** + * Tool xmldb external functions and service definitions. + * + * @package tool_xmldb + * @copyright 2018 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +$functions = [ + 'tool_xmldb_invoke_move_action' => [ + 'classname' => tool_xmldb_external::class, + 'methodname' => 'invoke_move_action', + 'description' => 'moves element up/down', + 'type' => 'write', + 'ajax' => true, + ] +]; diff --git a/admin/tool/xmldb/styles_boost.css b/admin/tool/xmldb/styles_boost.css new file mode 100644 index 00000000000..ae530cbc96d --- /dev/null +++ b/admin/tool/xmldb/styles_boost.css @@ -0,0 +1,3 @@ +.path-admin-tool-xmldb a[name="lastused"] { + padding-top: 50px; +} diff --git a/admin/tool/xmldb/version.php b/admin/tool/xmldb/version.php index 486ba9e8f9c..98c4b2ee50b 100644 --- a/admin/tool/xmldb/version.php +++ b/admin/tool/xmldb/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX) +$plugin->version = 2018051401; // The current plugin version (Date: YYYYMMDDXX) $plugin->requires = 2018050800; // Requires this Moodle version $plugin->component = 'tool_xmldb'; // Full name of the plugin (used for diagnostics)