Reputation: 3
I am using Froala Editor in my project, and I have successfully implemented a custom simple dropdown using the editor's API. However, I need to create a multi-level dropdown (accordion-style) where each top-level option can have its own sub-options.
Here's the code I currently have for a simple custom dropdown:
FroalaEditor.DefineIcon('my_dropdown', { NAME: 'cog', SVG_KEY: 'cogs' });
FroalaEditor.RegisterCommand('my_dropdown', {
title: 'Advanced options',
type: 'dropdown',
focus: false,
undo: false,
refreshAfterCallback: true,
options: {
'v1': 'Option 1',
'v2': 'Option 2'
},
callback: function (cmd, val) {
console.log(val);
},
refresh: function ($btn) {
console.log('do refresh');
},
refreshOnShow: function ($btn, $dropdown) {
console.log('do refresh when show');
}
});
new FroalaEditor('div#froala-editor', {
toolbarButtons: ['bold', 'italic', 'formatBlock', 'my_dropdown']
})`;
I want to extend this functionality to support a multi-level dropdown. For example:
Level 1 - Option 1
Level 1 - Option 2
Level 2 - Option 1
Level 2 - Option 2
Level 1 - Option 3
I have tried modifying the refreshOnShow function to include nested HTML for the multi-level dropdown and adding event handlers to manage the showing and hiding of sub-options. Here is my attempt:
FroalaEditor.DefineIcon('my_multilevel_dropdown', { NAME: 'list', SVG_KEY: 'list' });
FroalaEditor.RegisterCommand('my_multilevel_dropdown', {
title: 'Advanced options',
type: 'dropdown',
focus: false,
undo: false,
refreshAfterCallback: true,
options: {
'level1_option1': 'Level 1 - Option 1',
'level1_option2': 'Level 1 - Option 2',
'level1_option3': 'Level 1 - Option 3'
},
callback: function (cmd, val) {
console.log('Selected:', val);
},
refresh: function ($btn) {
console.log('do refresh');
},
refreshOnShow: function ($btn, $dropdown) {
console.log('do refresh when show');
// Add custom HTML for multi-level dropdown
$dropdown.html(`
<div class="fr-dropdown-wrapper">
<div class="fr-command fr-dropdown-item" data-cmd="level1_option1">Level 1 - Option 1</div>
<div class="fr-command fr-dropdown-item" data-cmd="level1_option2">Level 1 - Option 2</div>
<div class="fr-command fr-dropdown-item" data-cmd="level1_option3">Level 1 - Option 3
<div class="fr-submenu">
<div class="fr-command" data-cmd="level2_option1">Level 2 - Option 1</div>
<div class="fr-command" data-cmd="level2_option2">Level 2 - Option 2</div>
</div>
</div>
</div>
`);
// Debug: Check if elements are found
var $commands = $dropdown.find('.fr-command');
console.log($commands.length + ' commands found.');
// Add accordion behavior
$commands.off('click').on('click', function (event) {
var $this = $(this);
var $submenu = $this.children('.fr-submenu');
if ($submenu.length) {
event.stopPropagation();
$submenu.slideToggle();
$this.siblings().find('.fr-submenu').slideUp();
} else {
var cmd = $this.data('cmd');
$this.closest('.fr-dropdown-wrapper').trigger('click.command', [cmd]);
}
});
}
});
new FroalaEditor('#froala-editor', {
toolbarButtons: ['bold', 'italic', 'formatBlock', 'my_multilevel_dropdown']
});
Upvotes: 0
Views: 144
Reputation: 11
You're on the right track!
The approach you've taken to create a multi-level dropdown in Froala Editor is a good one. Here's a breakdown of your code and some refinements to make it work smoothly: Understanding the Code
DefineIcon: This registers a custom icon for your dropdown button.
RegisterCommand: This is where the magic happens. You define:
title: The name displayed on the button.
type: Set to 'dropdown' for a dropdown menu.
options: These are the top-level options of your dropdown.
callback: This function is executed when a top-level option is selected.
refreshOnShow: This is crucial for dynamically generating the multi-level structure.
refreshOnShow Function: This is where you build the HTML for your multi-level dropdown.
Dynamic Submenu Generation:
Instead of hardcoding the submenu structure within refreshOnShow, it's better to make it more dynamic based on your data structure.
refreshOnShow: function ($btn, $dropdown) {
// Assuming you have a data structure like this:
const menuData = {
'level1_option1': 'Level 1 - Option 1',
'level1_option2': {
title: 'Level 1 - Option 2',
suboptions: {
'level2_option1': 'Level 2 - Option 1',
'level2_option2': 'Level 2 - Option 2'
}
},
'level1_option3': 'Level 1 - Option 3'
};
// Build the dropdown HTML
let html = '';
for (const key in menuData) {
const item = menuData[key];
html += `<div class="fr-command fr-dropdown-item" data-cmd="${key}">${item.title || item}</div>`;
if (item.suboptions) {
html += `<div class="fr-submenu">`;
for (const subkey in item.suboptions) {
html += `<div class="fr-command" data-cmd="${subkey}">${item.suboptions[subkey]}</div>`;
}
html += `</div>`;
}
}
$dropdown.html(html);
// ... (rest of your accordion behavior code)
}
Accordion Behavior: Your accordion logic is good. Here's a slightly refined version:
$commands.off('click').on('click', function (event) {
var $this = $(this);
var $submenu = $this.children('.fr-submenu');
if ($submenu.length) {
event.stopPropagation();
$submenu.slideToggle();
$this.siblings().find('.fr-submenu').slideUp();
} else {
// Handle top-level option selection
var cmd = $this.data('cmd');
$this.closest('.fr-dropdown-wrapper').trigger('click.command', [cmd]);
}
});
Styling:
You'll likely want to add some CSS to style your multi-level dropdown to match your Froala Editor theme.
You can check out more options in the Froala docs.
Upvotes: 0