-----------------------------------------------------------------------------------
---------------- How to develop a primitive editor filter in AXEL  ----------------
-----------------------------------------------------------------------------------

Stéphane Sire
Last update: June 22nd, 2010  

Summary
=======
Primitive editor filters
========================

Primitive editor filters are objects that can be "applied" on a primitive editor to replace some of its methods with new methods implemented by the filter. 

Filters are declared on the "filter" parameter of the xt:use element.

For example  applies the filter wiki and then the filter capitalize on the 'text' primitive editor.

The declaration order of the filter element imports as the methods will be redefined from left to right. Hence if both wiki and capitalize filters redefine the "load" method, with the declaration above the "load" method of the capitalize filter will be called.        

The choice of which methods to filter depends on the desired effects. Basically the filter can belong to one of the following categories:

- category A : filters with no side effect on the edited content, such filters will generally look for some specific data inside the content model and forward it to other components; such filters may build and maintain a toc, generate collaboration events outside of the application, etc.; see 'service' filter in servicefilter.js

- category B : some filters that change the user text entry but not the handle nor the target content model, such filters may do some small typographical corrections such as capitalizing some words, expanding some abbreviations, proposing some contextual input aids while typing, etc.; we do not have currently any example

- category C : some filters that change the handle and/or the target content model; such filter can improve the presentation of the edited content (e.g. displaying a video player if the input is a video URL), they can also allow to edit sub-content model using special rules to interpret the input (e.g. the 'wiki' filter in 'wiki.js') 

The "howto-plugins" document lists the methods that delegate filters can override. 
Creating delegation method call chains
======================================

It is the responsability of a filter to call the previous filter method (or ultimately the original model method if it is the first in the list). For that purpose, the filter must rename the method it filters to a new name that it can invoke with the "this" object (without remapping method names there would be an infinite loop). It can rename methods by creating a '->' hash object of key-value pairs where the method of the chained object with name "key" will be called in the filter with the new name "value".

Hence if a filter 'wiki' object has the following property: 

 '->': {	'load': '_wikiSuperLoad' }
 
Then it can call the "load" method of its latest predecessor in the filter chain that implements it with "this._wikiSuperLoad(...)" in its own "load" method. You should follow the recommendation in the "coding-style.txt" document to properly name the remapped methods.                

There is no rule to determine where to call the predecessor's method, but you must pay lot of attention to potential side effects of different positions.                        

You must also be careful that some filters, usually the one that change the handle and/or the target content model, must break the delegation method call chains and not perpetuate the call to the overriden method. That is the case each time the extended functionalities are incompatible with the default behavior of the model object. Such filter must document it so that template authors now they cannot put filters before these filters in a filter chain.

This delegation pattern is inspired from Alex Russell's blog [1].
Scope of Filters
================

The filter delegate can redefine some methods of the model object it is applied to. It can also create new methods inside the filtered object. In terms of object-oriented programming a filtered model object is a mixin between the model class and the filter object.

The current implementation of filters supposes that each filter will be represented by a unique filter object shared at the application level. Hence if a filter needs to store state information at the model instance level it must either store this data either inside each model instance (which is usually one of the parameters of the delegate methods), or it must maintain it in some caches as each model is associated with a unique key identifier accessible with model.getUniqueKey().     

EXPLIQUER que le filter peut utiliser "this" et que c'est le "this" de l'objet auquel il a été appliqué 
Filter extension mechanism
==========================

Explain can / execute pattern 
Filter registration with primitive editor plugins 
=================================================

A filter can only be applied to a primitive editor if the corresponding filter object has been registered on the editor plugin factory. This can be done at the end of the filter source file. The registration method can depend on the plugin, we recommend to define a registerFilter method with two parameters: the unique filter key and the filter object. 

For example the 'wiki' filter registers on the 'text' primitive editor factory with the following line:

xtiger.editor.Plugin.prototype.pluginEditors['text'].registerFilter('wiki', _WikiFilter);

Where _WikiFilter is the global object that defines the filter.

Primitive editor plugins are strongly encouraged to follow a consistant API which is documented in the "howto-plugins" document. The benefit is that if it is consistent enough, the same filter can be applied to several different primitive editor types. However there are some limitations as some plugins may be specific and require specific filters.

According to the specification above, there are most chance that Category A filters can be shared on many different primitive editors. This is the case for instance for the 'service' filter that implements part of the service functionalities described in 'howto-services.txt'. Category B may eventually be shared on all the primitive editor plugins that support a single text entry field. Category C are most probably specific to a given primitive editor plugin because they depend on the structure of its handle.      
Filter parameters
=================                

To be developped

using model.getParam() to define some filter parameters
              
Filter skeleton
===============

The following template can be used to write a new filter object. As you can see we suggest to avoid anonymous function and use meaningful identifiers even if they are not seen from outside the filter's closure, since it will facilitate debugging. 

var _myServiceFilter  = (function _myServiceFilter () {    

  /////////////////////////////////////////////////
  /////    Static myService Mixin Part     ////////
  /////////////////////////////////////////////////
  
  var _myFunc = function _myFunc (...) { 
    ...
  };

	return {  
	
    ///////////////////////////////////////////////////
    /////     Instance myService Mixin Part    ////////
    ///////////////////////////////////////////////////

		// Property remapping for chaining
		'->': {
		  'update': '__myServiceUpdate', 
      ...
		},
		                             
		/** example if you override update and chain it */
		update : function (...) {
		 this.__myServiceUpdate(...);
		 ...
		 _myFunc (...); // example calling a private static method
		 ...		  
		}  
		
		/** add any other method from the filtered object that you want to override */

		/** add any other method you want to add to the filtered object to be called with can() / execute() */
		 
  };
		
})();

// Do not forget to register your filter on any compatible primitive editor plugin
xtiger.editor.Plugin.prototype.pluginEditors['plugin_identifier'].registerFilter('filter_identifier', _myServiceFilter);  

As a consequence of the last line, template authors are then able to write:

<xt:use types="plugin_identifier" param="filter=filter_identifier" />
References
==========

[1] http://alex.dojotoolkit.org/2008/10/delegate-delegate-delegate/