Frontend Development
Festi Framework provides a robust frontend architecture that combines proven technologies with modern approaches. This section outlines the key components and best practices for frontend development in Festi applications.
Frontend Architecture Overview
Festi's frontend architecture consists of several key components:
- jQuery: The primary JavaScript library for DOM manipulation and events
- Jimbo.js: Festi's custom JavaScript utility library for common operations
- HUI Components: PHP-based UI component library for consistent interface design
- ReactJS: Support for modern component-based UI development
jQuery
jQuery is the foundation of Festi's frontend architecture. It provides battle-tested functionality that works reliably across browsers.
While jQuery is considered an older library, we continue to use it because it is easy to implement, widely supported, and simplifies DOM manipulation. Our focus is on building enterprise applications where modern JavaScript frameworks are not always critical to achieving business goals. The primary objective is reducing time to market, ensuring rapid development and deployment. Additionally, since we focus on full-stack development, jQuery allows seamless integration with backend logic, making it a practical choice for many of our projects.
Best Practices
When working with jQuery in Festi applications:
// Always use the full jQuery name instead of $ shorthand
jQuery('.selector').remove(); // Correct
$('.selector').remove(); // Incorrect - don't use this
// Initialize Jimbo with jQuery mode
jQuery(document).ready(function() {
Jimbo.init({
mode: "jquery",
debug: true
});
});
Jimbo.js
Jimbo is Festi's JavaScript utility library that provides standardized functionality for common operations such as:
- Event handling
- Dialog management
- Form validation
- AJAX requests
- Loading indicators
- Notifications
The Jimbo.js file is located in the ThemeAssets package. This package is typically included as part of a theme.
Event Management
Jimbo provides a custom event system that helps maintain clean, modular JavaScript code:
// Subscribe to events
Jimbo.addListener(Jimbo.EVENT_BEFORE_LOAD_FORM, function(event, options) {
console.log(options);
// options.override = true; // Prevent default behavior
});
Jimbo.EVENT_OPEN_DIALOG
Triggered when a dialog with an add or edit form is opened.
Jimbo.addListener(Jimbo.EVENT_OPEN_DIALOG, function (event) {
console.log("Dialog is open.");
});
Jimbo.EVENT_BEFORE_CLOSE_DIALOG
Triggered before closing any dialog window on the page.
The params
object contains the Bootstrap modal close event, which can be used for additional handling.
Jimbo.addListener(Jimbo.EVENT_BEFORE_CLOSE_DIALOG, function (event) {
console.log("Dialog is closing.");
});
Jimbo.EVENT_BEFORE_LOAD_FORM
Triggered before sending an AJAX request to load a form.
Options:
override
- If set to true, the request will be prevented.url
- The URL used to load the form.callback
- A callback function executed after the form is loaded.
Jimbo.EVENT_CALL_ERROR_FIELD
Triggered when an error is set on a field using $field->setErrorMessage($msg)
. This event allows custom error message rendering. By default, errors are displayed as a tooltip.
input
- A jQuery object representing the field where the error occurred.message
- The error message text.override
- If set to true, the default behavior will not occur.
Example: Displaying error messages below the field
Jimbo.addListener(Jimbo.EVENT_CALL_ERROR_FIELD, function (event, options) {
jQuery('.field-invalid-value-message').detach();
var input = options.input;
var message = options.message;
options.override = true;
var messageContainer = input.next();
if (!messageContainer.hasClass('field-invalid-value-message')) {
messageContainer = jQuery('<div class="field-invalid-value-message">' + message + '</div>');
input.after(messageContainer);
} else {
messageContainer.text(message);
}
return true;
});
UI Utilities
Jimbo offers several helpers for UI interactions:
// Display a notification
Jimbo.growlCreate("Warning", "This is a notification message", true);
// Show/hide loading indicators
Jimbo.showLoadingBar('#container');
Jimbo.hideLoadingBar('#container');
// Validate form inputs
Jimbo.util.validateInputs('.f-db-form .form-control');
// Show a confirmation dialog
jQuery.SmartMessageBox({
title: "Are you sure?",
content: "Confirmation of action",
buttons: '[Cancel][Confirm]'
}, function(pressedButton) {
if (pressedButton == "Confirm") {
// Handle confirmation
}
});
Retrieving Form Options
Jimbo.options.formOptions
// Response
options = {
"override": false,
"actionName": actionName,
"url": url,
"callback": callback,
"data": {}
};
Form Validation
To enable form validation, ensure that the correct HTML5 attributes are set.
Validating Specific Fields:
var inputs = jQuery('.f-db-form .form-control');
Jimbo.util.validateInputs(inputs);
inputs
- an array of fields or a CSS selector for the fields.
HUI Components
HUI (HTML UI) is Festi's PHP-based UI component library that allows developers to create consistent interfaces using a fluent API. These components should be preferred over writing raw HTML for maintainable, consistent interfaces.
More information about HUI and Theme can be found in the Theme.
Basic Usage
HUI components are accessed through the $this->ui
object in your DisplayPlugin
code:
// Create a button
echo $this->ui->button()
->setCaption('Save')
->setId('save-button')
->setUrl('/save')
->setCSS('btn-primary')
->fetch();
// Create a message
echo $this->ui->message()
->setType('info')
->setMessage('Operation completed successfully')
->fetch();
Common Components
Dialog
$messageInput = $this->ui->input()->setName('message')->setType('textarea');
$dialog = $this->ui->dialog()
->setTitle(__('Close the User Review #%s', $id))
->addField(__('Message'), $messageInput)
->setUrl($url)
->fetch();
$response->content = $dialog;
Block
echo $this->ui->block()
->setTitle(__('Summary'))
->setContent($content)
->fetch();
Widget
$content = $this->fetch('form_import.phtml');
$response->content = $this->ui->widget()
->setTitle(__('Invoice Creation'))
->setContent($content)
->fetch();
Breadcrumbs
$items = array(
__('Dashboard') => $this->getUrl('/'),
__('Report') => false
);
echo $this->ui->breadcrumbs()->addItems($items)->fetch();
DataList
$columns = array(
'name' => __('Name')
);
$data = array(
'name' => 'Jack'
);
echo $this->ui->datalist()
->setColumns($columns)
->setRows($data)
->fetch();
CSS Guidelines
When writing CSS for Festi applications, follow these naming conventions:
b-*
- Block elementse-*
- Elements within a blockm-*
- Modifiers
<div class="b-login">
<div class="e-row">
<label class="e-label m-required"></label>
<input class="e-input e-login" name="login" />
</div>
</div>
ReactJS Integration
For more complex UI requirements, Festi supports ReactJS integration as a modern approach to frontend development. This allows component-based architecture while maintaining compatibility with the existing jQuery-based system.
Adding ReactJS to a Plugin
- Add a submodule with the ReactJS application in your plugin
- Configure package.json with appropriate build scripts:
"scripts": {
"postbuild": "php ../../../../core/tools/react/deploy.php PROJECT_NAME",
"watch": "npm-watch"
},
"watch": {
"build": {
"patterns": ["src"],
"extensions": "js,jsx"
}
},
"devDependencies": {
"npm-watch": "^0.6.0",
// ...other dependencies
},
- Start development with:
npm install npm run watch
Future Direction: Microfrontends
Festi's frontend architecture is evolving toward a microfrontend approach, which will allow:
- Independent development and deployment of frontend components
- Technology flexibility with a mix of jQuery and React
- Gradual migration path from legacy to modern frontend technologies
- Better isolation and maintainability of UI components
This direction provides a strategic path for modernizing Festi applications while preserving existing functionality.