Overview
WebForce sites are built of elements in hierarchical model. Every element has meta information and properties. The applications are just objects in the WebForce infrastructure which have meta information and properties.
The meta information contains of 2 parts:
- Meta information of the class of element
- Meta information of the instance of element
The properties of the element contain the information that reflects how the element will be displayed and how changing the information from these properties affects the outlook of the element.
The class of the element contains information about the element that is about to be added:
- Unique ID of the element — an integer (e.g. 130)
- Instance ID of the element — a string that represents an element with the ID above that may have the same functionality but the way it looks may be slightly different
- Edit template — template that displays an interface for editing the element properties
- View template — the template that visualizes the properties in the way the end user will perceive them
- URL for element helpful information
The meta information of the instance of the element contains class meta data as well as:
- ID of the instance of the element — an integer (e.g. 235111545)
- ID of the parent element in the hierarchy on the page
- Order of the element among its siblings - an index defining the place of the current element among its siblings
When an element is added its Edit Template is displayed and the user is allowed to enter the initial values of element's properties. After the element is added its visualized by its View Template. If the user wants to edit the properties of an existing element, the Edit Template is displayed filling the current element properties.
Edit Templates
Overview
The Edit Templates are displayed within a framework that manages the properties and meta data of elements. When an edit template is displayed within the framework all meta information and properties are available in the JavaScript environment of the Edit Template. The framework that manages the Edit Templates allows them to be entirely client side based which means they could be written the means of HTML/JS/CSS only.
Life cycle
The lifespan of an Edit Template has the following phases:
- Loading the code of the Edit Template
- Invoking an initialization procedure
- Validating the values of the form fields prior submitting the data to the server
- Submitting the data from the Edit Template to the server
- Closing the Edit Template or opening another one
The developer of the Edit Template can hook on any of these phases and modify its behavior.
Rules for Coding
The Edit Template code is an organized list of form elements that are subjected to a few rules:
- Must use MooTools as a JavaScript library
- Unified DOM structure (in order to be uniformly styled with CSS) — see Appendix
- All fields that allow editing or keeping element properties should have a "name" attribute and the value should be "property__<property name>"
- If the field is of a "file" type, the property name should end with "_url" (e.g. "Image_url"). If you want to delete the digital asset that's stored in this property set a value of "__None__".
- All fields that must be updated with a default value upon adding of an element should have an attribute "default_value" and the value should be the desired default one
- Fields that need to be validated prior submitting data to the server should have an attribute "validate_as" where the value could be
- "not_empty"
- "number"
- "email"
- "custom" — in this case the developer must specify a reference to a validator function that would be invoked for this field. The validator function name should be as a value of a "validator" attribute. The function should accept one parameter — the value to be validated. It is bound to the current instance of SK.UI.Object.Properties or the object that inherits it (it means "this" in the function refers to the JS object instance). It should return a hash structure as follows:
{
"success": true or false,
"message": "<text of message if success is false>"
}
- The initialization of the property sheet should be a simple JavaScript line:
<script type="text/javascript">new SK.UI.Properties( ).init();</script>
- If element needs to do some extra processing it must provide a JavaScript object that extends SK.UI.Properties and replace the name of the constructor in the initialization above with its own class name.
Customizing
If one needs to customize the behavior of the Edit Template may extend the functionality of SK.UI.Properties. This base class executes the initialization, validation, submission and closing phases. Each of them can be overridden as well as one can hook on before- and after- phase execution via MooTools standard event mechanism.
The events that take place in the base class are:
- init — invoked upon UI initialization — at this phase the element properties are mapped to the form fields (if any) that have the appropriate name (property__<propertyname>)
- add — invoked when a button "Add" is clicked. It initiates the server-side call for adding a new element. Element properties are collected from the form fields and are validated if there are any validators attached to them
- update — invoked when a button "Update". It initiates the server-side call for updating the element properties. Element properties are collected and validated prior that.
- close — invoked after "add" or "update" as well as on "Close" button click
- error — invoked when an error occurs
- help — invoked when the "Help" button is clicked
Each of them (with a few exceptions) have a "before" and "after" events as follows: "beforeinit", "afterinit", "beforeadd", "afteradd", "beforeupdate", "afterupdate", "beforeclose", "beforehelp", "afterhelp".
In order to hook at some point of execution without fully overriding the event one should do:
var MyElement = new Class({ Extends: SK.UI.Object.Properties, initialize: function( ) { this.parent(); // Initialize the base class this.addEvents({ "beforeinit": function( ) { ... }, "beforeupdate": function( ) { ... } }); } }); |
If an event needs to be fully overridden one should do:
var MyElement = new Class({ Extends: SK.UI.Object.Properties, initialize: function( ) { this.parent(); // Initialize the base class this.removeEvents( "update" ); this.removeEvents( "close" ); this.addEvents({ "update": function( ) { ... }, "close": function( ) { ... } }); } }); |
In order to use the base events in some conditions one can use the methods initially attached to those events. The names of the methods are composed of "on" prefix and the event name in camel-case, e.g. the "beforeupdate" event is bound to the "onBeforeUpdate" method. The "update" event is bound to the "onUpdate" method and so on.
SK.UI.Properties Functional Reference
Initialization
- init() — initializes the framework
- onBeforeInit() — executed prior onInit
- onInit() — initializes the UI
- onAfterInit() — invoked after onInit
Adding an Element
- onBeforeAdd() — invoked before onAdd
- onAdd() — collects, validates and submits the element properties from the form when the "Add" button is clicked. The submission to the server is through anasynchronous AJAX request. On event completion is invoked onAfterAdd
- onAfterAdd( success, message, data ) — invoked after the "onAdd" AJAX request is completed. The parameters are as follows
- success — true or false
- message — the error message if there's a failure during the request
- data — the "data" property from the AJAX response JSON
Updating an Element
- onBeforeUpdate() — invoked prior onUpdate
- onUpdate() — invoked when the "Update" button is clicked. This method collects, validates and submits element properties to the server through an asynchronous AJAX request. The onAfterUpdate method is invoked upon completion.
- onAfterUpdate( success, message, data) — executed after the AJAX request is completed. The parameters have the same meaning as for onAfterAdd
Error Handling
- onError( message, data ) — invoked when there's an error during the AJAX request
Closing the Edit Template Window
- onBeforeClose( data ) — invoked by onClose
- onClose( data ) - executed upon a successful add/update request or when the "Close" button is clicked. It invokes onBeforeClose and then closes the window. The "data" parameter is the same "data" parameter returned by the AJAX request from onAdd or onUpdate
Displaying Helpful Information
- onBeforeHelp() — invoked from onHelp
- onHelp() — invoked when clicking the "Help" button. Opens the help window for that particular element (if any URL to a helpful information is provided in the element meta data).
- onAfterHelp() — invoked from onHelp
Buttons Management
getButtons — invoked when initializing the UI. The method checks if the property sheet is displayed prior adding or updating an element to display a different set of buttons.
- When in "update" mode the buttons are "update", "close" and "help" (if any help URL is provided)
- When in "add" mode the buttons are "add", "close" and "help" (if any help URL)
- For each of the modes there are several performed actions:
- Generating a list of buttons. In the default case each of the buttons is generated by the getDefaultButton( <button type> ) method.
- Check if there's a help URL provided by hasHelpButton.
- Returning an array of buttons.
- If one needs to add an extra button, the actions above must be performed and the button must be added in the list at the appropriate place. The buttons are displayed in the order of the list.
var MyPropertyManager = new Class({ Extends : SK.UI.Object.Properties, getToolbarButtons : function () { // get current button configuration (Object) var buttons = this.parent(); // extend the config with our custom button buttons.my_button = { "caption" : 'My Button', 'event' : 'mycustomevent', 'handler' : SK.UI.Object.Properties.Button }; return buttons; }, initialize : function () { // register our custom event, which will be fired when the button is clicked this.addEvent('mycustomevent', function () { alert('Hello, world!'); }); } }); |
The buttons are displayed only if there's a placeholder that can be accessed via the CSS selector ".skprops .buttons-box"
hasHelpButton() — returns true if there's a help URL supplied
getDefaultButton( button_type ) — returns a DOM element that would be displayed as a button. The button_type values that are currently supported are "add", "update", "close" and "help". This function invokes a class that deals with button DOM element production — SK.UI.Properties.Button. The constructor of the object returns the DOM element that's ready to be injected. Here's the interface of that class:
- SK.UI.Properties.Button( manager, properties ) — the "manager" is a reference to the SK.UI.Object.Properties object or the object that inherits it. The "properties" is a hash with the following keys:
- class — CSS class name for the button
- event — the event ID that would be fired when one clicks on the button
- caption — the button caption
Edit Template Environment Handling
- getForm() — returns a reference to the <form> DOM element where the element property fields are settled in
- validate() — validates all element properties (that have name="property_<property name>") if they have a validator set
- isUpdateMode() — returns true if the edit template is opened in update mode
- isAddMode() — returns true if the edit template is opened in add mode
- noActionPerformed() — returns true if onAdd or onUpdate has been invoked
- displayError( message ) — displays an error message
- displayAddNextObject( parent_id ) — opens the edit template of the first child object in the hierarchy of object classes in add mode. The "parent_id" is the ID of the element in the added elements hierarchy. The ID of the element can be fetched after onAdd or onUpdate from the "data" structure by "data.meta.node_id". The information about the next object is used from the value returned by getEnvironment.
- closeWindow() — closes the edit template window
- getEnvironment() — returns information about the object environment. This returns a hash structure with the following information:
meta: {
user_id : <user ID who owns the element>,
node_id : <unique ID of the added element — it's empty if the object is about to be added>,
obj_id : <the unique object type ID>,
obj_inst : <the instance ID of the element>,
obj_order: <the index of the element among its siblings>,
parent_id: <the node_id of the parent element>
},
next_object: {
obj_id : <type ID of the next object in the class hierarchy>,
obj_inst : <instance ID of the next object>
},
help_url: <URL to the help page of the current element>,
properties: {
<property name1>: <property value1>,
<property name2>: <property value2>,
...
}
Helper Utilities
Expand-collapse sections
If you need to have an expandable section just add a "class" attribute to a FIELDSET and set it to "expanded" or "collapsed". This indicates the state the section will appear initially. Then you can set a title of the section using an H1 tag where you can specify an icon too:
<fieldset class="collapsed"> <h1 class="options">Options</h1> <div> <div class="label"><label for="...">...</label></div> <div class="field"><input type="..."></div> </div> .. .</fieldset> |
File upload
If one needs to integrate a property for allowing uploading a digital asset, s/he needs to just set the proper "name" attribute to a <input type="file"...> tag, so that it's taken as an element property.
... <input type="file" name="property__Src" class="field-text w3u" validate_as="custom" validator="SK.UI.Properties.Validator.FileNotEmpty"> ... |
Links
SK.UI.LinkManager
Access Protection Control
This control allows the editor to protect the element when being viewed unless the viewer is authenticated. The control is placed in a DOM element with a class ".placeholder-box". The constructor is simply:
- SK.UI.Properties.Protection( <list of modules to include/exclude> ) — the "list of modules to include/exclude" is not mandatory. It's a hash with the following keys
{
password: true/false, // Global password only protection
mailing_list: true/false, // Protection by email which has to exist in a certain mailing list
members: true/false, // Username + password protection for individual members
}
By default all types of protection are enabled.
Here is a sample of how to use it:
var properties_protection = new SK.UI.Properties.Protection( ); properties_protection.init( ); |