Chapter 2: Approach 1 [Plugin override]
Note: for those of you who do not mind modifying your component, skip this section and go to Approach 2.
Here we are going to make the assumption that you are not the developer of the component and you want to add inline editing support, or you do not want to modify the code of your component.
In either case, we are going to have to utilize Joomla’s event based plugin system, namely content plugins, to get the job done.
In most cases, components will fire off the onPrepareContent and onAfterDisplayContent events, when they are displaying content for their item detail and category type views. However, if this is not the case in your component, you will need to skip this section and go to the next section below.
The inline editing framework provides an event listener handler, for those events for components wanting inline editing support, for their defined types.
In our MyCCK component, we fire off both the onPrepareContent and onAfterDisplayContent event, for our item view. And only the onPrepareContent, for the blog category view.
Okay first, we are going to create a directory structure as follows:
+files_inlinemycck [FILES_INLINE + COMPONENT NAME]
|
------+extensions
|
---mycck.php [COMPONENT NAME]
|
------+contexts
|
---+mycck [COMPONENT NAME]
|
-----category.php [TYPE NAME as explained in XML]
|
-----item.php [TYPE NAME as explained in XML]
|
-----blog.php [TYPE NAME as explained in XML]
|
index.html
|
inlinemyck.xml [INLINE + COMPONENT NAME].xml
Do not worry about the content you need to put into the files for now, that will be explained in detail later. For now, just create the folders and files for your component.
The only file we need to concern ourselves with in this section, is the mycck.php file.
In this file, we are going to add two methods:
- prepare.
- display.
The names of these methods match the names of the Joomla’s events: onPrepareContent and onAfterDisplayContent. And as you probably guessed, these methods will be called respectively, with their namesake Joomla events.
So to add these methods, we will create a class as follows:
class ARKExtensionsMyCCK extends ARKExtensionsBase
{
public function __construct($context, $item, $params)
{
//call parent construtor
parent::__construct($context, $item, $params);
//set allowable context array for inline editing
$this->inline_allowed_contexts = array ('com_mycck.item','com_mycck.category');
}
public function prepare()
{
}
}
ARKExtensionsMyCCK extends the ARKExtensionsBase class because it does a lot of things for us behind the scenes that we want.
You notice that we added a constructor. This is required to set things up; we may have specific things to do for our component, and we have to define the inline allowed_contexts array.
The constructor takes three parameters: the context, current item, and the parameters for the current item.
The context we are talking about here, is the context in which the content plugin event was fired, in your component. So, in other words, it comes down to what view the content plugin event was fired. Or in the case of a CCK, in what type/element this event was fired when rendering that type. This parameter context, is, in fact, a requirement by Joomla for most content plugin events. Joomla needs to know where or when the plugin event was fired.
In our case for the MyCCK component, we have two contexts, in which our events are fired: one when we are rendering our types for the category view and the other when we are, for the main, item type.
So we added the line in the constructor:
$this->inline_allowed_contexts = array('com_mycck.item','com_mycck.category');
That is it really; apart from calling the parent constructor.
Next we will look at the code we will add, to the prepare method, for our MyCCK component:
public function prepare()
{
//Are we allowed to edit in this context
if($this->context != 'com_content.category') //override base check as we only fire this for category description
{
return false;
}
if(isset($this->item->introtext)) //Ensure this is only fired off for a category
return false;
//Set Data Item Type
$this->type = 'category';
//Permisson Check
if(!isset($this->id))
{
$id = $this->app->input->get('id',0);
$this->id = $id ? $id : 0;
}
//Set Asset number
$asset = 'com_content.category.' . $this->id;
$table = JTable::getInstance('category',’MyCCK’);
$table->load($this->id);
$createdBy = $table->created_user_id;
$user = JFactory::getUser();
//can user edit item if not then bail
if (!($user->authorise('core.edit', $asset) || ($user->authorise('core.edit.own', $asset) && $user->id == $createdBy)) )
{
return false;
}
//need to override base class here for following check for categories
/*filter article to see if it is being used to load a module if so skip it
[widgetkit]
{loadmodule}
{loadposition}
{module}
{modulepos}
{modulepos}
{component}
{article(s)}
*/
$text = $table->description;
$test = preg_match('/\{(?:loadmodule|loadposition|module|modulepos|component|articles?)\s+(.*?)\}/i',$text);
if(!$test)
$test = preg_match('/\[widgetkit\s+(.*?)\]/i',$text);
if($test)
{
return;
}
return parent::prepare();
}
The first thing we do in the prepare method is that we do a check to ensure we only create an editable region for our type if we are in the category view. In our MyCCK component, this is sufficient enough and should be in yours. If, however, the item object you pass into this event also has some type ID, of sorts, please feel free to use that as well.
if($this->context != 'com_mycck.category') //override base check as we only fire this for category description
{
return false;
}
In the next line, we wanted to ensure in our component, that we only process the category type and not the blog item type, so that it is only dealt with in the display event. In our case, the context is the same for both the category and the category blog item types, so this extra check is needed.
if(isset($this->item->introtext)) //Ensure this is only fired off for a category
return false;
After this, we check permissions using Joomla’s Assets system, to check if the user has permission to do inline editing, for our categories:
$user = JFactory::getUser();
//can user edit item if not then bail
if (!($user->authorise('core.edit', $asset) || ($user->authorise('core.edit.own', $asset) && $user->id == $createdBy)) )
{
return false;
}
Now let us add the display method:
public function display()
{
//If this item already proccessed
if(isset($this->item->proccessedInline) && $this->item->proccessedInline)
return false;
//Are we allowed to edit in this context
//override base check if needed
//Set Data Item Type
$this->type = str_replace($this->app->input->get('option').'.','',$this->context);
if($this->type == "category" ) //we are in blog view so set type to blog
{
$this->type = 'blog';
}
//Permisson Check
//Set Asset number
$asset = 'com_content.item.'.$this->id;
$createdBy = $this->item->created_by;
$user = JFactory::getUser();
//can user edit item if not then bail
if (!($user->authorise('core.edit', $asset) || ($user->authorise('core.edit.own', $asset) && $user->id == $createdBy)) )
{
return false;
}
}
The first thing, we see in this function is a check to see if the ‘processedInline’ flag on the item object has been set to true. This will be the case if the item that is currently being processed has, in fact, been already processed in the prepare function, above.
Okay, now, as below, we set the Data Item type so that the rest of the system knows what type it is dealing with.
//Set Data Item Type
$this->type = str_replace($this->app->input->get('option').'.','',$this->context);
Now, we check if the type is an item type, or, in fact, a category blog type:
if($this->type == "category" || $this->type == "featured") //we are in blog view so set type to blog
{
$this->type = 'blog';
$update_introtext = true;
}
Next, we do a permission check, to see if the current user is allowed to do inline editing.
This should all be pretty standard stuff by now:
//Permission Check
//Set Asset number
$asset = 'com_content.item.'.$this->id;
$createdBy = $this->item->created_by;
$user = JFactory::getUser();
//can user edit item if not then bail
if (!($user->authorise('core.edit', $asset) || ($user->authorise('core.edit.own', $asset) && $user->id == $createdBy)) )
{
return false;
}