Commit ccc2446d authored by Cecilia Vela Gurovic's avatar Cecilia Vela Gurovic Committed by Robert Lyon

Bug 1813987: Blocks display fixes

- assessment block: tinymce and the asseesment js
need to be initialized after the block is loaded
- signoff block: sing-off modal is showing now
- embedded media init functions need to be loaded after
the blocks are added to the grid
- wall post block initializes the tinyMCE after it's loaded
and refreshes the content of the block after a new post is made
- comment block: update block size when adding a comment
- scrolling to the block when a new one is added
- modified the text for button to add a new block to the page
  'Drag to add a new block' for normal mode
  'Click to add a new block' for accessibility mode
- add a block to the bottom of the page by default so it won't
break the layout
- add SE annotation to the bottom of the page
- added 'Add block' button event handlers after trnaslating a view
- annotation feedback loads the tinyMCE

behatnotneeded

Change-Id: I7642cacde729a2a85b497e077452de792ec72eb7
parent 25082988
......@@ -115,3 +115,23 @@ function addAnnotationFeedbackError(form, data) {
jQuery('#' + id).removeClass('closed').addClass('active');
formError(form, data);
}
function show_se_desc(id) {
$("#instconf_smartevidencedesc_container div:not(.description)").addClass('d-none');
$("#option_" + id).removeClass('d-none');
}
function annotationBlockInit() {
if ($("#instconf_smartevidence").length) {
// block title will be overwritten with framework choice so make it disabled
$("#instconf_title").attr('disabled', true);
// Set up evidence choices and show/hide related descriptions
$("#instconf_smartevidence").select2();
show_se_desc($("#instconf_smartevidence").val());
$("#instconf_smartevidence").on('change', function() {
show_se_desc($(this).val());
});
}
};
......@@ -45,6 +45,10 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
return $view->get('group') == null;
}
public static function has_static_content() {
return false;
}
/**
* defines if the title should be shown if there is no content in the block
*
......@@ -428,7 +432,8 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
public static function get_instance_javascript(BlockInstance $bi) {
return array(
array(
'file' => 'js/annotation.js'
'file' => 'js/annotation.js',
'initjs' => " annotationBlockInit(); ",
)
);
}
......@@ -444,27 +449,4 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
set_field('blocktype_installed', 'active', 0, 'artefactplugin', 'annotation');
}
}
public static function get_instance_config_javascript(BlockInstance $instance) {
return <<<EOF
jQuery(function($) {
function show_se_desc(id) {
$("#instconf_smartevidencedesc_container div:not(.description)").addClass('d-none');
$("#option_" + id).removeClass('d-none');
}
if ($("#instconf_smartevidence").length) {
// block title will be overwritten with framework choice so make it disabled
$("#instconf_title").attr('disabled', true);
// Set up evidence choices and show/hide related descriptions
$("#instconf_smartevidence").select2();
show_se_desc($("#instconf_smartevidence").val());
$("#instconf_smartevidence").on('change', function() {
show_se_desc($(this).val());
});
}
});
EOF;
}
}
......@@ -22,10 +22,10 @@ function initTinyMCE(formname) {
}
}
$(function() {
function peerassessmentBlockInit() {
configureAssessmentCancel();
configureModalOpen();
});
};
jQuery(window).on('pageupdated', {}, function() {
configureAssessmentCancel();
......@@ -37,6 +37,9 @@ function configureModalOpen() {
$('.js-peerassessment-modal').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
// needs to initialize the tinyMCE editor when the block is loaded
PieformManager.signal('onload');
var blockid = $(this).data('blockid');
var formname = $('#assessment_feedbackform_' + blockid).find('form')[0].id;
dock.show($('#assessment_feedbackform_' + blockid), false, true);
......
......@@ -142,7 +142,8 @@ class PluginBlocktypePeerassessment extends MaharaCoreBlocktype {
public static function get_instance_javascript(BlockInstance $bi) {
return array(
array(
'file' => 'js/peerassessment.js'
'file' => 'js/peerassessment.js',
'initjs' => " peerassessmentBlockInit(); ",
)
);
}
......
......@@ -198,7 +198,8 @@ class PluginBlocktypeWall extends MaharaCoreBlocktype {
public function wallpost_js() {
$js = <<<EOF
function wallpost_success(form, data) {
if (jQuery('#wall').length && data.posts && data.block) {
var wall = jQuery('#wall');
if (wall.length && data.posts && data.block) {
var wall = jQuery('#blockinstance_' + data.block + ' div.wall').first();
var temp = jQuery('<div>');
var textareaid = 'wallpost_' + data.block + '_text';
......@@ -215,6 +216,10 @@ function wallpost_success(form, data) {
formSuccess(form, data);
}
}
jQuery( function() {
// needs to initialize the tinyMCE editor when the block is loaded
PieformManager.signal('onload');
});
EOF;
return "<script>$js</script>";
}
......
......@@ -28,13 +28,17 @@ function loadGridTranslate(grid, blocks) {
);
gridElements.push(el);
});
jQuery(document).trigger('blocksloaded');
window.setTimeout(function(){
updateBlockSizes();
updateTranslatedGridRows(blocks);
gridInit();
$.each(gridElements, function(index, el) {
el.on('resizestop', resizeStopBlock);
})
});
initJs();
}, 300);
}
......@@ -49,6 +53,15 @@ function loadGrid(grid, blocks) {
jQuery(document).trigger('blocksloaded');
initJs();
// images need time to load before height can be properly calculated
window.setTimeout(function(){
updateBlockSizes();
}, 300);
}
function initJs() {
// initialize js function for edit view
if (typeof editViewInit !== "undefined") {
editViewInit();
......@@ -57,11 +70,6 @@ function loadGrid(grid, blocks) {
if (typeof viewmenuInit !== "undefined") {
viewmenuInit();
}
// images need time to load before height can be properly calculated
window.setTimeout(function(){
updateBlockSizes();
}, 300);
}
function updateTranslatedGridRows(blocks) {
......
......@@ -8,3 +8,5 @@ Modifications:
- Moved scss file from src/gridstack.scss to
theme/raw/sass/lib/_gridstack.scss
- removed z-index:0 from grid-stack-content class css because it breaks
the sign-off block modal
......@@ -105,6 +105,8 @@ function addFeedbackSuccess(form, data) {
// then close the modal
if (jQuery('#feedback-form').length) {
dock.hide();
// update the size of the comment block
updateBlockSizes();
}
}
......
......@@ -449,6 +449,8 @@
x = placeholder.attr('data-gs-x'),
y = placeholder.attr('data-gs-y');
var grid = $('.grid-stack').data('gridstack');
grid.removeWidget(placeholder);
$(placeholder).remove();
$('.grid-stack .blocktype-drag').removeClass('btn btn-primary');
......@@ -556,6 +558,11 @@
list.insertBefore(children[length-1], children[0]);
}
}
else {
if (typeof whereTo === 'string') {
$('html, body').animate({ scrollTop: $(blockinstance).offset().top }, 'slow');
}
}
},
function() {
// On error callback we need to reset the Dock
......
......@@ -269,6 +269,7 @@ $string['cantversionvieweditpermissions'] = 'You do not permission to edit this
$string['cantversionviewsubmitted'] = 'You cannot edit this page because it has been submitted for assessment. You will have to wait until it is released.';
$string['cantversionviewgroupeditwindow'] = 'You cannot edit this page. It is outside of the group editable date window.';
$string['cantversionoldlayout'] = 'You cannot save a timeline version of a view with an old layout. You need to convert it to the new grid layout. To do this simply edit the page and the layout will be converted.';
$string['cantaddannotationinoldlayout'] = 'You cannot add an annotation to this page. Please translate the page layout by editing the view first.';
$string['invalidcolumn'] = 'Column %s out of range';
......@@ -318,7 +319,8 @@ $string['nrrows'] = array(
'%s row',
'%s rows',
);
$string['addnewblock'] = 'Add a new block';
$string['addnewblock'] = 'Drag to add a new block';
$string['addnewblockaccessibility'] = 'Click to add a new block';
$string['addnewblockhere'] = 'Add new block here';
$string['add'] = 'Add';
$string['addcolumn'] = 'Add column';
......
......@@ -2163,81 +2163,117 @@ class View {
}
/**
* Gets the view blocks in an array to be easily loaded in js gridstack
* @param boolean $editing whether we are in the edit more or not
*/
public function get_blocks($editing=false, $exporting=false, $versioning=false) {
if (!$versioning) {
$sql = '
SELECT bi.id, bi.view, bi.row, bi.column, bi.order,
positionx, positiony, width, height, blocktype, title, configdata
FROM {block_instance_dimension} bd
INNER JOIN {block_instance} bi
ON bd.block = bi.id
WHERE bi.view = ?
ORDER BY positiony, positionx';
/*
* Returns an array of blockinstances only, not rendering them for viewing or editing
*/
public function get_blocks_datastructure() {
$sql = '
SELECT bi.id, bi.view, bi.row, bi.column, bi.order,
positionx, positiony, width, height, blocktype, title, configdata
FROM {block_instance_dimension} bd
INNER JOIN {block_instance} bi
ON bd.block = bi.id
WHERE bi.view = ?
ORDER BY positiony, positionx';
$blocks = get_records_sql_array($sql, array($this->get('id')));
}
else {
$blocks = $versioning->blocks;
}
$this->grid = array();
if (is_array($blocks) || is_object($blocks)) {
foreach ($blocks as $block) {
require_once(get_config('docroot') . 'blocktype/lib.php');
$block = (object)$block;
$block->view = $this->get('id');
$block->view_obj = $this;
if (!$versioning) {
$grid = array();
if (is_array($blocks) || is_object($blocks)) {
foreach ($blocks as $block) {
require_once(get_config('docroot') . 'blocktype/lib.php');
$block = (object)$block;
$block->view = $this->get('id');
$block->view_obj = $this;
$blockid = $block->id;
}
else {
$blockid = $block->originalblockid;
}
$b = new BlockInstance($blockid, (array)$block);
if (isset($versioning->newlayout)) {
$b = new BlockInstance($blockid, (array)$block);
$b->set('positionx', $block->positionx);
$b->set('positiony', $block->positiony);
$b->set('width', $block->width);
$b->set('height', $block->height);
$b->set('configdata', (array)$block->configdata);
}
else {
$b->set('row', $block->row);
$b->set('column', $block->column);
$b->set('order', $block->order);
$grid[]=$b;
}
$this->grid[]=$b;
}
return $grid;
}
$blockcontent = array();
foreach($this->grid as $blockinstance) {
$block = array();
if ($editing) {
$result = $blockinstance->render_editing();
$result = $result['html'];
/**
* Gets the view blocks in an array to be easily loaded in js gridstack
* @param boolean $editing whether we are in the edit more or not
*/
public function get_blocks($editing=false, $exporting=false, $versioning=false) {
if (!$versioning) {
$sql = '
SELECT bi.id, bi.view, bi.row, bi.column, bi.order,
positionx, positiony, width, height, blocktype, title, configdata
FROM {block_instance_dimension} bd
INNER JOIN {block_instance} bi
ON bd.block = bi.id
WHERE bi.view = ?
ORDER BY positiony, positionx';
$blocks = get_records_sql_array($sql, array($this->get('id')));
}
else {
$result = $blockinstance->render_viewing($exporting, $versioning);
if (call_static_method(generate_class_name('blocktype', $blockinstance->get('blocktype')), 'has_static_content')) {
$block['class'] = 'staticblock';
}
}
$block['content'] = $result;
$block['width'] = $blockinstance->get('width');
$block['height'] = $blockinstance->get('height');
$block['positionx'] = $blockinstance->get('positionx');
$block['positiony'] = $blockinstance->get('positiony');
$block['row'] = $blockinstance->get('row');
$block['column'] = $blockinstance->get('column');
$block['order'] = $blockinstance->get('order');
$block['id'] = $blockinstance->get('id');
$blockcontent[] = $block;
}
return $blockcontent;
}
$blocks = $versioning->blocks;
}
$this->grid = array();
if (is_array($blocks) || is_object($blocks)) {
foreach ($blocks as $block) {
require_once(get_config('docroot') . 'blocktype/lib.php');
$block = (object)$block;
$block->view = $this->get('id');
$block->view_obj = $this;
if (!$versioning) {
$blockid = $block->id;
}
else {
$blockid = $block->originalblockid;
}
$b = new BlockInstance($blockid, (array)$block);
if (isset($versioning->newlayout)) {
$b->set('positionx', $block->positionx);
$b->set('positiony', $block->positiony);
$b->set('width', $block->width);
$b->set('height', $block->height);
$b->set('configdata', (array)$block->configdata);
}
else {
$b->set('row', $block->row);
$b->set('column', $block->column);
$b->set('order', $block->order);
}
$this->grid[]=$b;
}
}
$blockcontent = array();
foreach($this->grid as $blockinstance) {
$block = array();
if ($editing) {
$result = $blockinstance->render_editing();
$result = $result['html'];
}
else {
$result = $blockinstance->render_viewing($exporting, $versioning);
if (call_static_method(generate_class_name('blocktype', $blockinstance->get('blocktype')), 'has_static_content')) {
$block['class'] = 'staticblock';
}
}
$block['content'] = $result;
$block['width'] = $blockinstance->get('width');
$block['height'] = $blockinstance->get('height');
$block['positionx'] = $blockinstance->get('positionx');
$block['positiony'] = $blockinstance->get('positiony');
$block['row'] = $blockinstance->get('row');
$block['column'] = $blockinstance->get('column');
$block['order'] = $blockinstance->get('order');
$block['id'] = $blockinstance->get('id');
$blockcontent[] = $block;
}
return $blockcontent;
}
/*
*
* wrapper around get_column_datastructure
......@@ -2743,6 +2779,53 @@ public function get_blocks($editing=false, $exporting=false, $versioning=false)
return array('html' => $html);
}
/*
* Get the position to place a block at the bottom of the page
*/
public function bottomfreeposition() {
// get y of blocks at the bottom
$sql = 'SELECT MAX("positiony") FROM {block_instance_dimension} bid
INNER JOIN block_instance bi ON bi.id = bid.block
WHERE bi.view = ?';
if ($maxy = get_field_sql($sql, array($this->get('id')))) {
// get max height in last row blocks
$sql = 'SELECT MAX("height") FROM {block_instance_dimension} bid
INNER JOIN {block_instance} bi ON bi.id = bid.block
WHERE bi.view = ? AND bid.positiony = ?';
$maxheight = get_field_sql($sql, array($this->get('id'), $maxy));
return ($maxy + $maxheight);
}
else {
// the view has no blocks
return 0;
}
}
/*
* Helper function to get the blockinstances from old layout pages
* and from new grid layout pages
*/
private function get_blockinstances() {
$blockinstances = array();
if (!$this->uses_new_layout()) {
$view_data = $this->get_row_datastructure();
foreach ($view_data as $row_data) {
foreach($row_data as $column) {
foreach($column['blockinstances'] as $blockinstance) {
$blockinstances[] = $blockinstance;
}
}
}
}
else {
$data = $this->get_blocks_datastructure();
foreach ($data as $blockinstance) {
$blockinstances[] = $blockinstance;
}
}
return $blockinstances;
}
/**
* Returns a list of required javascript files + initialization codes, based on
* the blockinstances present in the view.
......@@ -2753,42 +2836,40 @@ public function get_blocks($editing=false, $exporting=false, $versioning=false)
$javascriptfiles = array();
$initjavascripts = array();
$view_data = $this->get_row_datastructure();
$loadajax = false;
foreach ($view_data as $row_data) {
foreach($row_data as $column) {
foreach($column['blockinstances'] as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
if (!safe_require_plugin('blocktype', $pluginname)) {
continue;
}
$classname = generate_class_name('blocktype', $pluginname);
$instancejs = call_static_method(
$classname,
'get_instance_javascript',
$blockinstance
);
foreach($instancejs as $jsfile) {
if (is_array($jsfile) && isset($jsfile['file'])) {
$javascriptfiles[] = $this->add_blocktype_path($blockinstance, $jsfile['file']);
if (isset($jsfile['initjs'])) {
$initjavascripts[] = $jsfile['initjs'];
}
if (isset($jsfile['extrafilejs']) && is_array($jsfile['extrafilejs'])) {
foreach ($jsfile['extrafilejs'] as $extrafilejs) {
$javascriptfiles[] = $this->add_blocktype_path($blockinstance, $extrafilejs);
}
}
}
else if (is_string($jsfile)) {
$javascriptfiles[] = $this->add_blocktype_path($blockinstance, $jsfile);;
}
$blockinstances = $this->get_blockinstances();
if (!empty($blockinstances)) {
foreach ($blockinstances as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
if (!safe_require_plugin('blocktype', $pluginname)) {
continue;
}
$classname = generate_class_name('blocktype', $pluginname);
$instancejs = call_static_method(
$classname,
'get_instance_javascript',
$blockinstance
);
foreach($instancejs as $jsfile) {
if (is_array($jsfile) && isset($jsfile['file'])) {
$javascriptfiles[] = $this->add_blocktype_path($blockinstance, $jsfile['file']);
if (isset($jsfile['initjs'])) {
$initjavascripts[] = $jsfile['initjs'];
}
// Check to see if we need to include the block Ajax file.
if (!$loadajax && $CFG->ajaxifyblocks && call_static_method($classname, 'should_ajaxify')) {
$loadajax = true;
if (isset($jsfile['extrafilejs']) && is_array($jsfile['extrafilejs'])) {
foreach ($jsfile['extrafilejs'] as $extrafilejs) {
$javascriptfiles[] = $this->add_blocktype_path($blockinstance, $extrafilejs);
}
}
}
else if (is_string($jsfile)) {
$javascriptfiles[] = $this->add_blocktype_path($blockinstance, $jsfile);;
}
}
// Check to see if we need to include the block Ajax file.
if (!$loadajax && $CFG->ajaxifyblocks && call_static_method($classname, 'should_ajaxify')) {
$loadajax = true;
}
}
}
......@@ -2811,34 +2892,33 @@ public function get_blocks($editing=false, $exporting=false, $versioning=false)
$buttons = array();
$toolbarhtml = array();
$view_data = $this->get_row_datastructure();
$loadajax = false;
foreach ($view_data as $row_data) {
foreach($row_data as $column) {
foreach($column['blockinstances'] as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
if (!safe_require_plugin('blocktype', $pluginname)) {
continue;
$blockinstances = $this->get_blockinstances();
if (!empty($blockinstances)) {
foreach ($blockinstances as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
if (!safe_require_plugin('blocktype', $pluginname)) {
continue;
}
$classname = generate_class_name('blocktype', $pluginname);
$instanceinfo = call_static_method(
$classname,
'get_instance_toolbars',
$blockinstance
);
foreach($instanceinfo as $info) {
if (is_array($info)) {
if (isset($info['buttons'])) {
$buttons[] = $info['buttons'];
}
$classname = generate_class_name('blocktype', $pluginname);
$instanceinfo = call_static_method(
$classname,
'get_instance_toolbars',
$blockinstance
);
foreach($instanceinfo as $info) {
if (is_array($info)) {
if (isset($info['buttons'])) {
$buttons[] = $info['buttons'];
}
if (isset($info['toolbarhtml'])) {
$toolbarhtml[] = $info['toolbarhtml'];
}
}
else if (is_string($info)) {
$buttons[] = $info;
}
if (isset($info['toolbarhtml'])) {
$toolbarhtml[] = $info['toolbarhtml'];
}
}
else if (is_string($info)) {
$buttons[] = $info;
}
}
}
}
......@@ -2856,33 +2936,32 @@ public function get_blocks($editing=false, $exporting=false, $versioning=false)
global $THEME;
$cssfiles = array();
$checkedplugins = array();
$view_data = $this->get_row_datastructure();
foreach ($view_data as $row_data) {
foreach ($row_data as $column) {
foreach ($column['blockinstances'] as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
if (!empty($checkedplugins[$pluginname]) ||
!safe_require_plugin('blocktype', $pluginname)) {
continue;
}
$artefactdir = '';
if ($blockinstance->get('artefactplugin') != '') {
$artefactdir = 'artefact/' . $blockinstance->get('artefactplugin') . '/';
}
$hrefs = $THEME->get_url('style/style.css', true, $artefactdir . 'blocktype/' . $pluginname);
$hrefs = array_reverse($hrefs);
$classname = generate_class_name('blocktype', $pluginname);
$instancecss = call_static_method(
$classname,
'get_instance_css',
$blockinstance
);
$hrefs = array_merge($hrefs, $instancecss);
foreach ($hrefs as $href) {
$cssfiles[] = '<link rel="stylesheet" type="text/css" href="' . append_version_number($href) . '">';
}
$checkedplugins[$pluginname] = 1;
$blockinstances = $this->get_blockinstances();
if (!empty($blockinstances)) {
foreach ($blockinstances as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
if (!empty($checkedplugins[$pluginname]) ||
!safe_require_plugin('blocktype', $pluginname)) {
continue;
}
$artefactdir = '';
if ($blockinstance->get('artefactplugin') != '') {
$artefactdir = 'artefact/' . $blockinstance->get('artefactplugin') . '/';
}
$hrefs = $THEME->get_url('style/style.css', true, $artefactdir . 'blocktype/' . $pluginname);
$hrefs = array_reverse($hrefs);
$classname = generate_class_name('blocktype', $pluginname);
$instancecss = call_static_method(
$classname,
'get_instance_css',
$blockinstance
);
$hrefs = array_merge($hrefs, $instancecss);
foreach ($hrefs as $href) {
$cssfiles[] = '<link rel="stylesheet" type="text/css" href="' . append_version_number($href) . '">';
}
$checkedplugins[$pluginname] = 1;
}
}
return array_unique($cssfiles);
......@@ -2910,33 +2989,33 @@ public function get_blocks($editing=false, $exporting=false, $versioning=false)
* the blockinstances present in the view.
*/
public function get_blocktype_javascript() {
$view_data = $this->get_row_datastructure();
$javascript = array();
foreach($view_data as $row) {
foreach($row as $column) {
foreach($column['blockinstances'] as $blockinstance) {
$pluginname = $blockinstance->get('blocktype');
safe_require('blocktype', $pluginname);
$instancejs = call_static_method(
generate_class_name('blocktype', $pluginname),
'get_instance_javascript',
$blockinstance
);
foreach($instancejs as &$jsfile) {
if (stripos($jsfile, 'http://') === false && stripos($jsfile, 'https://') === false) {
if ($artefactplugin = get_field('blocktype_installed', 'artefactplugin', 'name', $pluginname)) {
$jsfile = 'artefact/' . $artefactplugin . '/blocktype/' .
$pluginname . '/' . $jsfile;
}