Variable-Length Line Item Edits
Overview
Documentation of the lineitems.js library and how to use it on CMS pages to edit lists of records that are linked to parent records.
Markup
Cross-site request forgery
- A CSRF token is created and saved as a session variable.
- The value of this variable is saved in a hidden element on the page:
#csrf-tokenwhere it will then be available in jQuery.
Line item listings
- Outer container has
.line-items-containerclass.- This element does not get modified by jQuery.
- The class is used as a selector in jQuery to target the parent of the individual line items.
- Each individual line item element has
.line-itemclass.- The class name is used as a selector in jQuery to assign edit handlers to the individual line items.
- When iterating through the line item objects in PHP, they should be rendered using a separate PHP include file. This way, that line item include file can be shared between the front-end PHP template and the AJAX script that updates page content.
- The
.line-itemelement must have the following attributes defined:data-id: Record id of the line item in the database.data-type: PHP class name of the object that can fetch and save the line item data to and from the database.
- New item button:
<button class="add-line-btn" data-pid="[PARENT_RECORD_ID]" data-type="[CONTENT_PHP_CLASS_NAME]" title="add new [OBJECT NAME]">add new [OBJECT_NAME]</button>
Edit form
- The edit form markup will include the
.line-itemelement. - The flattened display of the line item will be replaced in its entirety with the edit form markup.
- The edit form will be replaced in its entirety with the updated flattened display of the line item once editing has been completed.
- The edit form will include the following variables as hidden form elements:
class: Name of PHP class that handles line item edits.id: Line item record id, if editing an existing line item record.pid: The record id of the parent record that the line item is linked to, if editing a new line item record.*
CSS
There is nothing critical here to the operation of the line item edits.
The line item elements can be table rows or divs.
If they are divs, consider creating CSS rules for .line-item that will render divs contained within it horizontally, and arrange them so that they line up vertically, e.g:
.line_item div {
display: table-cell;
vertical-align: top;
margin-right: 8px;
}
JavaScript
Libraries
[COMMON_LIB]littled/lineitemsjs
Binding handlers and buttons
Default binding handlers and buttons:
$(document).ready(function() {
$('.line-items-container').lineitems('init');
});
The defaults can be overridden by passing in custom configuration in the 2nd argument:
$(document).ready(function() {
$('.line-items-container').lineitems('init', {
edit: {
selector: '.custom-selector',
event: 'click',
uri: '/path/to/custom/edit_ajax.php'
},
del: {
uri: '/path/to/custom/del_ajax.php'
callback: function(evt, options) {
console.log('Custom handler called.');
}
}
});
});
Default selectors
.line-item: Row element with the following attributes holding values that are passed to the AJAX scripts:data-id: Record id of the line item in the database.data-type: Name of the PHP class that will be instantiated to fetch and save edits to the line item in the AJAX script.
.add-line-btn: Button with click handler to add new line items to the list..line-item: Row element with double-click handler to edit existing line items..save-line-btn: Button added to the DOM while editing or deleting a line item that commits the changes..cancel-line-btn: Button added to the DOM while editing or deleting a line item that cancels the edit.#csrf-token: Hidden element holding a CSRF token value that is then passed to the AJAX script to prevent cross-site forgery.
Default ajax handlers
- Adding & editing:
[COMMON_LIB]_ajax/utils/edit_line_item.php - Deleting:
[COMMON_LIB]_ajax/utils/del_line_item.php
PHP
Classes
[COMMON_LIB]content/ajax_page_class.php- Custom class to fetch and save the line item data from and to the database.
Utility scripts
[COMMON_LIB]_ajax/utils/edit_line_item.php[COMMON_LIB]_ajax/utils/del_line_item.php
Content include files
[COMMON_LIB]_templates/forms/ajax/line_item_submit_buttons.php
Adds save and cancel buttons to a line item edit form.
Case-by-case templates
- Line item module containing all the individual line item elements.
- This element is not modified by jQuery at any point.
- Individual line items Template containing the flattened (non-interactive) presentation of an existing line item.
This is used by both the front-end display template and the AJAX script to display and update the line item listings. - Line item edit form
- Included in the template is a
.line-itemelement containing the form and form elements. - Within the
lineitems.jslibrary handler, the existing.line-itemelement will be replaced with the new.line-itemelement containing the editing form markup.
- Included in the template is a
- Delete confirmation form
- Same as the editing form, this template must contain a
.line-itemelement that in turn contains the delete confirmation form elements.
- Same as the editing form, this template must contain a
Workflow
MySQL
- Create new MySQL table for the line items, linking them to an existing table, e.g.:
CREATE TABLE content_template (
id int(11) NOT NULL auto_increment,
site_section_id int(11) NOT NULL,
name varchar(45) NOT NULL,
path varchar(255) NOT NULL,
location enum('local','shared') default NULL,
PRIMARY KEY (id),
UNIQUE KEY idx_content_template_site_section_id_name (site_section_id,name),
CONSTRAINT fk_site_section_content_template FOREIGN KEY (site_section_id) REFERENCES site_section (id) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
- It's necessary to create a separate
site_sectionrecord for the line item object, setting its parent content type to the appropriate type.- This can be done through the "Content Sections" CMS.
- Set the "parent", "root directory", and "table name" properties.
- Add records for any templates used to display or edit the line items to the
content_templatetable in the database.site_section_idis id of the childsite_sectionrecord.namemust be specific to its function, e.g. "details", "delete", or "edit".pathis relative to the site section's base directory as defined in thesite_sectiontable, and should not have a leading slash.locationis either "local" or "shared" depending on if the template exists in the common directory for all sites.- This is not implemented yet, but at some point this will be possible through the "Content Sections" CMS.
INSERT INTO content_template ( site_section_id , name , path , `location` ) VALUES ( 32 , 'details' , '_templates/content/location_line_item.php' , 'local' );
PHP
Create a PHP class to represent the line item records.
require_once (COMMON_CLASS_DIR."db/db_content_class.php");
class ContentTemplate extends db_content_class
{
public $id;
public $name;
public $site_section_id;
public $base_dir;
public $path;
public $location;
function __construct( $id=null, $parent_id=null, $name='', $base_dir='', $path='', $location='')
{
$this->id = new integer_input_class("Template id", "templateID", true, $id);
$this->site_section_id = new integer_input_class("templateParentid", "contentTypeID", true, $parent_id);
$this->name = new string_text_input_class("Name", "templateName", true, $name, 45);
$this->path = new string_text_input_class("Path", "templatePath", true, $path, 255);
$this->location = new string_select_input_class("Location", "templateLocation", false, $location, 20);
}
/* [...] */
}
- The class must have
parent_idproperty.- If the class has property that links it to the parent record but isn't named "parent_id" (as in the example above with the
site_section_id), then add a$parent_idproperty and point it to the existing property in the class's constructor:$this->parent_id = &$this->site_section_id;
- If the class has property that links it to the parent record but isn't named "parent_id" (as in the example above with the
- Add an include for the class in the project's local
cache_class.php.
Markup
Create PHP include files containing markup to display & edit the line items.
Line item group container
One div (or section) to act as a container for the line items.
- This
divshould be outside the include file for the individual line items, either in its own include file, or placed directly in the details and editing include file. - CSS class is
item-items-container. - Include a
buttonfor adding new line items (classadd-line-btn).- CSS class is
add-line-btn. data-pidattribute contains the parent record's id.data-typeattribute contains the name of the PHP class that will be used to save edits to the line.
- CSS class is
Individual flattened line item
Line item edit form
divcontainer withline-itemCSS class.formelement- Hidden input with
name="<?=P_COMMIT ?>"andvalue="1" - Hidden input with
name="class"with the PHP class's name as its value. - Form inputs for each of the object's properties.
- Submit buttons include:
[COMMON_TEMPLATE_DIR]forms/ajax/edit_line_item_submit_buttons.php
Line item deletion confirmation form
divcontainer withline-itemanddelete-confirmationCSS classes.formelement- Hidden input with
name="<?=P_COMMIT ?>"andvalue="1" - Hidden input with
name="class"with the PHP class's name as its value. - Plain text description of the line item, optionally inside of an element with
infoblockas its CSS class. - Submit buttons include:
[COMMON_TEMPLATE_DIR]forms/ajax/delete_line_item_submit_buttons.php
JavaScript
The main content type's details and editing pages will include jQuery binding of the line item handlers.
(function($) {
$(function() {
$('.line-items-container').lineitems('init');
});
});
Any necessary overrides of the line item editing configuration can be set using the 2nd argument to the 'init' routine:
$('.line-items-container').lineitems('init', {
errorContainer: '.error-container',
edit: {
event: 'click',
selector: '.edit-line-btn',
uri: '/path/to/custom/editing_script.php'
}
});
Examples
- littledamien.com ontacts CMS Contact status and contact history
- Luzern Labs Advice CMS (deprecated)