Publishr is a project mainly written in ..., based on the View license.
A CMS for PHP5.2
The Widget API ##############
The Widget API that comes with the CMS Publishr provides features to create widgets on the server side, make them come to life on the client side, fetch widgets from remote locations and append them to the document while taking care of the required CSS and Javascript assets.
A widget is a reusable element of a graphical user interface that displays an information arrangement and provides standardized data manipulation. In web applications, widgets are usually composed of multiple HTML elements that come to life with the magic of Javascript.
The Widget API is an ensemble of techniques, guidelines and conventions, mostly from the WdCore framework (the RESTful API used to fetch widgets), the WdElements framework (used as the base class to create widgets, or compose them) and the MooTools framework.
We usualy turn HTML elements into widgets when the domready
event is fired, but because we often
load widgets after the event has been fired (e.g. pop adjust widgets), we need another event
that can be fired at various times during the lifetime of the document.
The custom event elementsready
is fired on the document object when new widgets are added
to the document, and they need to come to life. Because the event can be fired multiple times
during the lifetime of the document, one should use the store()
and retrieve()
methods to check
if an element has already been made a widget.
The elementsready
event is first fired when the domready
event is fired.
By matching the Javascript constructor to a CSS class, the Widget API is capable of turning HTML
elements into splendid widgets all by itself. When the elementsready
event is fired on the
document object, the Widget API traverses all the constructors defined in the Widget
variable,
and for each one of them map their name to a CSS class and create widgets for the matching
elements.
As an example, the Widget.AdjustNode
constructor is mapped to the ".widget-adjust-node" css
class, and all matching elements are turned into widgets using the constructor. Thus, all we need
to do for the magic to happen is to add widget constructors to the Widget
variable, which also
serves as a namespace:
Widget.AdjustNode = new Class({...});
Elements are usually loaded using a Request.Element
instance, which extends the Request.JSON
class to support the loading of single HTML elements. The class overrides the onSuccess
method
to create a DOM element from the result of the response and update the document with its assets.
Here are the modified arguments of the onSuccess
event:
element
(object) - The DOM element created from the HTML result of the remote request.response
(object) - The JSON decoded response to the request.text
(string) - The raw response to the request.Widgets are usually loaded using a Request.Widget
instance, which extends the Request.Element
and provides a simpler mean to load widgets:
function callback(el, response)
{
console.log('loaded element: %a, response: %a', el, response);
}
new Request.Widget('adjust-thumbnail', callback).get({ selected: 190 });
Widgets can also be requested using the "/api/widgets/:class
" API route. The route triggers an
operation that creates the requested widget and returns its HTML code along with its required CSS
and Javascript assets.
As an example, the "/api/widgets/adjust-thumbail
" route returns the HTML representation of an
instance of the WdAdjustThumbnailWidget
class, along with its assets.
Additional routes are available to return parts of the widget, its results set for example, or a popup version of the widget:
/api/widgets/adjust-thumbnail/results?selected=190&page=2&search=keywords
/api/widgets/adjust-thumbnail/popup?selected=190
Because we often load widgets after the document was created or rendered, the document needs to be
updated with the CSS and Javascript files required by the loaded widgets. The
Document.updateAssets()
method updates the document with the required CSS and Javascript
files. A callback function is called when the files have been loaded:
function assetsLoaded()
{
alert('Assets have been loaded !');
};
Document.updateAssets
(
{
css: [ '/public/widget.css' ],
js: [ '/public/widget.js' ]
},
assetsLoaded
);
A widget is usually an instance of the Widget
class. There are many classes available, most of
them come with a module and are often used to edit a data type of their module. As an example,
the PopImage widget is used to select an image from the "resources.images" module. One can create
such a widget with the following code:
$widget = new WdPopImageWidget
(
array
(
WdForm::T_LABEL => 'Illustration image',
'name' => 'imageid'
)
);
When the widget is created it adds its required assets to the global document object:
$document->css->add('public/pop-image.css');
$document->js->add('public/pop-image.js');
One can retrieve the assets using the get_assets()
method:
$assets = document->get_assets();
Widgets are often loaded through the RESTful API of the WdCore
framework. For example, the AdjustImage
widget:
var widget;
new Request.Widget
(
'adjust-image', function(el, response)
{
widget = el;
document.appendChild(el);
}
)
.get({selected: 190});
For adjust elements, the '/results' route can be used to update the widget results:
Request.Element
({
url: '/api/widgets/adjust-image/results',
onSuccess: function(el, response)
{
el.replaces(widget.getElement('.results'));
}
})
.get({selected: 190, page: 2, search: "core"})
On the server side, the widget type "adjust-image
" is translated to the PHP class name
WdAdjustImageWidget. If the widget HTML code is requested, the string version of the instance
is returned as the result of the operation. In addition to the result, the assets
property of
the response might contain the CSS and Javascript files that are required for the widget to
operate.