One of my primary postulates towards the new MCE Online Editor is that it supports different button sets, depending on explicit call or preset settings. Actually, presets would stand a much better approach, so let's forget about template declaration for a while. I decided to find out how much work it would require to make the preset approach run.
First of all, we have to store the settings we will be using later on. Current button declaration in ezoe.ini looks as follows:
[EditorSettings]
Buttons[]
Buttons[]=formatselect
Buttons[]=bold
Buttons[]=italic
Buttons[]=underline
...
We would need multi-dimentional array with multiple preset-like named blocks instead:
[EditorSettings]
ButtonPresets[]
ButtonPresets[]=full
ButtonPresets[]=mini
#...
[ButtonPreset-full]
Buttons[]
Buttons[]=formatselect
Buttons[]=bold
Buttons[]=italic
Buttons[]=underline
Buttons[]=|
Buttons[]=bullist
Buttons[]=numlist
Buttons[]=indent
Buttons[]=outdent
Buttons[]=|
Buttons[]=undo
Buttons[]=redo
#...
[ButtonPreset-mini]
Buttons[]
Buttons[]=formatselect
Buttons[]=bold
Buttons[]=italic
Buttons[]=underline
Buttons[]=|
Buttons[]=bullist
Buttons[]=numlist
Buttons[]=indent
Buttons[]=outdent
Once we're done with our preset configuration, we have to make the XML Block datatype actually display and store the preset values. First of all, we need to modify the datatype itself (kernel/classes/datatypes/ezxmltext/ezxmltexttype.php):
// Class constants declaration
const BUTTONS_FIELD = 'data_text2';
const BUTTONS_VARIABLE = '_ezxmltext_buttons_';
// Fetch and store post data - method modification
function fetchClassAttributeHTTPInput( $http, $base, $classAttribute )
{
$column = $base . self::COLS_VARIABLE . $classAttribute->attribute( 'id' );
$buttons = $base . self::BUTTONS_VARIABLE . $classAttribute->attribute( 'id' );
if ( $http->hasPostVariable( $column ) )
{
$columnValue = $http->postVariable( $column );
$classAttribute->setAttribute( self::COLS_FIELD, $columnValue );
$buttonsValue = $http->postVariable( $buttons );
$classAttribute->setAttribute( self::BUTTONS_FIELD, $buttonsValue );
return true;
}
return false;
}
The example above is not complete, there are other methods to modify, like initialization or (un)serialization ones. This should be enough to run the test, though.
We still have to modify the datatype templates. Again, we'll do the minimum: modify the datatype's class attribute template (design/standard/templates/class/datatype/edit/ezxmltext.tpl) by adding the following code:
<div class="block">
<label>{'Button preset'|i18n( 'design/standard/class/datatype' )}:</label>
<select name="ContentClass_ezxmltext_buttons_{$class_attribute.id}">
{def $preset_list=ezini( 'EditorSettings', 'ButtonPresets', 'ezoe.ini' )}
{foreach $preset_list as $preset}
<option value="{$preset|wash()}"{if eq( $preset, $class_attribute.data_text2 )} selected="selected"{/if}>{$preset|wash()}</option>
{/foreach}
</select>
</div>
Now, all pieces are in their place for the final cuts.
First of all, we have to modify the method responsible for collecting the button settings from the configuration files. We locate the eZOEXMLInput handler class and extend the proper method:
function getEditorButtonList()
{
if ( $this->editorButtonList === null )
{
$contentClassAttributeID = $this->ContentObjectAttribute->ContentClassAttributeID;
$contentClassAttribute = eZContentClassAttribute::fetch( $contentClassAttributeID );
$buttonPreset = $contentClassAttribute->DataText2;
$oeini = eZINI::instance( 'ezoe.ini' );
$buttonPresets = $oeini->variable( 'EditorSettings', 'ButtonPresets' );
if( !in_array( $buttonPreset, $buttonPresets ) )
{
$buttonPreset = $buttonPresets[0];
}
$buttonList = $oeini->variable( 'ButtonPreset-' . $buttonPreset , 'Buttons' );
$contentini = eZINI::instance( 'content.ini' );
$tags = $contentini->variable('CustomTagSettings', 'AvailableCustomTags' );
$hideButtons = array();
$showButtons = array();
// filter out underline if custom underline tag is not enabled
if ( !in_array('underline', $tags ) )
$hideButtons[] = 'underline';
// filter out pagebreak if custom pagebreak tag is not enabled
if ( !in_array('pagebreak', $tags ) )
$hideButtons[] = 'pagebreak';
// filter out relations buttons if user dosn't have access to relations
if ( !eZOEXMLInput::currentUserHasAccess( 'relations' ) )
{
$hideButtons[] = 'image';
$hideButtons[] = 'objects';
}
foreach( $buttonList as $button )
{
if ( !in_array( $button, $hideButtons ) )
$showButtons[] = $button;
}
$this->editorButtonList = $showButtons;
}
return $this->editorButtonList;
}
All this modification does is choose a proper button preset instead of a general one. It could be more warning-secured, this is the minimum.
This seems to be all, but it is not. The main MCE init template uses run-once operator to make sure that OE init is only run once. This is going to be a problem since OE button configuration is part of the init. We have to remove the run-once operator and allow multiple initializations. Now, I'm not sure at the moment if this is JavaScript-safe, but seems to work fine at first glance. Edit ezxmltext_ezoe.tpl template file and comment out run-once operators:
{*run-once*}
...
{*/run-once*}
This should be it.
As this example shows, a number of kernel-located files have to be modified in order to achieve this functionality. This takes just a couple of minutes once you know what you're doing, but kernel modification won't likely be accepted for premium support, for example. This is why I really hope this modification makes it to the eZ Publish 4.1.0 release, with some 4.0.x backward compatibility mode.
Also, note that this is hardly a substitute for server-side validation of what user is allowed to do within the OE (which ideally should automatically control what a user can do and I hope for that in eZ 4.2+), but stands a great transitional presentation-layer functionality that can be backed up with proper access control. Many projects will suffer if this is not in place...
Comments
It's getting implemented ;)
JavaScript