diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index eec85058ebc..9cc1d080bda 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -593,6 +593,7 @@ registry.sizing = SnippetOption.extend({
var direction = $handle.hasClass('n') ? 'top': 'bottom';
$handle.height(self.$target.css('padding-' + direction));
});
+ this.$target.trigger('content_changed');
},
});
diff --git a/addons/website/static/src/js/content/snippets.animation.js b/addons/website/static/src/js/content/snippets.animation.js
index c303d0691d3..e4969f43ce6 100644
--- a/addons/website/static/src/js/content/snippets.animation.js
+++ b/addons/website/static/src/js/content/snippets.animation.js
@@ -430,18 +430,17 @@ registry.slider = publicWidget.Widget.extend({
selector: '.carousel',
disabledInEditableMode: false,
edit_events: {
- 'slid.bs.carousel': '_onEditionSlide',
+ 'content_changed': '_onContentChanged',
},
/**
* @override
*/
start: function () {
- if (!this.editableMode) {
- this.$('img').on('load.slider', this._onImageLoaded.bind(this));
- this._computeHeights();
- }
- this.$target.carousel();
+ this.$('img').on('load.slider', () => this._computeHeights());
+ this._computeHeights();
+ // Initialize carousel and pause if in edit mode.
+ this.$target.carousel(this.editableMode ? 'pause' : undefined);
return this._super.apply(this, arguments);
},
/**
@@ -467,6 +466,7 @@ registry.slider = publicWidget.Widget.extend({
_computeHeights: function () {
var maxHeight = 0;
var $items = this.$('.carousel-item');
+ $items.css('min-height', '');
_.each($items, function (el) {
var $item = $(el);
var isActive = $item.hasClass('active');
@@ -477,9 +477,7 @@ registry.slider = publicWidget.Widget.extend({
}
$item.toggleClass('active', isActive);
});
- _.each($items, function (el) {
- $(el).css('min-height', maxHeight);
- });
+ $items.css('min-height', maxHeight);
},
//--------------------------------------------------------------------------
@@ -489,13 +487,7 @@ registry.slider = publicWidget.Widget.extend({
/**
* @private
*/
- _onEditionSlide: function () {
- this._computeHeights();
- },
- /**
- * @private
- */
- _onImageLoaded: function () {
+ _onContentChanged: function (ev) {
this._computeHeights();
},
});
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index 8e0f4b2dc4a..e46796d4dd4 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -225,69 +225,46 @@ options.registry.carousel = options.Class.extend({
* @override
*/
start: function () {
- var self = this;
-
- this.$target.carousel({interval: false});
- this.id = this.$target.attr('id');
- this.$inner = this.$target.find('.carousel-inner');
- this.$indicators = this.$target.find('.carousel-indicators');
this.$target.carousel('pause');
- this._rebindEvents();
+ this.$indicators = this.$target.find('.carousel-indicators');
+ this.$controls = this.$target.find('.carousel-control-prev, .carousel-control-next, .carousel-indicators');
+ this.$items = this.$target.find('.carousel-item');
+ this.$target.on('slid.bs.carousel.carousel_option', () => this._retargetEdition());
- var def = this._super.apply(this, arguments);
-
- // set background and prepare to clean for save
- this.$target.on('slid.bs.carousel', function () {
- self.$target.carousel('pause');
- self.trigger_up('option_update', {
- optionNames: ['background', 'background_position', 'colorpicker', 'sizing_y'],
- name: 'target',
- data: self.$target.find('.carousel-item.active'),
- });
- });
-
- return def;
+ return this._super.apply(this, arguments);
+ },
+ /**
+ * @override
+ */
+ destroy: function () {
+ this._super.apply(this, arguments);
+ this.$target.off('.carousel_option');
},
/**
- * Associates unique ID on slider elements.
- *
* @override
*/
onBuilt: function () {
- this.id = 'myCarousel' + new Date().getTime();
- this.$target.attr('id', this.id);
- this.$target.find('[data-target]').attr('data-target', '#' + this.id);
- this._rebindEvents();
+ this._assignUniqueID();
+ },
+ /**
+ * @override
+ */
+ onClone: function () {
+ this._assignUniqueID();
},
/**
* @override
*/
onFocus: function () {
- // Needs to be done on focus, not on start, as all other options are
- // maybe not all initialized in start
- this.$target.trigger('slid.bs.carousel');
- },
- /**
- * Associates unique ID on cloned slider elements.
- *
- * @override
- */
- onClone: function () {
- var id = 'myCarousel' + new Date().getTime();
- this.$target.attr('id', id);
- this.$target.find('[data-slide]').attr('href', '#' + id);
- this.$target.find('[data-slide-to]').attr('data-target', '#' + id);
+ this._retargetEdition();
},
/**
* @override
*/
cleanForSave: function () {
this._super.apply(this, arguments);
- this.$target.find('.carousel-item').removeClass('next prev left right active')
- .first().addClass('active');
- this.$target.find('.carousel-indicators').find('li').removeClass('active').html('')
- .first().addClass('active');
- this.$target.removeClass('oe_img_bg ' + this._class).css('background-image', '');
+ this.$items.removeClass('next prev left right active').first().addClass('active');
+ this.$indicators.find('li').removeClass('active').empty().first().addClass('active');
},
//--------------------------------------------------------------------------
@@ -300,18 +277,18 @@ options.registry.carousel = options.Class.extend({
* @see this.selectClass for parameters
*/
addSlide: function (previewMode) {
- var self = this;
- var cycle = this.$inner.find('.carousel-item').length;
- var $active = this.$inner.find('.carousel-item.active, .carousel-item.prev, .carousel-item.next').first();
- var index = $active.index();
- this.$('.carousel-control-prev, .carousel-control-next, .carousel-indicators').removeClass('d-none');
- this.$indicators.append('
');
- var $clone = $active.clone(true);
- $clone.removeClass('active').insertAfter($active);
- _.defer(function () {
- self.$target.carousel().carousel(++index);
- self._rebindEvents();
- });
+ this.$controls.removeClass('d-none');
+ this.$indicators.append($('', {
+ 'data-target': '#' + this.$target.attr('id'),
+ 'data-slide-to': this.$items.length,
+ }));
+ // Need to remove editor data from the clone so it gets its own.
+ const $active = this.$items.filter('.active');
+ $active.clone(false)
+ .removeClass('active')
+ .insertAfter($active);
+ this.$items = this.$target.find('.carousel-item');
+ this.$target.carousel('next');
},
/**
* Removes the current slide.
@@ -319,33 +296,19 @@ options.registry.carousel = options.Class.extend({
* @see this.selectClass for parameters.
*/
removeSlide: function (previewMode) {
- if (this.remove_process) {
- return;
- }
-
- var self = this;
-
- var $items = this.$inner.find('.carousel-item');
- var cycle = $items.length - 1;
- var $active = $items.filter('.active');
- var index = $active.index();
-
- if (cycle > 0) {
- this.remove_process = true;
- this.$target.on('slid.bs.carousel.slide_removal', function (event) {
- $active.remove();
- self.$indicators.find('li:last').remove();
- self.$target.off('slid.bs.carousel.slide_removal');
- self._rebindEvents();
- self.remove_process = false;
- if (cycle === 1) {
- self.$target.find('.carousel-control-prev, .carousel-control-next, .carousel-indicators').addClass('d-none');
- }
- });
- _.defer(function () {
- self._refreshPublicWidgets();
- self.$target.carousel(index > 0 ? --index : cycle);
+ const newLength = this.$items.length - 1;
+ if (!this.removing && newLength > 0) {
+ const $toDelete = this.$items.filter('.active');
+ this.$target.one('slid.bs.carousel', (event) => {
+ $toDelete.remove();
+ this.$indicators.find('li:last').remove();
+ this.$items = this.$target.find('.carousel-item');
+ this.$controls.toggleClass('d-none', newLength === 1);
+ this.$target.find('.carousel').trigger('content_changed');
+ this.removing = false;
});
+ this.removing = true;
+ this.$target.carousel('prev');
}
},
/**
@@ -366,25 +329,33 @@ options.registry.carousel = options.Class.extend({
*/
_setActive: function () {
this._super.apply(this, arguments);
- this.$el.find('[data-interval]').removeClass('active')
- .filter('[data-interval=' + this.$target.attr('data-interval') + ']').addClass('active');
+ this.$el.find('[data-interval]')
+ .removeClass('active')
+ .filter(`[data-interval=${this.$target.attr('data-interval')}]`)
+ .addClass('active');
},
/**
- * Rebinds carousel events on indicators.
+ * Activates current slide for edition and vertical padding. Padding on the
+ * carousel itself would mean the slides' backgrounds don't cover the padding.
*
* @private
*/
- _rebindEvents: function () {
- var self = this;
- this.$target.find('.carousel-control-prev, .carousel-control-next').off('click').on('click', function () {
- self.$target.carousel($(this).data('slide'));
+ _retargetEdition: function () {
+ this.trigger_up('activate_snippet', {
+ $snippet: this.$items.filter('.active'),
+ ifInactiveOptions: true,
});
- this.$target.find('.carousel-indicators [data-slide-to]').off('click').on('click', function () {
- self.$target.carousel(+$(this).data('slide-to'));
- });
-
- /* Fix: backward compatibility saas-3 */
- this.$target.find('.item.text_image, .item.image_text, .item.text_only').find('.container > .carousel-caption > div, .container > img.carousel-image').attr('contentEditable', 'true');
+ },
+ /**
+ * Creates a unique ID for the carousel and reassign data-attributes that depend on it.
+ *
+ * @private
+ */
+ _assignUniqueID: function () {
+ const id = 'myCarousel' + Date.now();
+ this.$target.attr('id', id);
+ this.$target.find('[data-target]').attr('data-target', '#' + id);
+ this.$target.find('[data-slide]').attr('href', '#' + id);
},
});
diff --git a/addons/website/views/snippets.xml b/addons/website/views/snippets.xml
index 95bac08325d..ac46f7b5371 100644
--- a/addons/website/views/snippets.xml
+++ b/addons/website/views/snippets.xml
@@ -198,76 +198,78 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Slide Title
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Slide Title
+
+
Use this snippet to presents your content in a slideshow-like format. Don't write about products or services here, write about solutions.
+
-
Use this snippet to presents your content in a slideshow-like format. Don't write about products or services here, write about solutions.
-
+
+
+
+
+
+
+
+
Clever Slogan
+
+
+
+
Storytelling is powerful. It draws readers in and engages them.
+
+
+
+
+
+
+
+
+
+
+
Edit this title
+
Good writing is simple, but not simplistic.
+
Good copy starts with understanding how your product or service helps your customers. Simple words communicate better than big words and pompous language.
+
+
+
+
-
-
-
-
-
-
Clever Slogan
-
-
-
-
Storytelling is powerful. It draws readers in and engages them.
-
-
-
-
-
-
-
-
-
-
-
Edit this title
-
Good writing is simple, but not simplistic.
-
Good copy starts with understanding how your product or service helps your customers. Simple words communicate better than big words and pompous language.
-
-
-
-
-
-
-
-
+
+
+
+ Previous
+
+
+
+ Next
+
-
-
-
- Previous
-
-
-
- Next
-
-
+
@@ -750,69 +752,71 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Write a quote here from one of your customers. Quotes are a great way to build confidence in your products or services.
-
-
- — Jane DOE, CEO of MyCompany
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Write a quote here from one of your customers. Quotes are a great way to build confidence in your products or services.
+
+
+ — Jane DOE, CEO of MyCompany
+
+
+
+
+
+
+
+
+
+
+ Odoo provides essential platform for our project management. Things are better organized and more visible with it.
+
+
+ — John DOE, CEO of MyCompany
+
+
+
+
+
+
+
+
+
+
+ Odoo provides essential platform for our project management. Things are better organized and more visible with it.
+
+
+
-
-
-
-
-
- Odoo provides essential platform for our project management. Things are better organized and more visible with it.
-
-
- — John DOE, CEO of MyCompany
-
-
-
-
+
+
+
+ Previous
-
-
-
-
-
- Odoo provides essential platform for our project management. Things are better organized and more visible with it.
-
-
-
-
+
+
+ Next
-
-
-
- Previous
-
-
-
- Next
-
-
+
@@ -1147,7 +1151,8 @@
+ data-selector="section"
+ data-target="> .carousel">
Add Slide
@@ -1310,9 +1315,9 @@
-
+
Background
@@ -1320,7 +1325,8 @@
+ data-selector="section, .parallax, .carousel-item"
+ data-exclude=".o_gallery .carousel-item">
Background Image Sizing
@@ -1346,8 +1352,8 @@
+ data-selector="section, .carousel-item"
+ data-exclude=".parallax, .o_gallery .carousel-item">
Background Color
@@ -1389,7 +1395,8 @@
+ data-selector="section, .row > div, .parallax, .s_hr, .s_btn, .carousel-item"
+ data-exclude="section:has(> .carousel), .o_gallery .carousel-item"/>