Skip to content

Commit b169ae3

Browse files
committed
Add the slideshow layout
This commit add the possibility to add an image in a slideshow gallery. It also add the possibility of reordering images in a slideshow.
1 parent 500ac44 commit b169ae3

File tree

2 files changed

+87
-19
lines changed

2 files changed

+87
-19
lines changed

addons/html_builder/static/src/plugins/image_gallery_option.xml

+26
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,31 @@
3131
<BuilderNumberInput applyTo="'.carousel'" action="'setCarouselSpeed'" unit="'s'" saveUnit="''" step="0.1"/>
3232
</BuilderRow>
3333
</t>
34+
<t t-name="html_builder.s_image_gallery_slideshow">
35+
<div t-attf-id="#{id}" t-attf-class="carousel slide #{colorContrast}" t-att-data-bs-ride="ride" t-attf-data-bs-interval="#{interval}" style="margin: 0 12px;">
36+
<div class="carousel-inner">
37+
<t t-foreach="images" t-as="image" t-key="image_index">
38+
<div t-attf-class="carousel-item #{image_index == index and 'active' or None}">
39+
<img t-if="!hideImage" class="img img-fluid d-block" t-att-src="image.getAttribute('src')" t-att-alt="image.alt" data-name="Image"/>
40+
</div>
41+
</t>
42+
</div>
43+
<div class="o_carousel_controllers">
44+
<button class="carousel-control-prev o_we_no_overlay o_not_editable" contenteditable="false" t-attf-data-bs-target="##{id}" data-bs-slide="prev" aria-label="Previous" title="Previous">
45+
<span class="carousel-control-prev-icon" aria-hidden="true"/>
46+
<span class="visually-hidden">Previous</span>
47+
</button>
48+
<div class="carousel-indicators s_image_gallery_indicators_bars">
49+
<t t-foreach="images" t-as="image" t-key="image_index">
50+
<button type="button" aria-label="Carousel indicator" t-attf-data-bs-target="##{id}" t-att-data-bs-slide-to="image_index" t-att-class="image_index == index and 'active' or None" t-attf-style="background-image: url(#{image.getAttribute('src')})"/>
51+
</t>
52+
</div>
53+
<button class="carousel-control-next o_we_no_overlay o_not_editable" contenteditable="false" t-attf-data-bs-target="##{id}" data-bs-slide="next" aria-label="Next" title="Next">
54+
<span class="carousel-control-next-icon" aria-hidden="true"/>
55+
<span class="visually-hidden">Next</span>
56+
</button>
57+
</div>
58+
</div>
59+
</t>
3460

3561
</templates>

addons/html_builder/static/src/plugins/image_gallery_option_plugin.js

+61-19
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Plugin } from "@html_editor/plugin";
33
import { applyModifications, loadImageInfo } from "@html_editor/utils/image_processing";
44
import { _t } from "@web/core/l10n/translation";
55
import { ImageGalleryComponent } from "./image_gallery_option";
6+
import { renderToElement } from "@web/core/utils/render";
67

78
class ImageGalleryOption extends Plugin {
89
static id = "imageGalleryOption";
@@ -67,6 +68,12 @@ class ImageGalleryOption extends Plugin {
6768
};
6869
}
6970

71+
setup() {
72+
const slideshowCarousels = this.document.querySelectorAll(".s_image_gallery .carousel");
73+
for (const carousel of slideshowCarousels) {
74+
this.addDomListener(carousel, "slid.bs.carousel", this.onCarouselSlid);
75+
}
76+
}
7077
restoreSelection(imageToSelect) {
7178
if (imageToSelect && !this.dependencies.history.getIsPreviewing()) {
7279
// We want to update the container to the equivalent cloned image.
@@ -119,7 +126,27 @@ class ImageGalleryOption extends Plugin {
119126
itemsEls.push(elementToReorder);
120127
break;
121128
}
122-
this.reorderItems(itemsEls, itemsEls.indexOf(elementToReorder));
129+
130+
const newItemPosition = itemsEls.indexOf(elementToReorder);
131+
itemsEls.forEach((img, index) => {
132+
img.dataset.index = index;
133+
});
134+
const mode = this.getMode(editingGalleryElement);
135+
this.setImages(editingGalleryElement, mode, itemsEls);
136+
137+
if (mode === "slideshow") {
138+
const carouselEl = editingGalleryElement.querySelector(".carousel");
139+
const carouselInstance = window.Carousel.getOrCreateInstance(carouselEl, {
140+
ride: false,
141+
pause: true,
142+
});
143+
144+
carouselInstance.to(newItemPosition);
145+
const activeImageEl = editingGalleryElement.querySelector(
146+
".carousel-item.active img"
147+
);
148+
this.dependencies["builder-options"].updateContainers(activeImageEl);
149+
}
123150
}
124151
}
125152

