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

Bug 1813987: Translate old views to new gridstack layout on edit

Old layout pages will be displayed as they were
with the old layout.

New pages are created with the new grid layout.

If we try to edit a page with an old layout,
the page will be translated into the new grid layout.

To translate from an old layout to a new grid layout,
we respect the row, column and order of blocks inside each cell.

All blocks in the same row in old layout will be together
in the new layout, and the first block of each column
of the same row are displayed at the same level to each other
in the new layout.

The blocks will respect the column order
they had in the old layout.

A column of the old layout can have many blocks. In the
new grid layout they respect the same order they had.

As we have 12 columns in the new grid layout,
the blocks that where included in a 5 column row,
will be displayed in smaller columns in the new layout.

TODO:
confirmation before trnaslating a page to the new grid layout

behatnotneeded

Change-Id: I46f5cdbacb026519631503437c10d33f1b2800e5
parent 66c08ce0
......@@ -9,13 +9,42 @@
* @copyright (C) 2013 Mike Kelly UAL m.f.kelly@arts.ac.uk
*
*/
function loadGridTranslate(grid, blocks) {
var gridElements = [];
gridRemoveEvents();
// load grid with empty blocks
$.each(blocks, function(index, block) {
var blockContent = $('<div id="block_' + block.id + '"><div class="grid-stack-item-content">'
+ block.content +
'<div/><div/>');
el = grid.addWidget(
blockContent,
block.positionx,
block.positiony,
block.width,
block.height,
null, null, null, null, null,
block.id
);
gridElements.push(el);
});
window.setTimeout(function(){
updateBlockSizes();
updateTranslatedGridRows(blocks);
gridInit();
$.each(gridElements, function(index, el) {
el.on('resizestop', resizeStopBlock);
})
}, 300);
}
function loadGrid(grid, blocks) {
$.each(blocks, function(blockId, block) {
var blockContent = $('<div id="block_' + blockId + '"><div class="grid-stack-item-content">'
$.each(blocks, function(index, block) {
var blockContent = $('<div id="block_' + block.id + '"><div class="grid-stack-item-content">'
+ block.content +
'<div/><div/>');
addNewWidget(blockContent, blockId, block, grid, block.class);
addNewWidget(blockContent, block.id, block, grid, block.class);
});
jQuery(document).trigger('blocksloaded');
......@@ -35,6 +64,64 @@ function loadGrid(grid, blocks) {
}, 300);
}
function updateTranslatedGridRows(blocks) {
var height = [], maxheight = [], realheight;
height[0] = 0;
maxheight[0] = 0;
$.each(blocks, function(key, block) {
var el, y;
if (typeof(height[block.row]) == 'undefined') {
height[block.row] = [];
height[block.row][0] = 0;
}
if (typeof(height[block.row][block.column]) == 'undefined') {
height[block.row][block.column] = 0;
}
y = 0;
if (block.row > 1) {
// get the actual y value based on the max height of previus rows
for (var i = 1; i < block.row; i++) {
y += maxheight[i];
}
}
if (typeof(height[block.row][block.column]) != 'undefined') {
y += height[block.row][block.column];
}
block.positiony = y;
el = $('#block_' + block.id);
realheight = parseInt($(el).attr('data-gs-height'));
$('.grid-stack').data('gridstack').move(
el,
block.positionx,
block.positiony
);
var id = block.id,
dimensions = {
newx: block.positionx,
newy: block.positiony,
newwidth: block.width,
newheight: realheight,
}
moveBlock(id, dimensions);
if (height[block.row][block.column] == 0) {
height[block.row][block.column] = realheight;
}
else {
height[block.row][block.column] += realheight;
}
maxheight[block.row] = Math.max(...height[block.row]);
});
}
function updateBlockSizes() {
$.each($('.grid-stack').children(), function(index, element) {
if (!$(element).hasClass('staticblock')) {
......@@ -67,34 +154,37 @@ function addNewWidget(blockContent, blockId, dimensions, grid, blocktypeclass) {
null, null, null, null, null,
blockId
);
$(el).addClass(blocktypeclass);
el.on('resizestop', function(event, data) {
var content = $(this).find('.grid-stack-item-content')[0];
var heightpx = Math.max(data.size.height, content.scrollHeight),
widthpx = data.size.width,
heightgrid = Math.ceil((heightpx + grid.opts.verticalMargin) / (grid.cellHeight() + grid.opts.verticalMargin)),
widthgrid = Math.ceil((widthpx + grid.opts.verticalMargin) / (grid.cellWidth() + grid.opts.verticalMargin)); // horizontalMargin doesn't exist in gridstack yet
grid.resize($(this), widthgrid, heightgrid);
// update dimesions in db
var id = this.attributes['data-gs-id'].value,
dimensions = {
newx: this.attributes['data-gs-x'].value,
newy: this.attributes['data-gs-y'].value,
newwidth: widthgrid,
newheight: heightgrid,
}
moveBlock(id, dimensions);
});
// images need time to load before height can be properly calculated
window.setTimeout(function(){
updateBlockSizes();
}, 300);
return false;
$(el).addClass(blocktypeclass);
el.on('resizestop', resizeStopBlock);
// images need time to load before height can be properly calculated
window.setTimeout(function(){
updateBlockSizes();
}, 300);
return el;
}
function resizeStopBlock(event, data) {
var grid = $('.grid-stack').data('gridstack');
var content = $(this).find('.grid-stack-item-content')[0];
var heightpx = Math.max(data.size.height, content.scrollHeight),
widthpx = data.size.width,
heightgrid = Math.ceil((heightpx + grid.opts.verticalMargin) / (grid.cellHeight() + grid.opts.verticalMargin)),
widthgrid = Math.ceil((widthpx + grid.opts.verticalMargin) / (grid.cellWidth() + grid.opts.verticalMargin)); // horizontalMargin doesn't exist in gridstack yet
grid.resize($(this), widthgrid, heightgrid);
// update dimesions in db
var id = this.attributes['data-gs-id'].value,
dimensions = {
newx: this.attributes['data-gs-x'].value,
newy: this.attributes['data-gs-y'].value,
newwidth: widthgrid,
newheight: heightgrid,
}
moveBlock(id, dimensions);
}
function moveBlock(id, whereTo) {
var pd = {
......@@ -106,7 +196,41 @@ function moveBlock(id, whereTo) {
sendjsonrequest(config['wwwroot'] + 'view/blocks.json.php', pd, 'POST');
}
var serializeWidgetMap = function(items) {
// get the block id
// json call to update new position and/or dimension
var i;
if (typeof(items) != 'undefined') {
for (i=0; i<items.length; i++) {
if (typeof(items[i].id) != 'undefined') {
$(window).on('colresize', function() {
updateBlockSizes();
});
var blockid = items[i].id,
destination = {
'newx': items[i].x,
'newy': items[i].y,
'newheight': items[i].height,
'newwidth': items[i].width,
}
moveBlock(blockid, destination);
}
}
}
};
function gridInit() {
$('.grid-stack').on('change', function(event, items) {
event.stopPropagation();
event.preventDefault();
serializeWidgetMap(items);
});
$(window).on('colresize', function() {
updateBlockSizes();
});
}
function gridRemoveEvents() {
$('.grid-stack').off('change');
$(window).off('colresize');
}
......@@ -1239,9 +1239,7 @@ jQuery(function($) {
else if ($('.container.main-content').length) {
headerheight = $('.container.main-content').offset().top;
}
$('html, body').animate({
scrollTop: target.offset().top - headerheight
}, 500);
$('html, body').animate({}, 500);
}
});
});
......@@ -289,38 +289,12 @@
location.reload();
});
var serializeWidgetMap = function(items) {
// get the block id
// json call to update new position and/or dimension
var i;
if (typeof(items) != 'undefined') {
for (i=0; i<items.length; i++) {
if (typeof(items[i].id) != 'undefined') {
var blockid = items[i].id,
destination = {
'newx': items[i].x,
'newy': items[i].y,
'newheight': items[i].height,
'newwidth': items[i].width,
}
moveBlock(blockid, destination);
}
}
}
};
$('.grid-stack').on('change', function(event, items) {
event.stopPropagation();
event.preventDefault();
serializeWidgetMap(items);
})
// images need time to load before height can be properly calculated
window.setTimeout(function(){
$(window).trigger('colresize');
}, 300);
gridInit();
// images need time to load before height can be properly calculated
window.setTimeout(function(){
$(window).trigger('colresize');
}, 300);
} // init
......@@ -1001,5 +975,3 @@ function blockConfigError(form, data) {
function wire_blockoptions() {
return ViewManager.blockOptions();
}
/* GRIDSTACK functions */
......@@ -2186,12 +2186,13 @@ class View {
*/
public function get_blocks($editing=false) {
$sql = '
SELECT bi.id, bi.view,positionx, positiony, width, height, blocktype, title, configdata
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 bi.row, bi.column, bi.order';
$blocks = get_records_sql_array($sql, array($this->get('id')));
if (is_array($blocks) || is_object($blocks)) {
......@@ -2203,6 +2204,9 @@ class View {
$b->set('positiony', $block->positiony);
$b->set('width', $block->width);
$b->set('height', $block->height);
$b->set('row', $block->row);
$b->set('column', $block->column);
$b->set('order', $block->order);
$this->grid[]=$b;
}
}
......@@ -2225,7 +2229,11 @@ class View {
$block['height'] = $blockinstance->get('height');
$block['positionx'] = $blockinstance->get('positionx');
$block['positiony'] = $blockinstance->get('positiony');
$blockcontent[$blockinstance->get('id')] = $block;
$block['row'] = $blockinstance->get('row');
$block['column'] = $blockinstance->get('column');
$block['order'] = $blockinstance->get('order');
$block['id'] = $blockinstance->get('id');
$blockcontent[] = $block;
}
return $blockcontent;
}
......
......@@ -6,3 +6,7 @@
margin-bottom: unset;
overflow: hidden;
}
.grid-stack > .grid-stack-item > .grid-stack-item-content {
overflow: hidden !important;
}
......@@ -106,6 +106,10 @@ $animation_speed: .3s !default;
}
}
> .ui-draggable-handle {
border: 1px dashed lightgray;
}
@for $i from 1 through $gridstack-columns {
&[data-gs-width='#{$i}'] { width: (100% / $gridstack-columns) * $i; }
&[data-gs-x='#{$i}'] { left: (100% / $gridstack-columns) * $i; }
......
......@@ -45,12 +45,8 @@
<div class="col">
<div id="bottom-pane" data-role="workspace">
<div id="column-container" class="user-page-content">
{if $newlayout}
<div class="grid-stack">
</div>
{else}
{$columns|safe}
{/if}
</div>
</div>
</div>
......
......@@ -17,6 +17,7 @@ define('SECTION_PAGE', 'blocks');
require(dirname(dirname(__FILE__)) . '/init.php');
require_once(get_config('libroot') . 'view.php');
require_once(get_config('libroot') . 'group.php');
require_once(get_config('libroot') . 'gridstacklayout.php');
$id = param_integer('id', 0); // if 0, we're editing our profile.
$profile = param_boolean('profile');
......@@ -162,31 +163,44 @@ require_once('pieforms/pieform/elements/select.php');
$inlinejs .= pieform_element_select_get_inlinejs();
$inlinejs .= "jQuery(window).on('pageupdated', {}, function() { dock.init(jQuery(document)); });";
if ($newlayout = $view->uses_new_layout()) {
$blocks = $view->get_blocks(true);
$blocksencode = json_encode($blocks);
$inlinejs .="
$(function () {
var options = {
verticalMargin: 10,
float: true, //to place a block in any part of the page and the position will remain fixed
resizable: false,
acceptWidgets: '.blocktype-drag',
};
var grid = $('.grid-stack');
grid.gridstack(options);
grid = $('.grid-stack').data('gridstack');
grid.resizable('.grid-stack-item', true);
// should add the blocks one by one
var blocks = {$blocksencode};
loadGrid(grid, blocks);
});
";
}
else {
// Build content before initialising smarty in case pieform elements define headers.
$viewcontent = $view->build_rows(true);
$needstranslate = "false";
if (!$view->uses_new_layout()) {
// if it's old rowa layout, we need to translate to grid layout
save_blocks_in_new_layout($view->get('id'));
$needstranslate = "true";
}
$blocks = $view->get_blocks(true);
$blocksencode = json_encode($blocks);
$inlinejs .="
$(function () {
var options = {
verticalMargin: 10,
float: true, //to place a block in any part of the page and the position will remain fixed
resizable: false,
acceptWidgets: '.blocktype-drag',
draggable: {
scroll: true,
},
animate: true,
},
grid, translate;
grid = $('.grid-stack');
grid.gridstack(options);
grid = $('.grid-stack').data('gridstack');
grid.resizable('.grid-stack-item', true);
// should add the blocks one by one
var blocks = {$blocksencode};
if ({$needstranslate}) {
// update block heights when they are loaded
loadGridTranslate(grid, blocks);
}
else {
loadGrid(grid, blocks);
}
});
";
// The form for adding blocks via the keyboard
$addform = pieform(array(
......@@ -210,7 +224,6 @@ $addform = pieform(array(
),
));
// Get the placeholder block info
$placeholderblock = PluginBlockType::get_blocktypes_for_category('shortcut', $view, 'placeholder');
$placeholderbutton = '';
......@@ -291,13 +304,7 @@ if ($collection = $view->get('collection')) {
}
$smarty->assign('collectionid', $collectionid);
$smarty->assign('newlayout', $newlayout);
if (!$newlayout) {
// The HTML for the columns in the view
$columns = $viewcontent;
$smarty->assign('columns', $columns);
}
$smarty->assign('needstranslate', ($needstranslate ? 1 : 0));
$smarty->assign('issiteview', isset($institution) && ($institution == 'mahara'));
$smarty->assign('issitetemplate', $view->is_site_template());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment