MANUAL
All the doumentation of this web site is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License
How to build a complete plugin for W3StudioCMS
In the previous tutorial we have seen how to build a content and the relative editor to manage it. In this tutorial you will learn how to make them work with ajax transactions.
Save the content in the database
During the creation of the content manager object the getInteractiveMenu() method has been defined.
This method is used to set the active editor to manage the content in the standard function that draws the interactive menu. The method was:
public function getInteractiveMenu()
{
$editor = sprintf('activeEditor = new maskedGalleryEditor(%s, %s);', $this->content->getId(), $this->getContentMapping()->getSlotId());
return sprintf($this->defaultInteractiveMenu, $this->content->getId(), $this->getContentMapping()->getSlotId(), $editor);
}
This function instantiates a new object, called maskedGalleryEditor, at client-side level. Now we are going to implement it.
Create a folder called web under the plugin's folder then create a directory inside it and call this one js. Inside this new folder create a file called w3s_masked_gallery.js, open it and insert this code:
var maskedGalleryEditor = Class.create(w3sEditor, {
edit: function()
{
W3sContent.editContent($('w3s_masked_gallery_form').serialize());
return false;
}
});
This code creates an object which inherits from the w3sEditor object.
The edit method overrides the same method defined in the parent object and calls the W3sContent.editContent() function which is deputated to save the content passed as parameter in the database. In this case the content is:
$('w3s_masked_gallery_form').serialize()
the serialization of our form, we just created in previous tutorial.
Add some styles for a better look
At this moment the form has not a great look, so we will add some styles into a stylesheet file to format it.
Under the web folder you have just created, add a new directory and call it css, then create a new file and call it w3s_masked_gallery.css. Inside this file add this code:
#w3s_masked_gallery_container
{
border:1px solid #666;
background-color: #fff;
padding: 4px;
}
#w3s_masked_gallery_container input
{
border:1px solid #666;
background-color: #fff;
}
#w3s_masked_gallery_container select
{
border:1px solid #666;
background-color: #EEE;
}
#w3s_masked_gallery_container .button
{
border:1px solid #666;
background-color: #CCC;
}
As it works for the plugin's javascripts the stylesheets are automatically loaded by W3StudioCMS when the editor is opened.
Images upload
The last thing to is to configure the uploader tool that comes with W3StudioCMS, so we can be able to upload the images, for the masks, loaders and controls.
The uploader tool has to be configured in the app.yml file as follows:
all:
.settings:
w3s_uploader_dirs:
gallery-images:
folder : ''
fileDesc : 'Image files'
fileExt : '*.gif;*.jpg;*.jpeg;*.png;'
To setup a new uploader you have to define a param called w3s_uploader_dirs which will contain all the parames required by the uploader tool.
gallery-images is the uploader's name which is used to retrieve the parameters for the uploader and under it there are defined all the paramaters accepted by this tool.
Here are defined some parameters which are quite clear. The folder param is always required but in this case its value is an empty string because the value will be defined at runtime.
In the previous tutorial we created a toolbar to upload the images. If you examine one of those calls, you will note that a path is passed to the javascipt object when it is initialized. That's the reason why the folder param contains a blank string.
Keep a look to the toolbar, you will see that in the action param it is referenced a javascript object called w3sFileUploaderGallery, which we are going to create now.
Under the js folder of the plugin's web directory, create a new file and call it w3s_files_uploader_gallery.js. Open it and paste the following code:
var w3sFileUploaderGallery = Class.create({
initialize: function(path)
{
if (path == undefined) path = '';
this.path = path.replace(/\//g, '\\');
},
});
Now the w3sFileUploaderGallery has been defined. Its initialization function accepts a path as param, we passed for all the buttons when the toolbar has been defined.
To let this path working, it is necessary to replace each / char with the \ otherwise it cannot be processed by symfony.
this.path is a private variable which can be accessed by the methods of the class. Each button calls the method show: here is the code that defines it:
show: function(type, controlName)
{
var sType = (type) ? type : 'gallery-images';
var sActionPath = w3studioCMS.frontController + 'w3sUploadify/show';
if (this.path != '') sActionPath += '/addToPath/' + this.path;
var sAjaxOptions = {asynchronous:true,
evalScripts:false,
method:'get',
parameters:'type=' + sType};
var cWindow = new Window({
className: "alphacube",
title:'W3StudioCMS',
width: 402,
height: 340,
closable:true,
resizable:false,
minimizable:false,
maximizable:false,
draggable:true,
showEffect:Element.show,
destroyOnClose:true,
onClose:function(){if(sType != 'gallery-images'){activeEditor.refresh(controlName, sType);}},
zIndex:3100});
cWindow.showCenter();
cWindow.setAjaxContent(sActionPath, sAjaxOptions);
return false;
}
This method uses a javascript window object which is based on prototype framework.
The code is pretty clear: the parameter type defines which is the type of image that has to be uploaded, so gallery-images is the default value and it is referred to the images displayed by the gallery.
The controlName param is the form's select which will be updated when a new image is loaded while the sActionPath defines the action used by the ajax transaction.
sAjaxOptions defines the parameters for the ajax transaction and cWindow is the window that will be created.
The instruction
cWindow.setAjaxContent(sActionPath, sAjaxOptions);
is deputated to create and display the response code inside the window. In the window initialization construct, please note that there is a function defined for the event onClose.
onClose:function(){if(sType != 'gallery-images'){activeEditor.refresh(controlName, sType);}},
This is the call to the method which will refresh the control which gets the image when the window is closed. Any action is taken when the user will upload an image the gallery must display because there is nothing to update on the form.
This method has to be defined in the activeEditor object, that represents the current opened editor, which is maskedGalleryEditor.
Open the w3s_masked_gallery.js file and replace the inserted code with the following one:
edit: function()
{
W3sContent.editContent($('w3s_masked_gallery_form').serialize());
return false;
},
refresh: function(controlName, type)
{
var sActionPath = w3studioCMS.frontController + 'w3sMaskedGallery/refresh';
new Ajax.Request(sActionPath,
{asynchronous:true,
evalScripts:false,
onComplete:function(request, json)
{
if(json)
{
if (json[0] != 'galleryControls')
{
W3sTools.updateCombobox(json[0], json[1]);
}
else
{
W3sTools.updateCombobox('nextPath', json[1]);
W3sTools.updateCombobox('prevPath', json[1]);
}
}
},
parameters:'controlName=' + controlName +
'&type=' + type
});
}
The refresh method defines and ajax call that points to the w3sMaskedGallery symfony's module and executes the refresh action. When the ajax transaction is completed the control on the form is updated using the W3sTools.updateCombobox() method.
The module
We need a module to manage this ajax transaction, so add a new module called w3sMaskedGallery then create a new lib directory under that folder. Inside this new directory create a new file and call it BaseW3sMaskedGalleryActions.class.php.
This is the base class for the modules' actions. Open it and add this code:
class BaseW3sMaskedGalleryActions extends sfActions
{
public function executeRefresh($request)
{
}
}
To the refresh method add the following code:
switch($request->getParameter('type'))
{
case 'mask':
$path = sfConfig::get('sf_web_dir') . sfConfig::get('app_gallery_masks_images_dir');
break;
case 'loader':
$path = sfConfig::get('sf_web_dir') . sfConfig::get('app_gallery_loaders_images_dir');
break;
case 'controls':
$path = sfConfig::get('sf_web_dir') . sfConfig::get('app_gallery_controls_images_dir');
break;
}
$uploaderDirs = sfConfig::get('app_w3s_uploader_dirs');
$allowedExtensions = $uploaderDirs[$request->getParameter('type')]['fileExt'];
$allowedExtensions = explode(';', $allowedExtensions);
$files = sfFinder::type('file')->maxdepth(0)->relative()->sort_by_name();
foreach($allowedExtensions as $allowedExtension)
{
$files = $files->name($allowedExtension);
}
$files = $files->in($path);
The switch defines the right path according tho the parameter type passed by the ajax transaction declared in the w3sFileUploaderGallery by the options 'parameters':
var sAjaxOptions = {asynchronous:true,
evalScripts:false,
method:'get',
parameters:'type=' + sType};
The following code will retrieve the allowed extensions for the current uploader:
$uploaderDirs = sfConfig::get('app_w3s_uploader_dirs');
$allowedExtensions = $uploaderDirs[$request->getParameter('type')]['fileExt'];
At last the files are retrieved using the sfFinder tool. The result files have to be returned as a json header to be processed by the ajax caller in the onComplete event. Add the following code under the one just inserted:
$this->getResponse()->setHttpHeader('X-JSON', sprintf('(["%s", "%s"])', $request->getParameter('controlName'), implode(';', $files)));
return sfView::HEADER_ONLY;
At last open the actions.class.php file and replace the existing code with this one to use the base classe just created:
require_once(dirname(__FILE__).'/../lib/BaseW3sMaskedGalleryActions.class.php');
class w3sMaskedGalleryActions extends BaseW3sMaskedGalleryActions
{
}
jQuery compatibility
W3StudioCMS has been developed using prototype as primary client-side javascript and this tool is a jQuery's plugins, so jQuery is required, but using jQuery with prototype causes some conflicts.
W3StudioCMS already implements all the required solutions to work with both the frameworks, but when a plugin uses jQuery, this has to be explicity declared to let W3StudioCMS loads all the static javascripts under all the scripts that uses prototype in the head section of the rendered page.
This is made by adding a parameter to the plugin's app.yml file: open it and add the following code:
w3s_jquery_plugins:
w3sExtensionMbMaskedGalleryPlugin: on
The plugin name has to be added to the w3s_jquery_plugins options with on as value.
To use your plugin, enable the w3sMaskedGallery module, then run the following commands from the cli:
php symfony plugin:publish-assets
php symfony cc
If you want to get the full code for this plugin, download it from the extension's download page.
That's all. Let me know if you find some mistakes writing and email to info [aT] w3studiocms [DoT] com.

