I want to create an accordion in grapesjs like the below image.
I have tried the below code but its not working.
editor.BlockManager.add('collapse-block', {
label: 'Collapse',
content: `
<div id="accordion">
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Collapsible Group Item #1
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
Any content can go here, including widgets like forms or containers.
</div>
</div>
</div>
</div>
`,
category: 'Components',
attributes: { class: 'gjs-block-section' },
});
editor.DomComponents.addType('collapse', {
isComponent: el => el.classList && el.classList.contains('collapse'),
model: {
defaults: {
tagName: 'div',
classes: ['collapse'],
traits: [
{
type: 'text',
label: 'Target',
name: 'data-target',
changeProp: 1
},
{
type: 'checkbox',
label: 'Expanded',
name: 'aria-expanded',
changeProp: 1
}
],
script: function() {
var btn = this.closest('.card').querySelector('button');
var target = this.getAttribute('data-target');
btn.setAttribute('data-target', target);
btn.addEventListener('click', function() {
$(target).collapse('toggle');
});
}
}
}
});
It creates the panel but doesn't work for open and close. How to replicate this feature in grapesjs. This can be a group of sections or an individual collapsible. Also any image or text or any media object should also be available to be added in the content section.
First you will have to create a custom block with collapsible
// Define a new component type for the collapsible
gjs.Components.addType('collapsible', {
model: {
defaults: {
tagName: 'div',
classes: ['collapsible-block'],
components: [
{
type: 'div',
tagName: 'div',
classes: ['collapsible-header'],
editable: true, // Allows editing the div text
components: [
{
type: 'text',
tagName: 'div',
content: 'Open Collapsible',
editable: true, // Allows editing the inner div text
style: {
color: '#fff', // White text color
flex: '1', // Ensures text div takes up full space within the header
'text-align': 'center'
}
}
]
},
{
type: 'div',
classes: ['collapsible-content'],
components: [
{
type: 'text',
tagName: 'p',
content: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
},
],
droppable: true, // Allows adding more blocks inside the content
}
],
// Define traits for div text to ensure it stays editable
traits: [
{
type: 'text',
label: 'Header Text',
name: 'headerText',
changeProp: 1
}
],
}
}
});
// Add the custom block to the BlockManager
gjs.BlockManager.add('bootstrap-collapsible', {
label: 'Collapsible',
category: 'Bootstrap Components',
activate: true,
content: { type: 'collapsible' }
});
Then you need to inject css and js files
// Ensure the editor is fully loaded before injecting stylesheets
gjs.on('load', function() {
injectStylesheets(gjs, [
'{% static "libs/css/bootstrap-4-5-3.min.css" %}',
'{% static "libs/css/jquery-ui.css" %}',
'{% static "libs/css/bootstrap.min.css" %}',
'{% static "libs/fontawesome/css/all.css" %}',
'{% static "libs/fontawesome4/css/font-awesome.css" %}',
'{% static "css/style.css" %}?v={{ DRAVOKA_APP_VERSION }}',
]);
injectScripts(gjs, [
'{% static "libs/js/jquery.min.js" %}',
'{% static "libs/js/jquery-3.5.1.min.js" %}',
'{% static "libs/js/bootstrap.bundle.min.js" %}',
'{% static "libs/js/bootstrap.min.js" %}',
'{% static "js/script.js" %}',
]);
});
// Function to inject multiple stylesheets into the canvas
function injectStylesheets(gjs, urls) {
const canvasDoc = gjs.Canvas.getDocument();
const head = canvasDoc.head;
urls.forEach(function(url) {
const link = canvasDoc.createElement('link');
link.rel = 'stylesheet';
link.href = url;
head.appendChild(link);
});
}
// Function to inject multiple JavaScript files into the canvas
function injectScripts(gjs, urls) {
const canvasDoc = gjs.Canvas.getDocument();
const head = canvasDoc.head;
urls.forEach(function(url) {
const script = canvasDoc.createElement('script');
script.src = url;
head.appendChild(script);
});
}
const id = "{{ page.id }}";
if(id){
const html = `{{ page.temp_html|safe }}`;
const css = `{{ page.temp_css|safe }}`;
if (html !== 'None'){
gjs.setComponents(html);
gjs.setStyle(css);
}
}
Then in script.js you will have to handle collapsible content
$(document).on("click", ".collapsible-header", function(event){
// Toggle the 'active' class on the clicked element
$(this).toggleClass('active');
// Find the next sibling element (the content) and toggle its display
const $content = $(this).next();
if ($content.css('display') === 'block') {
$content.css('display', 'none');
} else {
$content.css('display', 'block');
}
});