Conventions
Common patterns
Reusable JavaScript patterns that appear across most Paradigm CMS extensions: searchable lists, create/edit windows, form submission, and delete confirmations.
List with search, filters, and pagination
Most admin list views follow this pattern: a search/filter state object, a load function that calls the API, and render functions for items and pagination controls.
$block.searchParams = {
search_str: '',
status: '',
page: 1,
limit: 20
};
$block.loadItems = async function() {
const response = await ParadigmAPI.REQUEST(SITEURL + '/API/index.php', {
action: 'extension:items->list',
actionVars: {
organization_ID: $block.organizationId,
searchParams: $block.searchParams
}
});
if (response.errors) {
ParadigmAPI.processErrors(response.errors);
return;
}
$block.items = response.items;
$block.totalPages = response.totalPages;
$block.renderItems();
$block.renderPagination();
}
$block.renderItems = function() {
const container = document.getElementById('$block-items-container');
// Build and insert HTML...
ParadigmCSS.render();
}
$block.applyFilters = async function() {
$block.searchParams.page = 1;
await $block.loadItems();
}
Create/edit form in a window
Opening a create or edit form uses WindowManager.createWindow() with
ParadigmPages.fetchBlock() to load the form block. The onClose callback
refreshes the list.
$block.openCreateWindow = function() {
WindowManager.createWindow({
title: 'Create Item',
width: 600,
focus: 'exclusive',
content: async function() {
return await ParadigmPages.fetchBlock(
'extension:admin->items->create',
{ organization_ID: $block.organizationId }
);
},
onClose: function() {
$block.loadItems();
}
});
}
$block.openEditWindow = function(itemId) {
WindowManager.createWindow({
title: 'Edit Item',
width: 600,
focus: 'exclusive',
content: async function() {
return await ParadigmPages.fetchBlock(
'extension:admin->items->edit',
{ item_ID: itemId }
);
},
onClose: function() {
$block.loadItems();
}
});
}
Form submission
Form submit handlers prevent the default event, validate inputs, call the API, handle errors, and close the window on success.
$block.submit = async function(event) {
if (event) event.preventDefault();
const label = document.getElementById('$block-label-input').value.trim();
if (!label) {
alert('Please enter a name.');
return;
}
const response = await ParadigmAPI.REQUEST(SITEURL + '/API/index.php', {
action: 'extension:items->create',
actionVars: {
organization_ID: $block.organizationId,
label: label
}
});
if (response.errors) {
ParadigmAPI.processErrors(response.errors);
return;
}
if (response.success) {
WindowManager.closeCurrentWindow();
}
}
Confirmation before delete
Delete actions always prompt the user for confirmation before making the API call. The event is stopped to prevent parent click handlers from firing.
$block.deleteItem = async function(event, itemId) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
if (!confirm('Are you sure you want to delete this item? This action cannot be undone.')) {
return;
}
const response = await ParadigmAPI.REQUEST(SITEURL + '/API/index.php', {
action: 'extension:items->delete',
actionVars: {
item_ID: itemId
}
});
if (response.errors) {
ParadigmAPI.processErrors(response.errors);
return;
}
if (response.success) {
$block.loadItems();
}
}
Putting it together
A typical admin list block combines all four patterns: the list loads items on init, the header contains search and a create button, each row has edit and delete actions, and the footer shows pagination. See JavaScript conventions for the full block structure and naming rules.