Working and layout's drawers resize
This commit is contained in:
@@ -1,119 +1,157 @@
|
||||
/**
|
||||
* MF Layout Component - JavaScript Controller
|
||||
* Manages drawer state and provides programmatic control
|
||||
* Layout Drawer Resizer
|
||||
*
|
||||
* Handles resizing of left and right drawers with drag functionality.
|
||||
* Communicates with server via HTMX to persist width changes.
|
||||
*/
|
||||
|
||||
// Global registry for layout instances
|
||||
if (typeof window.mfLayoutInstances === 'undefined') {
|
||||
window.mfLayoutInstances = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a layout instance with drawer controls
|
||||
* @param {string} layoutId - The unique ID of the layout (mf-layout-xxx)
|
||||
* Initialize drawer resizer functionality for a specific layout instance
|
||||
*
|
||||
* @param {string} layoutId - The ID of the layout instance to initialize
|
||||
*/
|
||||
function initLayout(layoutId) {
|
||||
function initLayoutResizer(layoutId) {
|
||||
'use strict';
|
||||
|
||||
const MIN_WIDTH = 150;
|
||||
const MAX_WIDTH = 600;
|
||||
|
||||
let isResizing = false;
|
||||
let currentResizer = null;
|
||||
let currentDrawer = null;
|
||||
let startX = 0;
|
||||
let startWidth = 0;
|
||||
let side = null;
|
||||
|
||||
const layoutElement = document.getElementById(layoutId);
|
||||
|
||||
if (!layoutElement) {
|
||||
console.error(`Layout with id "${layoutId}" not found`);
|
||||
console.error(`Layout element with ID "${layoutId}" not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create layout controller object
|
||||
const layoutController = {
|
||||
layoutId: layoutId,
|
||||
element: layoutElement,
|
||||
/**
|
||||
* Initialize resizer functionality for this layout instance
|
||||
*/
|
||||
function initResizers() {
|
||||
const resizers = layoutElement.querySelectorAll('.mf-layout-resizer');
|
||||
|
||||
/**
|
||||
* Get drawer element by side
|
||||
* @param {string} side - 'left' or 'right'
|
||||
* @returns {HTMLElement|null} The drawer element
|
||||
*/
|
||||
getDrawer: function (side) {
|
||||
if (side !== 'left' && side !== 'right') {
|
||||
console.error(`Invalid drawer side: "${side}". Must be "left" or "right".`);
|
||||
return null;
|
||||
}
|
||||
resizers.forEach(resizer => {
|
||||
// Remove existing listener if any to avoid duplicates
|
||||
resizer.removeEventListener('mousedown', handleMouseDown);
|
||||
resizer.addEventListener('mousedown', handleMouseDown);
|
||||
});
|
||||
}
|
||||
|
||||
const drawerClass = side === 'left' ? '.mf-layout-left-drawer' : '.mf-layout-right-drawer';
|
||||
return this.element.querySelector(drawerClass);
|
||||
},
|
||||
/**
|
||||
* Handle mouse down event on resizer
|
||||
*/
|
||||
function handleMouseDown(e) {
|
||||
e.preventDefault();
|
||||
|
||||
/**
|
||||
* Check if a drawer is currently open
|
||||
* @param {string} side - 'left' or 'right'
|
||||
* @returns {boolean} True if drawer is open
|
||||
*/
|
||||
isDrawerOpen: function (side) {
|
||||
const drawer = this.getDrawer(side);
|
||||
return drawer ? !drawer.classList.contains('collapsed') : false;
|
||||
},
|
||||
currentResizer = e.target;
|
||||
side = currentResizer.dataset.side;
|
||||
currentDrawer = currentResizer.closest('.mf-layout-drawer');
|
||||
|
||||
/**
|
||||
* Open a drawer
|
||||
* @param {string} side - 'left' or 'right'
|
||||
*/
|
||||
openDrawer: function (side) {
|
||||
const drawer = this.getDrawer(side);
|
||||
if (drawer) {
|
||||
drawer.classList.remove('collapsed');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Close a drawer
|
||||
* @param {string} side - 'left' or 'right'
|
||||
*/
|
||||
closeDrawer: function (side) {
|
||||
const drawer = this.getDrawer(side);
|
||||
if (drawer) {
|
||||
drawer.classList.add('collapsed');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle a drawer between open and closed
|
||||
* @param {string} side - 'left' or 'right'
|
||||
*/
|
||||
toggleDrawer: function (side) {
|
||||
if (this.isDrawerOpen(side)) {
|
||||
this.closeDrawer(side);
|
||||
} else {
|
||||
this.openDrawer(side);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize event listeners for toggle buttons
|
||||
*/
|
||||
initEventListeners: function () {
|
||||
// Get all toggle buttons within this layout
|
||||
const toggleButtons = this.element.querySelectorAll('[class*="mf-layout-toggle"]');
|
||||
|
||||
toggleButtons.forEach(button => {
|
||||
button.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
const side = button.getAttribute('data-side');
|
||||
if (side) {
|
||||
this.toggleDrawer(side);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (!currentDrawer) {
|
||||
console.error('Could not find drawer element');
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize event listeners
|
||||
layoutController.initEventListeners();
|
||||
isResizing = true;
|
||||
startX = e.clientX;
|
||||
startWidth = currentDrawer.offsetWidth;
|
||||
|
||||
// Store instance in global registry for programmatic access
|
||||
window.mfLayoutInstances[layoutId] = layoutController;
|
||||
// Add event listeners for mouse move and up
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
|
||||
// Log successful initialization
|
||||
console.log(`Layout "${layoutId}" initialized successfully`);
|
||||
}
|
||||
// Add resizing class for visual feedback
|
||||
document.body.classList.add('mf-layout-resizing');
|
||||
currentDrawer.classList.add('mf-layout-drawer-resizing');
|
||||
}
|
||||
|
||||
// Export for module environments if needed
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {initLayout};
|
||||
/**
|
||||
* Handle mouse move event during resize
|
||||
*/
|
||||
function handleMouseMove(e) {
|
||||
if (!isResizing) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
let newWidth;
|
||||
|
||||
if (side === 'left') {
|
||||
// Left drawer: increase width when moving right
|
||||
newWidth = startWidth + (e.clientX - startX);
|
||||
} else if (side === 'right') {
|
||||
// Right drawer: increase width when moving left
|
||||
newWidth = startWidth - (e.clientX - startX);
|
||||
}
|
||||
|
||||
// Constrain width between min and max
|
||||
newWidth = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, newWidth));
|
||||
|
||||
// Update drawer width visually
|
||||
currentDrawer.style.width = `${newWidth}px`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse up event - end resize and save to server
|
||||
*/
|
||||
function handleMouseUp(e) {
|
||||
if (!isResizing) return;
|
||||
|
||||
isResizing = false;
|
||||
|
||||
// Remove event listeners
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
|
||||
// Remove resizing classes
|
||||
document.body.classList.remove('mf-layout-resizing');
|
||||
currentDrawer.classList.remove('mf-layout-drawer-resizing');
|
||||
|
||||
// Get final width
|
||||
const finalWidth = currentDrawer.offsetWidth;
|
||||
const commandId = currentResizer.dataset.commandId;
|
||||
|
||||
if (!commandId) {
|
||||
console.error('No command ID found on resizer');
|
||||
return;
|
||||
}
|
||||
|
||||
// Send width update to server
|
||||
saveDrawerWidth(commandId, finalWidth);
|
||||
|
||||
// Reset state
|
||||
currentResizer = null;
|
||||
currentDrawer = null;
|
||||
side = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save drawer width to server via HTMX
|
||||
*/
|
||||
function saveDrawerWidth(commandId, width) {
|
||||
htmx.ajax('POST', '/myfasthtml/commands', {
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
swap: "outerHTML",
|
||||
target: `#${currentDrawer.id}`,
|
||||
values: {
|
||||
c_id: commandId,
|
||||
width: width
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize resizers
|
||||
initResizers();
|
||||
|
||||
// Re-initialize after HTMX swaps within this layout
|
||||
layoutElement.addEventListener('htmx:afterSwap', function(event) {
|
||||
initResizers();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user