[IMP] web_editor, website: allow/forbid grid mode for each snippet
Currently, the toggle to grid mode is not the same process for all snippets: some have both the option 'Layout Grid/Cols' and the ability to toggle on drag but other don't have the option, making it complicated/impossible to leave the grid mode. Also, the snippets for which the grid mode has been blocked don't have their move handle anymore, which prevents them to use the normal drag and drop (it was hidden because dragging them would toggle the grid mode). This commit uniformizes the grid mode for all snippets and adds the move handle back to the ones that cannot use this mode. It also improves the grid mode of the 'Items' and 'Carousel' snippets. More precisely: - All the snippets that are allowed to have the grid mode now have both the option "Layout Grid/Cols" and the ability to toggle on drag. - The snippets who cannot toggle the grid mode have the move handle back but it doesn't toggle on drag and they don't have the option. They use the "normal" drag and drop. - The drag and drop has been improved to allow normal columns to go inside the grids. Indeed, since the drag was previously blocked, this case could not occur but now that it is possible, it had to be taken into account. - The grid mode of the Items snippet has been improved by removing the "hardcoded" height that was breaking the grid. - The vertical dropzones of Carousel appearing when dragging inner content have been removed because they appeared in grid mode and were breaking it. It is also more logical because now that this snippet has a column option, vertical dropzones should only appear when dragging a column. task-2973198 X-original-commit: 84d684d8bdf43d3db11defd8174dee44775085c2 Part-of: odoo/odoo#102525
This commit is contained in:
committed by
qsm-odoo
parent
82172c900a
commit
318c937d9d
@@ -251,6 +251,35 @@ export function _reloadLazyImages(columnEl) {
|
||||
imageEl.src = src;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Computes the column and row spans of the column thanks to its width and
|
||||
* height and returns them. Also adds the grid classes to the column.
|
||||
*
|
||||
* @private
|
||||
* @param {Element} rowEl
|
||||
* @param {Element} columnEl
|
||||
* @param {Number} columnWidth the width in pixels of the column.
|
||||
* @param {Number} columnHeight the height in pixels of the column.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function _convertColumnToGrid(rowEl, columnEl, columnWidth, columnHeight) {
|
||||
// First, checking if the column only contains an image and if it is the
|
||||
// case, converting it.
|
||||
if (_checkIfImageColumn(columnEl)) {
|
||||
_convertImageColumn(columnEl);
|
||||
}
|
||||
|
||||
// Computing the column and row spans.
|
||||
const gridProp = _getGridProperties(rowEl);
|
||||
const columnColCount = Math.round((columnWidth + gridProp.columnGap) / (gridProp.columnSize + gridProp.columnGap));
|
||||
const columnRowCount = Math.ceil((columnHeight + gridProp.rowGap) / (gridProp.rowSize + gridProp.rowGap));
|
||||
|
||||
// Adding the grid classes.
|
||||
columnEl.classList.add('g-col-lg-' + columnColCount, 'g-height-' + columnRowCount);
|
||||
columnEl.classList.add('o_grid_item');
|
||||
|
||||
return {columnColCount: columnColCount, columnRowCount: columnRowCount};
|
||||
}
|
||||
/**
|
||||
* Checks whether the column only contains an image or not. An image is
|
||||
* considered alone if the column only contains empty textnodes and line breaks
|
||||
|
||||
@@ -939,40 +939,67 @@ var SnippetEditor = Widget.extend({
|
||||
this.trigger_up('drag_and_drop_start');
|
||||
this.options.wysiwyg.odooEditor.automaticStepUnactive();
|
||||
var self = this;
|
||||
const rowEl = this.$target[0].parentNode;
|
||||
|
||||
// Allow the grid mode if the option is present in the right panel or
|
||||
// if the grid mode is already activated.
|
||||
let hasGridLayoutOption = false;
|
||||
this.trigger_up('user_value_widget_request', {
|
||||
name: 'grid_mode',
|
||||
allowParentOption: true,
|
||||
onSuccess: () => hasGridLayoutOption = true,
|
||||
});
|
||||
const allowGridMode = hasGridLayoutOption || rowEl.classList.contains('o_grid_mode');
|
||||
|
||||
// Number of grid columns and rows in the grid item (BS column).
|
||||
let columnColCount;
|
||||
let columnRowCount;
|
||||
const rowEl = this.$target[0].parentNode;
|
||||
this.dragState = {};
|
||||
if (rowEl.classList.contains('row') && this.options.isWebsite) {
|
||||
// Toggle grid mode if it is not already on.
|
||||
if (!rowEl.classList.contains('o_grid_mode')) {
|
||||
const containerEl = rowEl.parentNode;
|
||||
gridUtils._toggleGridMode(containerEl);
|
||||
if (allowGridMode) {
|
||||
// Toggle grid mode if it is not already on.
|
||||
if (!rowEl.classList.contains('o_grid_mode')) {
|
||||
const containerEl = rowEl.parentNode;
|
||||
gridUtils._toggleGridMode(containerEl);
|
||||
}
|
||||
|
||||
// Computing the moving column width and height in terms of columns
|
||||
// and rows.
|
||||
const columnStart = self.$target[0].style.gridColumnStart;
|
||||
const columnEnd = self.$target[0].style.gridColumnEnd;
|
||||
const rowStart = self.$target[0].style.gridRowStart;
|
||||
const rowEnd = self.$target[0].style.gridRowEnd;
|
||||
|
||||
columnColCount = columnEnd - columnStart;
|
||||
columnRowCount = rowEnd - rowStart;
|
||||
this.dragState.columnColCount = columnColCount;
|
||||
this.dragState.columnRowCount = columnRowCount;
|
||||
|
||||
// Storing the current grid and grid area to use them for the
|
||||
// history.
|
||||
this.dragState.previousGrid = rowEl;
|
||||
this.dragState.prevGridArea = self.$target[0].style.gridArea;
|
||||
|
||||
// Reload the images.
|
||||
gridUtils._reloadLazyImages(this.$target[0]);
|
||||
} else {
|
||||
// If the column comes from a snippet that doesn't toggle the
|
||||
// grid mode on drag, store its width and height to use them
|
||||
// when the column goes over a grid dropzone.
|
||||
const isImageColumn = gridUtils._checkIfImageColumn(this.$target[0]);
|
||||
if (isImageColumn) {
|
||||
// Store the image width and height if the column only
|
||||
// contains an image.
|
||||
const imageEl = this.$target[0].querySelector('img');
|
||||
this.dragState.columnWidth = parseFloat(imageEl.scrollWidth);
|
||||
this.dragState.columnHeight = parseFloat(imageEl.scrollHeight);
|
||||
} else {
|
||||
this.dragState.columnWidth = parseFloat(this.$target[0].scrollWidth);
|
||||
this.dragState.columnHeight = parseFloat(this.$target[0].scrollHeight);
|
||||
}
|
||||
}
|
||||
|
||||
this.dragState = {};
|
||||
// Computing the moving column width and height in terms of columns
|
||||
// and rows.
|
||||
const columnStart = self.$target[0].style.gridColumnStart;
|
||||
const columnEnd = self.$target[0].style.gridColumnEnd;
|
||||
const rowStart = self.$target[0].style.gridRowStart;
|
||||
const rowEnd = self.$target[0].style.gridRowEnd;
|
||||
|
||||
columnColCount = columnEnd - columnStart;
|
||||
columnRowCount = rowEnd - rowStart;
|
||||
this.dragState.columnColCount = columnColCount;
|
||||
this.dragState.columnRowCount = columnRowCount;
|
||||
|
||||
// Deactivate the snippet so the overlay doesn't show.
|
||||
this.trigger_up('deactivate_snippet', {$snippet: self.$target});
|
||||
// Storing the current grid and grid area to use them for the
|
||||
// history.
|
||||
this.dragState.previousGrid = rowEl;
|
||||
this.dragState.prevGridArea = self.$target[0].style.gridArea;
|
||||
|
||||
// Reload the images.
|
||||
gridUtils._reloadLazyImages(this.$target[0]);
|
||||
}
|
||||
|
||||
const isPopup = this.$target[0].closest('div.s_popup');
|
||||
@@ -1011,7 +1038,7 @@ var SnippetEditor = Widget.extend({
|
||||
// Remove the siblings that belong to a snippet in grid mode
|
||||
// and put the identified grid mode snippets in their own "selector".
|
||||
const selectorGrids = new Set();
|
||||
if (this.$target[0].classList.contains('o_grid_item')) {
|
||||
if (rowEl.classList.contains('row')) {
|
||||
if ($selectorSiblings) {
|
||||
// Looping backwards because elements are removed, so the
|
||||
// indexes are not lost.
|
||||
@@ -1062,6 +1089,18 @@ var SnippetEditor = Widget.extend({
|
||||
// dropzone.
|
||||
const rowEl = $dropzone[0].parentNode;
|
||||
|
||||
// If the column doesn't come from a grid mode snippet.
|
||||
if (!self.$target[0].classList.contains('o_grid_item')) {
|
||||
// Converting the column to grid.
|
||||
const spans = gridUtils._convertColumnToGrid(rowEl, self.$target[0], self.dragState.columnWidth, self.dragState.columnHeight);
|
||||
columnColCount = spans.columnColCount;
|
||||
columnRowCount = spans.columnRowCount;
|
||||
|
||||
// Storing the column spans.
|
||||
self.dragState.columnColCount = columnColCount;
|
||||
self.dragState.columnRowCount = columnRowCount;
|
||||
}
|
||||
|
||||
// Creating the drag helper.
|
||||
const dragHelperEl = document.createElement('div');
|
||||
dragHelperEl.classList.add('o_we_drag_helper');
|
||||
@@ -1197,21 +1236,32 @@ var SnippetEditor = Widget.extend({
|
||||
$el = $el.filter(this.$dropZones);
|
||||
if ($el.length) {
|
||||
// If the column is not dropped inside a dropzone.
|
||||
if (this.$target[0].classList.contains('o_grid_item')) {
|
||||
if ($el[0].classList.contains('oe_grid_zone')) {
|
||||
// Case when a column is dropped near a grid.
|
||||
// Placing it in the top left corner.
|
||||
this.$target[0].style.gridArea = `1 / 1 / ${1 + this.dragState.columnRowCount} / ${1 + this.dragState.columnColCount}`;
|
||||
const rowEl = $el[0].parentNode;
|
||||
const rowCount = Math.max(rowEl.dataset.rowCount, 1 + this.dragState.columnRowCount);
|
||||
rowEl.dataset.rowCount = rowCount;
|
||||
if ($el[0].classList.contains('oe_grid_zone')) {
|
||||
// Case when a column is dropped near a grid.
|
||||
const rowEl = $el[0].parentNode;
|
||||
|
||||
// Setting the z-index to the maximum of the grid.
|
||||
gridUtils._setElementToMaxZindex(this.$target[0], rowEl);
|
||||
} else {
|
||||
// Case when a column is dropped near a non-grid dropzone.
|
||||
// If the column doesn't come from a snippet in grid mode,
|
||||
// convert it.
|
||||
if (!this.$target[0].classList.contains('o_grid_item')) {
|
||||
const spans = gridUtils._convertColumnToGrid(rowEl, this.$target[0], this.dragState.columnWidth, this.dragState.columnHeight);
|
||||
this.dragState.columnColCount = spans.columnColCount;
|
||||
this.dragState.columnRowCount = spans.columnRowCount;
|
||||
}
|
||||
|
||||
// Placing it in the top left corner.
|
||||
this.$target[0].style.gridArea = `1 / 1 / ${1 + this.dragState.columnRowCount} / ${1 + this.dragState.columnColCount}`;
|
||||
const rowCount = Math.max(rowEl.dataset.rowCount, 1 + this.dragState.columnRowCount);
|
||||
rowEl.dataset.rowCount = rowCount;
|
||||
|
||||
// Setting the z-index to the maximum of the grid.
|
||||
gridUtils._setElementToMaxZindex(this.$target[0], rowEl);
|
||||
} else {
|
||||
if (this.$target[0].classList.contains('o_grid_item')) {
|
||||
// Case when a grid column is dropped near a non-grid
|
||||
// dropzone.
|
||||
this.$target[0].classList.remove('o_grid_item');
|
||||
this.$target[0].style.removeProperty('z-index');
|
||||
this.$target[0].style.removeProperty('grid-area');
|
||||
if (this.$target[0].classList.contains('o_grid_item_image')) {
|
||||
this.$target[0].classList.remove('o_grid_item_image');
|
||||
this.$target[0].removeAttribute('contentEditable');
|
||||
|
||||
@@ -4440,12 +4440,10 @@ registry.sizing = SnippetOptionWidget.extend({
|
||||
handleEl.classList.toggle('readonly', isMobileView && isGridHandle);
|
||||
}
|
||||
|
||||
// Hiding the move handle for some snippets so we can't drag them
|
||||
// and so we can't toggle the grid mode.
|
||||
// Hiding the move handle in mobile view so we can't drag the
|
||||
// columns.
|
||||
const moveHandleEl = this.$overlay[0].querySelector('.o_move_handle');
|
||||
const untoggleableColumns = '.s_masonry_block, .s_showcase, .s_features_grid, .s_website_form';
|
||||
const disableToggle = this.$target[0].closest(untoggleableColumns);
|
||||
moveHandleEl.classList.toggle('d-none', disableToggle || isMobileView);
|
||||
moveHandleEl.classList.toggle('d-none', isMobileView);
|
||||
|
||||
// Hiding/showing the arrows.
|
||||
if (isGrid) {
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
> * {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
margin: 0 !important;
|
||||
padding: var(--grid-item-padding-y) var(--grid-item-padding-x) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
.s_product_list {
|
||||
padding-top: 20px;
|
||||
|
||||
> div > .row:not(.o_grid_mode) > div {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
> div > .row > div {
|
||||
position: relative;
|
||||
margin-bottom: 20px; // without this style the columns go directly to the top of the bellow ones.
|
||||
|
||||
height: 200px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
|
||||
@@ -477,8 +477,8 @@
|
||||
</div>
|
||||
|
||||
<div data-js="layout_column"
|
||||
data-selector="section.s_features_grid"
|
||||
data-target="> *:has(> .row:not(.s_nb_column_fixed)), > .s_allow_columns">
|
||||
data-selector="section.s_features_grid, section.s_process_steps"
|
||||
data-target="> *:has(> .row), > .s_allow_columns">
|
||||
<we-select string="Columns" data-no-preview="true">
|
||||
<we-button data-select-count="0" data-name="zero_cols_opt">None</we-button>
|
||||
<we-button data-select-count="1">1</we-button>
|
||||
@@ -491,9 +491,9 @@
|
||||
</div>
|
||||
|
||||
<div data-js="layout_column"
|
||||
data-selector="section"
|
||||
data-target="> *:has(> .row:not(.s_nb_column_fixed)), > .s_allow_columns"
|
||||
data-exclude=".s_masonry_block, .s_features_grid">
|
||||
data-selector="section, section.s_carousel_wrapper .carousel-item"
|
||||
data-target="> *:has(> .row), > .s_allow_columns"
|
||||
data-exclude=".s_masonry_block, .s_features_grid, .s_media_list, .s_showcase, .s_table_of_content, .s_process_steps">
|
||||
<we-row>
|
||||
<we-button-group string="Layout" data-no-preview="true">
|
||||
<we-button data-select-layout="grid" data-name="grid_mode">Grid</we-button>
|
||||
|
||||
Reference in New Issue
Block a user