@@ -203,7 +230,6 @@ class ImageGalleryOption extends Plugin {
203230
imageGalleryElement.classList.remove("o_nomode", "o_masonry", "o_grid", "o_slideshow");
204231
imageGalleryElement.classList.add(`o_${mode}`);
205232
}
206-
//TODO: apply other layouts
207233
switch (mode) {
208234
case "masonry":
209235
this.masonry(imageGalleryElement, images);
@@ -214,6 +240,9 @@ class ImageGalleryOption extends Plugin {
214240
case "nomode":
215241
this.nomode(imageGalleryElement, images);
216242
break;
243+
case "slideshow":
244+
this.slideshow(imageGalleryElement, images);
245+
break;
217246
}
218247
}
219248

@@ -304,6 +333,36 @@ class ImageGalleryOption extends Plugin {
304333
}
305334
}
306335

336+
slideshow(imageGalleryElement, images) {
337+
const container = this.getContainer(imageGalleryElement);
338+
const currentInterval = imageGalleryElement.querySelector(".carousel").dataset.bsInterval;
339+
const carouselEl = imageGalleryElement.querySelector(".carousel");
340+
const colorContrast =
341+
carouselEl && carouselEl.classList.contains("carousel-dark") ? "carousel-dark" : " ";
342+
const slideshowEl = renderToElement("html_builder.s_image_gallery_slideshow", {
343+
images: images,
344+
index: 0,
345+
interval: currentInterval || 0,
346+
ride: !currentInterval ? "false" : "carousel",
347+
id: "slideshow_" + new Date().getTime(),
348+
colorContrast,
349+
});
350+
carouselEl.removeEventListener("slide.bs.carousel", this.onCarouselSlid);
351+
container.replaceChildren(slideshowEl);
352+
slideshowEl.querySelectorAll("img").forEach((img, index) => {
353+
img.setAttribute("data-index", index);
354+
});
355+
356+
imageGalleryElement.style.height = window.innerHeight * 0.7 + "px";
357+
this.addDomListener(slideshowEl, "slid.bs.carousel", this.onCarouselSlid);
358+
}
359+
360+
onCarouselSlid(ev) {
361+
// When the carousel slides, update the builder options to select the active image
362+
const activeImageEl = ev.target.querySelector(".carousel-item.active img");
363+
this.dependencies["builder-options"].updateContainers(activeImageEl);
364+
}
365+
307366
async processImages(editingElement, newImages = []) {
308367
await this.transformImagesToWebp(newImages);
309368
this.setImageProperties(editingElement, newImages);
@@ -442,23 +501,6 @@ class ImageGalleryOption extends Plugin {
442501
this.imageRemovedGalleryElement = undefined;
443502
}
444503
}
445-
446-
reorderItems(itemsEls, newItemPosition) {
447-
itemsEls.forEach((img, index) => {
448-
img.dataset.index = index;
449-
});
450-
const editingImageElement = itemsEls[newItemPosition];
451-
const editingGalleryElement = editingImageElement.closest(".s_image_gallery");
452-
const mode = this.getMode(editingGalleryElement);
453-
454-
// relayout the gallery
455-
this.setImages(editingGalleryElement, mode, itemsEls);
456-
if (mode === "slideshow") {
457-
// todo: wait for implementation in CarouselHandler, convert it to a
458-
// handler and dispatch to it
459-
// this._updateIndicatorAndActivateSnippet(newItemPosition);
460-
}
461-
}
462504
}
463505

464506
registry.category("website-plugins").add(ImageGalleryOption.id, ImageGalleryOption);

0 commit comments

Comments
 (0)