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:

  1. jQuery: The primary JavaScript library for DOM manipulation and events
  2. Jimbo.js: Festi's custom JavaScript utility library for common operations
  3. HUI Components: PHP-based UI component library for consistent interface design
  4. 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.

Form after validation

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();
$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 elements
  • e-* - Elements within a block
  • m-* - 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

  1. Add a submodule with the ReactJS application in your plugin
  2. 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
},
  1. Start development with:
    npm install
    npm run watch

Future Direction: Microfrontends

Festi's frontend architecture is evolving toward a microfrontend approach, which will allow:

  1. Independent development and deployment of frontend components
  2. Technology flexibility with a mix of jQuery and React
  3. Gradual migration path from legacy to modern frontend technologies
  4. Better isolation and maintainability of UI components

This direction provides a strategic path for modernizing Festi applications while preserving existing functionality.