utilikit-1.0.0/js/utilikit.behavior.js
js/utilikit.behavior.js
/**
* @file
* Main Drupal behavior for UtiliKit initialization and lifecycle management.
*
* This file contains the primary Drupal behavior that manages UtiliKit's
* integration with Drupal's behavior system, handling initialization,
* rendering mode coordination, and element processing workflows. The behavior
* ensures proper initialization order, manages the transition between inline
* and static modes, and provides comprehensive validation and debugging
* capabilities during development.
*
* Key Responsibilities:
* - Drupal behavior system integration and lifecycle management
* - Initialization of UtiliKit's environment and state management
* - Coordination between inline and static rendering modes
* - Development mode validation and debugging functionality
* - Integration with Drupal's once() API for element processing
* - Responsive system initialization and configuration
*
* Integration Points:
* - Drupal.behaviors system for automatic initialization
* - drupalSettings for configuration and runtime parameters
* - once() API for preventing duplicate element processing
* - UtiliKit's core services (environment, resize, logging)
* - Development and production mode feature flags
*
* Performance Considerations:
* - Lazy initialization to minimize startup overhead
* - Conditional processing based on rendering mode
* - Efficient element querying with targeted selectors
* - Development features disabled in production
*/
(function(Drupal, once, drupalSettings) {
'use strict';
// Ensure UtiliKit namespace exists for behavior integration
Drupal.utilikit = Drupal.utilikit || {};
/**
* Main UtiliKit behavior for Drupal integration and lifecycle management.
*
* This behavior handles the complete lifecycle of UtiliKit functionality
* within Drupal's behavior system, ensuring proper initialization,
* configuration, and processing of utility classes across page loads
* and AJAX operations.
*
* The behavior implements a lazy initialization pattern to minimize
* performance impact and provides different processing workflows for
* inline and static rendering modes.
*/
Drupal.behaviors.utilikitEngine = {
/**
* Attaches UtiliKit functionality to DOM elements.
*
* This method is called by Drupal's behavior system during page load
* and after AJAX operations. It handles initialization, mode detection,
* and appropriate processing based on the current rendering mode.
*
* Processing Workflow:
* 1. Check and perform one-time initialization if needed
* 2. Detect current rendering mode from configuration
* 3. Apply mode-specific processing (inline vs static)
* 4. Process new elements with once() API integration
*
* @param {Document|Element} context
* The DOM context being processed. Typically, the document on page load
* or a specific container after AJAX operations.
* @param {Object} settings
* Drupal settings object containing configuration and runtime data.
* Includes drupalSettings.utilikit with UtiliKit-specific configuration.
*
* @example
* // Automatically called by Drupal's behavior system
* // No manual invocation required
*
* @example
* // Can be manually triggered for specific contexts
* Drupal.behaviors.utilikitEngine.attach(container, drupalSettings);
*/
attach: function (context, settings) {
// Perform one-time initialization if not already done
if (!Drupal.utilikit.initialized) {
this.initialize();
}
// Determine current rendering mode from configuration
const renderingMode = drupalSettings.utilikit?.renderingMode || 'inline';
// Apply mode-specific processing
if (renderingMode === 'inline') {
this.processInlineMode(context);
}
// Note: Static mode requires no dynamic processing during attach
},
/**
* Performs one-time initialization of UtiliKit systems and services.
*
* This method sets up the complete UtiliKit environment including
* state management, responsive system, logging, and mode-specific
* configuration. It's designed to run only once per page load to
* minimize initialization overhead.
*
* Initialization Sequence:
* 1. Mark UtiliKit as initialized to prevent duplicate setup
* 2. Initialize core environment and state management
* 3. Set up responsive system for inline mode
* 4. Configure development mode features and logging
* 5. Provide mode-specific startup diagnostics
*
* @example
* // Called automatically during first attach() invocation
* // Manual initialization (if needed):
* Drupal.behaviors.utilikitEngine.initialize();
*/
initialize: function() {
// Mark as initialized to prevent duplicate initialization
Drupal.utilikit.initialized = true;
// Initialize core environment and state management
if (typeof Drupal.utilikit.initEnvironment === 'function') {
Drupal.utilikit.initEnvironment(document);
}
// Determine rendering mode for conditional setup
const renderingMode = drupalSettings.utilikit?.renderingMode || 'inline';
// Initialize responsive system for inline mode
if (renderingMode === 'inline' &&
typeof Drupal.utilikit.initResizeListener === 'function') {
Drupal.utilikit.initResizeListener(document, drupalSettings.utilikit.debounce || 50);
}
// Development mode initialization and diagnostics
if (drupalSettings.utilikit.devMode) {
Drupal.utilikit.utilikitLog('UtiliKit initialized', {
mode: renderingMode,
activeBreakpoints: drupalSettings.utilikit.activeBreakpoints
}, 'log');
// Static mode specific diagnostics
if (renderingMode === 'static') {
const elements = document.querySelectorAll('.utilikit');
Drupal.utilikit.utilikitLog('Static mode active - CSS file loaded', {
elementsFound: elements.length,
cssTimestamp: drupalSettings.utilikit.cssTimestamp
}, 'log');
}
}
},
/**
* Validates UtiliKit utility class syntax and usage during development.
*
* This method performs comprehensive validation of utility class names
* to help developers identify syntax errors, unknown prefixes, and
* malformed class patterns. Validation only runs in development mode
* to avoid performance impact in production.
*
* Validation Checks:
* - Class name format validation (prefix--value pattern)
* - Responsive breakpoint prefix validation
* - Known utility prefix verification against rules registry
* - Comprehensive error reporting with specific details
*
* @example
* // Called automatically during development mode processing
* // Manual validation trigger:
* if (drupalSettings.utilikit.devMode) {
* Drupal.behaviors.utilikitEngine.validateClasses();
* }
*
* @example
* // Example validation output for invalid classes:
* // "Invalid class format: uk-padding-20" (missing double dash)
* // "Unknown UtiliKit prefix: invalidprefix in class uk-invalidprefix--20"
*/
validateClasses: function() {
// Skip validation if not in development mode for performance
if (!drupalSettings.utilikit?.devMode) return;
const elements = document.querySelectorAll('.utilikit');
let invalidCount = 0;
elements.forEach(el => {
el.classList.forEach(className => {
// Only validate UtiliKit classes (those starting with 'uk-')
if (!className.startsWith('uk-')) return;
// Basic format validation - check for required double dash separator
const parts = className.split('--');
if (parts.length !== 2) {
Drupal.utilikit.utilikitLog('Invalid class format: ' + className, null, 'warn');
invalidCount++;
return;
}
// Parse responsive prefix and utility prefix
const prefixPart = parts[0].slice(3); // Remove 'uk-' prefix
const prefixMatch = prefixPart.match(/^(?:(sm|md|lg|xl|xxl)-)?(.+)$/);
if (!prefixMatch) return;
// Extract utility prefix (after optional responsive prefix)
const prefix = prefixMatch[2];
// Validate against known utility prefixes in rules registry
if (typeof Drupal.utilikit !== 'undefined' &&
Drupal.utilikit.rules &&
!(prefix in Drupal.utilikit.rules)) {
Drupal.utilikit.utilikitLog('Unknown UtiliKit prefix: ' + prefix + ' in class ' + className, null, 'warn');
invalidCount++;
}
});
});
// Provide summary validation results
if (invalidCount > 0) {
Drupal.utilikit.utilikitLog('Found ' + invalidCount + ' invalid classes', null, 'warn');
} else {
Drupal.utilikit.utilikitLog('All UtiliKit classes validated successfully', null, 'log');
}
},
/**
* Processes elements for inline rendering mode with dynamic CSS generation.
*
* This method handles the processing of UtiliKit elements in inline mode,
* where CSS is generated dynamically on the client side. It uses Drupal's
* once() API to ensure elements are processed only once, even across
* multiple AJAX operations.
*
* Processing Workflow:
* 1. Use once() API to identify unprocessed UtiliKit elements
* 2. Apply appropriate processing based on rendering mode
* 3. Generate and inject CSS for inline mode
* 4. Validate classes in development mode
*
* @param {Document|Element} context
* The DOM context to process for UtiliKit elements. Allows for
* scoped processing after AJAX operations or in specific containers.
*
* @example
* // Called automatically during attach() in inline mode
* // Manual processing for specific context:
* const container = document.querySelector('.dynamic-content');
* Drupal.behaviors.utilikitEngine.processInlineMode(container);
*
* @example
* // Processing after AJAX content update:
* $(document).ajaxComplete(function(event, xhr, settings) {
* Drupal.behaviors.utilikitEngine.processInlineMode(document);
* });
*/
processInlineMode: function(context) {
// Ensure CSS application function is available
if (typeof Drupal.utilikit.applyClasses !== 'function') {
return;
}
// Use once() API to process only new/unprocessed elements
const elements = once('utilikit-engine', '.utilikit', context);
if (elements.length > 0) {
// Re-check rendering mode for safety (may change during runtime)
const renderingMode = drupalSettings.utilikit?.renderingMode || 'inline';
if (renderingMode === 'inline') {
// Apply dynamic CSS generation for inline mode
Drupal.utilikit.applyClasses(elements);
} else {
// Static mode - perform validation only (CSS already loaded)
this.validateClasses();
}
}
}
};
})(Drupal, once, drupalSettings);
/**
* Integration Notes for UtiliKit Behavior System:
*
* Drupal Behavior System Integration:
* - Automatically invoked during page load and AJAX operations
* - Processes both initial page content and dynamically loaded content
* - Integrates with Drupal's once() API for element processing control
* - Respects Drupal's behavior attachment lifecycle and timing
* - Provides graceful degradation when UtiliKit services are unavailable
*
* Rendering Mode Coordination:
* - Detects current mode from drupalSettings.utilikit.renderingMode
* - Applies appropriate processing workflow for each mode
* - Inline mode: Dynamic CSS generation and responsive system initialization
* - Static mode: Validation and diagnostics only (CSS preloaded)
* - Supports runtime mode switching with appropriate behavior adaptation
*
* Performance Optimization Features:
* - Lazy initialization minimizes startup overhead
* - Conditional processing based on rendering mode reduces unnecessary work
* - once() API integration prevents duplicate element processing
* - Development features completely disabled in production builds
* - Efficient DOM querying with targeted selectors
*
* Development Mode Features:
* - Comprehensive initialization logging with configuration details
* - Utility class validation with detailed error reporting
* - Performance diagnostics and element count reporting
* - Mode-specific status information for debugging
* - Integration with UtiliKit's logging system for consistent output
*
* Error Handling and Graceful Degradation:
* - Checks for service availability before invocation
* - Graceful handling of missing configuration or corrupted settings
* - Fallback to safe defaults when configuration is unavailable
* - Non-blocking error handling that doesn't break other behaviors
* - Comprehensive logging for troubleshooting initialization issues
*
* AJAX and Dynamic Content Support:
* - Automatic processing of AJAX-loaded content through behavior system
* - Context-aware processing for partial page updates
* - once() API integration ensures no duplicate processing
* - Supports complex dynamic content scenarios (modals, accordions, etc.)
* - Maintains state consistency across AJAX operations
*
* Configuration and Settings Integration:
* - Full integration with drupalSettings.utilikit configuration object
* - Respects all performance and feature flags from configuration
* - Supports runtime configuration updates through settings changes
* - Validates configuration completeness and provides fallbacks
* - Integrates with experimental feature flags for beta functionality
*/
