Commit 7f31e743 authored by Cecilia Vela Gurovic's avatar Cecilia Vela Gurovic Committed by Gerrit Code Review

Merge changes from topic 'WR 311418'

* changes:
  Bug 1829940: Make placeholder blocktype be active by default
  Bug 1829940: Create plugin base config form / system
  Bug 1829940: Move 'add placeholder' to float on right
  Bug 1829940: Restrict the chooser to one 'add' button
  Bug 1829940: Placeholder option update page with block of choice
  Bug 1829940: Placeholder block
parents f13ddf37 25cbcb46
......@@ -197,7 +197,7 @@ var installplugin = (function($) {
}(jQuery));
JAVASCRIPT;
$plugins['blocktype']['configure'] = true;
$smarty = smarty();
setpageicon($smarty, 'icon-plug');
......
<?php
/**
*
* @package mahara
* @subpackage admin
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('ADMIN', 1);
define('MENUITEM', 'configextensions/pluginadmin');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
define('TITLE', get_string('pluginadmin', 'admin'));
$plugintype = param_alpha('plugintype');
define('SECTION_PLUGINTYPE', $plugintype);
define('SECTION_PAGE', 'pluginconfig');
require_once(get_config('docroot') . $plugintype . '/lib.php');
$classname = 'Plugin' . ucfirst($plugintype);
if (!call_static_method($classname, 'has_base_config')) {
throw new InvalidArgumentException("$classname doesn't have config options available");
}
if (method_exists($classname, 'get_base_config_options_css')) {
$formcss = call_static_method($classname, 'get_base_config_options_css');
}
else {
$formcss = array();
}
if (method_exists($classname, 'get_base_config_options_js')) {
$formjs = call_static_method($classname, 'get_base_config_options_js');
}
else {
$formjs = '';
}
$form = call_static_method($classname, 'get_base_config_options');
if (!array_key_exists('class', $form)) {
$form['class'] = 'card card-body';
}
$form['plugintype'] = $plugintype;
$form['name'] = 'pluginconfig';
$form['pluginconfigform'] = true;
$form['jsform'] = true;
$form['successcallback'] = 'plugintypeconfig_submit';
$form['validatecallback'] = 'plugintypeconfig_validate';
$form['elements']['plugintype'] = array(
'type' => 'hidden',
'value' => $plugintype
);
$form['elements']['save'] = array(
'type' => 'submit',
'class' => 'btn-primary',
'value' => get_string('save'),
);
$form = pieform($form);
$smarty = smarty(array('js/jquery/jquery-ui/js/jquery-ui.min.js','js/jquery/jquery-ui/js/jquery-ui.touch-punch.min.js'), $formcss);
$smarty->assign('form', $form);
$smarty->assign('plugintype', $plugintype);
$heading = get_string('pluginadmin', 'admin') . ': ' . $plugintype;
$smarty->assign('PAGEHEADING', $heading);
$smarty->assign('INLINEJAVASCRIPT', $formjs);
$smarty->display('admin/extensions/pluginconfig.tpl');
function plugintypeconfig_submit(Pieform $form, $values) {
global $plugintype, $classname;
$success = true;
if (is_callable($classname . '::save_base_config_options')) {
$success = false;
try {
call_static_method($classname, 'save_base_config_options', $form, $values);
$success = true;
}
catch (Exception $e) {
$success = false;
}
}
if ($success) {
$form->json_reply(PIEFORM_OK, get_string('settingssaved'));
}
else {
$form->json_reply(PIEFORM_ERR, array('message' => get_string('settingssavefailed')));
}
}
function plugintypeconfig_validate(PieForm $form, $values) {
global $plugintype, $classname;
if (is_callable($classname . '::validate_base_config_options')) {
call_static_method($classname, 'validate_base_config_options', $form, $values);
}
}
......@@ -15,7 +15,7 @@ define('JSON', 1);
define('NOSESSKEY', 1);
require(dirname(dirname(__FILE__)) . '/init.php');
require($CFG->docroot.'/blocktype/lib.php');
require_once(get_config('docroot') . 'blocktype/lib.php');
// Close the session to prevent session locking.
session_write_close();
......
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('ADMIN', 1);
define('JSON', 1);
require(dirname(dirname(__FILE__)) . '/init.php');
$id = param_alphanum('id');
$direction = param_variable('direction', '');
$message = null;
if (!empty($direction)) {
parse_str($direction, $direction_array);
if (is_array($direction_array['row']) && !empty($direction_array['row'])) {
foreach ($direction_array['row'] as $k => $v) {
execute_sql("UPDATE {blocktype_installed_category} SET sortorder = ? WHERE blocktype = ?", array(($k + 1) * 1000, $v));
}
}
}
// return updated info
$type = array();
$blocks = get_records_sql_array("SELECT b.name, b.artefactplugin, bc.sortorder,
(SELECT COUNT(bi.*) FROM {block_instance} bi WHERE bi.blocktype = b.name) AS blockcount
FROM {blocktype_installed} b
JOIN {blocktype_installed_category} bc ON bc.blocktype = b.name
WHERE b.active = 1
AND b.name != ?
ORDER BY bc.sortorder", array('placeholder'));
foreach ($blocks as $block) {
$namespaced = blocktype_single_to_namespaced($block->name, $block->artefactplugin);
safe_require('blocktype', $block->name);
$classname = generate_class_name('blocktype', $namespaced);
$types[] = array('name' => $block->name,
'title' => call_static_method($classname, 'get_title'),
'cssicon' => call_static_method($classname, 'get_css_icon', $block->name),
'cssicontype' => call_static_method($classname, 'get_css_icon_type', $block->name),
'count' => $block->blockcount,
);
}
$smarty = smarty_core();
$smarty->assign('types', $types);
$typeslist = $smarty->fetch('blocktype:placeholder:contenttypeslist.tpl');
$smarty->assign('typeslist', $typeslist);
$typeshtml = $smarty->fetch('blocktype:placeholder:contenttypes.tpl');
$message = get_string('blocktypeupdatedsuccess', 'admin');
json_reply(false, array(
'message' => $message,
'html' => $typeshtml,
));
......@@ -86,6 +86,127 @@ abstract class PluginBlocktype extends Plugin implements IPluginBlocktype {
return false;
}
/**
* To define a pluginwide configuration
*/
public static function has_base_config() {
return true;
}
/**
* To define a pluginwide configuration
*/
public static function get_base_config_options() {
$type = array();
$blocks = get_records_sql_array("SELECT b.name, b.artefactplugin, bc.sortorder,
(SELECT COUNT(bi.*) FROM {block_instance} bi WHERE bi.blocktype = b.name) AS blockcount
FROM {blocktype_installed} b
JOIN {blocktype_installed_category} bc ON bc.blocktype = b.name
WHERE b.active = 1
AND b.name != ?
ORDER BY bc.sortorder", array('placeholder'));
foreach ($blocks as $block) {
$namespaced = blocktype_single_to_namespaced($block->name, $block->artefactplugin);
safe_require('blocktype', $namespaced);
$classname = generate_class_name('blocktype', $namespaced);
$types[] = array('name' => $block->name,
'title' => call_static_method($classname, 'get_title'),
'cssicon' => call_static_method($classname, 'get_css_icon', $block->name),
'cssicontype' => call_static_method($classname, 'get_css_icon_type', $block->name),
'count' => $block->blockcount,
);
}
$form = array(
'elements' => array(
'types' => array(
'type' => 'fieldset',
'legend' => get_string('contenttypes', 'blocktype.placeholder'),
'elements' => array(
'contenttypes' => array(
'type' => 'html',
'value' => '',
),
),
),
)
);
$smarty = smarty_core();
$smarty->assign('types', $types);
$typeslist = $smarty->fetch('blocktype:placeholder:contenttypeslist.tpl');
$smarty->assign('typeslist', $typeslist);
$typeshtml = $smarty->fetch('blocktype:placeholder:contenttypes.tpl');
$form['elements']['types']['elements']['contenttypes']['value'] = $typeshtml;
return $form;
}
/**
* To define a pluginwide configuration
*/
public static function get_base_config_options_js() {
global $USER;
$sesskey = $USER->get('sesskey');
$js = <<<EOF
$(function() {
$('#placeholderlist button').each(function() {
$(this).off('click');
$(this).on('click', function(ev) {
ev.stopPropagation();
ev.preventDefault();
});
});
var updaterows = function(option) {
var sortorder = $('#placeholderlist').sortable('serialize');
$.post(config['wwwroot'] + "blocktype/config.json.php", { sesskey: '$sesskey', id: option, direction: sortorder })
.done(function(data) {
// update the page with the new list
if (data.returnCode == '0') {
$('#placeholderlist').replaceWith(data.message.html);
if (data.message.message) {
var okmessage = $('<div id="changestatusline" class="alert alert-dismissible alert-success" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="' + get_string('Close') + '"><span aria-hidden="true">&times;</span></button><p>' + data.message.message + '</p></div>');
$('#messages').empty().append(okmessage);
}
wiresortables();
}
});
};
var wiresortables = function() {
$('#placeholderlist > div').each(function() {
$(this).prepend('<div class="handle">&nbsp;</div>');
$('.handle').css('position', 'absolute');
$('.handle').css('z-index', '3');
$('.handle').css('width', $(this).find('button').css('width'));
$('.handle').css('height', $(this).find('button').css('height'));
});
$('#placeholderlist').sortable({
items: '> div',
appendTo: '#placeholderlist',
cursor: 'move',
opacity: 0.8,
helper: 'clone',
handle: '.handle',
stop: function(e, ui) {
var id = $(ui.item).find('button').data('option');
updaterows(id);
},
})
.disableSelection()
.on("mouseenter mouseleave", function() {
$(this).css('cursor', 'move');
});
// hide the 'save' button as this form works with drag / drop saving
$('#pluginconfig_save_container').hide();
};
// init
wiresortables();
});
EOF;
return $js;
}
public static function get_theme_path($pluginname) {
if (($artefactname = blocktype_artefactplugin($pluginname))) {
// Path for block plugins that sit under an artefact
......@@ -337,14 +458,19 @@ abstract class PluginBlocktype extends Plugin implements IPluginBlocktype {
return $description;
}
public static function get_blocktypes_for_category($category, View $view) {
$sql = 'SELECT bti.name, bti.artefactplugin
public static function get_blocktypes_for_category($category, View $view, $blocktype = null) {
$sql = 'SELECT bti.name, bti.artefactplugin, btic.sortorder
FROM {blocktype_installed} bti
JOIN {blocktype_installed_category} btic ON btic.blocktype = bti.name
JOIN {blocktype_installed_viewtype} btiv ON btiv.blocktype = bti.name
WHERE btic.category = ? AND bti.active = 1 AND btiv.viewtype = ?
ORDER BY btic.sortorder, bti.name';
if (!$bts = get_records_sql_array($sql, array($category, $view->get('type')))) {
WHERE btic.category = ? AND bti.active = 1 AND btiv.viewtype = ?';
$where = array($category, $view->get('type'));
if ($blocktype) {
$sql .= ' AND bti.name = ?';
$where[] = $blocktype;
}
$sql .= ' ORDER BY btic.sortorder, bti.name';
if (!$bts = get_records_sql_array($sql, $where)) {
return false;
}
......@@ -384,6 +510,7 @@ abstract class PluginBlocktype extends Plugin implements IPluginBlocktype {
'thumbnail_path' => get_config('wwwroot') . 'thumb.php?type=blocktype&bt=' . $bt->name . ((!empty($bt->artefactplugin)) ? '&ap=' . $bt->artefactplugin : ''),
'cssicon' => call_static_method($classname, 'get_css_icon', $bt->name),
'cssicontype' => call_static_method($classname, 'get_css_icon_type', $bt->name),
'sortorder' => $bt->sortorder,
);
}
}
......
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require_once(get_config('libroot') . 'view.php');
safe_require('blocktype', 'placeholder');
$offset = param_integer('offset', 0);
$limit = param_integer('limit', 8);
$viewid = param_integer('viewid');
$blockid = param_integer('blockid');
if (!can_view_view($viewid)) {
json_reply('local', get_string('accessdenied', 'error'));
}
$view = new View($viewid);
$setlimit = false;
$orderby = param_alphanum('orderby', null);
list($count, $types) = PluginBlocktypePlaceholder::get_content_types($view, $offset, $limit);
$pagination = build_showmore_pagination(array(
'count' => $count,
'limit' => $limit,
'offset' => $offset,
'orderby' => 'popular',
'databutton' => 'showmorebtn',
'jscall' => 'wire_blockoptions',
'jsonscript' => 'blocktype/placeholder/blockoptions.json.php',
'extra' => array('viewid' => $viewid,
'blockid' => $blockid),
));
$smarty = smarty_core();
$smarty->assign('blockid', $blockid);
$smarty->assign('types', $types);
$typeslist = $smarty->fetch('blocktype:placeholder:contenttypeslist.tpl');
$typeslist .= $pagination['html'];
json_reply(false, array(
'message' => null,
'data' => array(
'tablerows' => $typeslist,
'pagination_js' => $pagination['javascript'],
'count' => $count,
'results' => $count . ' ' . ($count == 1 ? get_string('result') : get_string('results')),
'offset' => $offset,
'setlimit' => $setlimit,
'jscall' => 'wire_blockoptions',
)
));
<?php
/**
*
* @package mahara
* @subpackage blocktype-inbox
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
defined('INTERNAL') || die();
$string['title'] = 'Placeholder';
$string['description'] = 'Placeholder block that allows you to select what type of block you want';
$string['placeholdertext'] = 'Please configure the block to choose what type of block this should be';
$string['defaulttitledescription'] = 'A default title will be generated if you leave the title field blank';
$string['contenttypes'] = 'Content types';
$string['placeholderblocktypenotenabled'] = 'The block type "placeholder" needs to be installed and be active. If it is already installed please set it to be active via the database "blocktype_installed" table.';
<?php
/**
*
* @package mahara
* @subpackage blocktype-inbox
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
defined('INTERNAL') || die();
class PluginBlocktypePlaceholder extends MaharaCoreBlocktype {
public static function get_title() {
return get_string('title', 'blocktype.placeholder');
}
public static function get_description() {
return get_string('description', 'blocktype.placeholder');
}
public static function get_categories() {
return array('shortcut' => 500);
}
public static function is_active() {
return get_field('blocktype_installed', 'active', 'name', 'placeholder');
}
/**
* We want this blocktype to be the default blocktype so we
* will prevent it being disabled.
*/
public static function can_be_disabled() {
return false;
}
public static function render_instance(BlockInstance $instance, $editing=false, $versioning=false) {
global $USER, $THEME;
$configdata = $instance->get('configdata');
$smarty = smarty_core();
$smarty->assign('placeholdertext', get_string('placeholdertext', 'blocktype.placeholder'));
return $smarty->fetch('blocktype:placeholder:body.tpl');
}
public static function has_instance_config() {
return true;
}
public static function instance_config_form(BlockInstance $instance) {
global $USER;
$view = $instance->get_view();
$elements = array();
$elements['types'] = array(
'type' => 'fieldset',
'legend' => get_string('contenttypes', 'blocktype.placeholder'),
'help' => true,
'helpcallback' => 'get_block_help',
'elements' => array(
'contenttypes' => array(
'type' => 'html',
'value' => '',
),
),
);
$offset = 0;
$limit = 4;
list($count, $types) = self::get_content_types($view, $offset, $limit);
$pagination = build_showmore_pagination(array(
'count' => $count,
'limit' => $limit,
'offset' => $offset,
'orderby' => 'popular',
'databutton' => 'showmorebtn',
'jscall' => 'wire_blockoptions',
'jsonscript' => 'blocktype/placeholder/blockoptions.json.php',
'extra' => array('viewid' => $view->get('id'),
'blockid' => $instance->get('id')),
));
$smarty = smarty_core();
$smarty->assign('blockid', $instance->get('id'));
$smarty->assign('types', $types);
$typeslist = $smarty->fetch('blocktype:placeholder:contenttypeslist.tpl');
$smarty->assign('typeslist', $typeslist);
$smarty->assign('pagination', $pagination);
$typeshtml = $smarty->fetch('blocktype:placeholder:contenttypes.tpl');
$elements['types']['elements']['contenttypes']['value'] = $typeshtml;
$elements['tags'] = array(
'type' => 'tags',
'title' => get_string('tags'),
'description' => get_string('tagsdescblock'),
'defaultvalue' => $instance->get('tags'),
'help' => false,
);
return $elements;
}
public static function instance_config_save($values, $instance) {
unset($values['contenttypes']);
return $values;
}
public static function get_content_types($view, $offset = 0, $limit = 8) {
$categories = $view->get('categorydata');
$blocks = array();
foreach ($categories as $c) {
$blocktypes = PluginBlockType::get_blocktypes_for_category($c['name'], $view);
if ($c['name'] == 'shortcut') {
foreach ($blocktypes as $key => $blocktype) {
if ($blocktype['name'] == 'placeholder') {
unset($blocktypes[$key]); // do not allow placeholder to select itself
}
}
}
$blocks = array_merge($blocks, $blocktypes);
}
$count = count($blocks);
// sort and return limit
usort($blocks, function ($a, $b) {
return $a['sortorder'] < $b['sortorder'] ? -1 : 1;
});
$blocks = array_slice($blocks, $offset, $limit);
return array($count, $blocks);
}
}
<?php
/**
*
* @package mahara
* @subpackage blocktype-inbox
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
defined('INTERNAL') || die();
$config = new stdClass();
$config->version = 2019052100;
$config->release = '1.0.0';
......@@ -495,6 +495,14 @@ if (!defined('INSTALLER')) {
throw new ConfigSanityException(get_string('multirecipientnotificationnotenabled',
'module.multirecipientnotification'));
}
if (!$siteclosedforupgrade) {
// Make sure that placeholder block is installed and active
safe_require('blocktype', 'placeholder');
if (!PluginBlocktypePlaceholder::is_active()) {
throw new ConfigSanityException(get_string('placeholderblocktypenotenabled',
'blocktype.placeholder'));
}
}
}
}
......
......@@ -323,6 +323,10 @@ function pagination_showmore(btn) {
sendjsonrequest(config['wwwroot'] + btn.data('jsonscript'), params, 'POST', function(data) {
var btnid = btn.prop('id');
btn.parent().replaceWith(data.data.tablerows);
// Run post 'show more' js function if needed
if (data.data.jscall) {
window[data.data.jscall]();
}
// we have a new 'showmore' button so wire it up
jQuery('#' + btnid).on('click', function(e) {
e.preventDefault();
......
......@@ -110,12 +110,16 @@
rewriteConfigureButton(newblock.find('.configurebutton'));
rewriteDeleteButton(newblock.find('.deletebutton'));
}
hideDock();
showMediaPlayers();
setTimeout(function() {
newblock.find('.configurebutton').trigger("focus");
}, 1);
if (data.closemodal) {
hideDock();
showMediaPlayers();
setTimeout(function() {
newblock.find('.configurebutton').trigger("focus");
}, 1);
}
else {
return newblock;
}
};
/**
......@@ -126,6 +130,7 @@
if (data.formelementsuccess) {
eval(data.formelementsuccess + '(form, data)');
}
data.closemodal = true;
if (data.blockid) {
ViewManager.replaceConfigureBlock(data);
}
......@@ -172,6 +177,86 @@