8. Bidding System

8.1. Bidding and insertion points

Insertion points, as described in Insertion Points, are perfect for extending WebApp in predefined places with a small additions. Next to this, another way of extending functionality is to override existing user interface components. The way WebApp decides which user interface class to use when presenting some kind of data is called the “bidding system”: WebApp allows all components to bid on functionality. The way this works, roughly, is that WebApp will ask all registered plugins to place bids on something, and the highest bidder is chosen to deliver the functionality.

The shared component system is not meant to be used for each and every button, but for components of some magnitude. This is due to the time it takes to ask each component to place a bid, so for items that need to be shown often and quickly, the system is too slow. Therefore, if we would use the shared component system for these smaller components as well, it will have a negative effect on the performance. Dialogs and preview panels are examples of components that are suitable for the bidding system: it takes a lot of time to initialize them anyway, so the bidding rounds don’t have a noticeable negative impact there. For smaller components, a more suitable approach is to use an insertion point: these are easily iterated over in rapid succession.

8.2. Working

The shared component bidding system is a mechanism to prevent tight coupling between plugins and allowing plugins to override existing dialogs. A plugin that requires a component like a dialog, context menu or a preview panel can ask the container to get it a specific type of the shared component. The container will start a bidding round across all the registered plugins, and each plugin will be able to bid and the highest bidder is asked to deliver this component. The system makes it possible to implement a dialog for reading mail by a mail context and the dialog for showing an appointment or a meeting request by the calendar context.

Shared Component bidding sequence

Shared Component bidding sequence

8.3. Bidding on a shared component

When the shared component is requested, a component type is also supplied. This can be used to bid more detailed based on the component type. The various component types are defined as valuess in the enumeration Zarafa.core.data.SharedComponentType. Other types can be added using the addProperty method of the enumeration. Next to the type of the component, a record can also be added as an argument.

The following snippet of code shows how to use the Shared Component mechanism:

var componentType = Zarafa.core.data.SharedComponentType[componentType];

var dialog = container.getSharedComponent(componentType, record);
if (dialog) {
        config.record = record;
        dialog.create(config);
}

The plugins that take part in the bidding round for the component can then base their bid on the data within the record. For example, the mail context can bid differently for records that have the object_type set to MAPI_MESSAGE and a message_class of IPM.Note, than for the records with a message_class of IPM.Appointment. On the other hand, the calendar context would bid higher for the latter one.

The hierarchy context would look for records that contain an object_type set to MAPI_FOLDER to do its bidding.

8.4. Example

The following snippet of code shows how the plugin can participate in the bidding round.

/**
 * Bid for the type of shared component
 * and the given record.
 * This will bid on a common.dialog.create or common.dialog.view for a
 * record with a message class set to IPM or IPM.Note.
 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context
 * can bid for.
 * @param {Ext.data.Record} record Optionally passed record.
 * @return {Number} The bid for the shared component
 */
bidSharedComponent : function(type, record)
{
        var bid = -1;
        if (Ext.isArray(record)) {
                record = record[0];
        }
        if (record && record.store || record instanceof Zarafa.addressbook.AddressBookRecord) {
                switch (type)
                {
                        case Zarafa.core.data.SharedComponentType['common.create']:
                        case Zarafa.core.data.SharedComponentType['common.view']:
                        case Zarafa.core.data.SharedComponentType['common.contextmenu']:
                                if (record.store.customObjectType==Zarafa.core.data.RecordCustomObjectType.ZARAFA_SPREED_PARTICIPANT)
                                    //|| record instanceof Zarafa.addressbook.AddressBookRecord)
                                {
                                        bid = 2;
                                }
                                break;
                        case Zarafa.core.data.SharedComponentType['common.dialog.attachments']:
                                if(record instanceof Zarafa.plugins.spreed.data.SpreedRecord) {
                                        bid = 2;
                                }
                                break;
                }
        }
        return bid;
},

When the plugin is the highest bidder the function getSharedComponent will be called to actually deliver the class to be constructed as component.

/**
 * Will return the reference to the shared component.
 * Based on the type of component requested a component is returned.
 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context
 * can bid for.
 * @param {Ext.data.Record} record Optionally passed record.
 * @return {Ext.Component} Component
 */
getSharedComponent : function(type, record)
{
        var component;
        switch (type)
        {
                case Zarafa.core.data.SharedComponentType['common.create']:
                case Zarafa.core.data.SharedComponentType['common.view']:
                        component = Zarafa.plugins.spreed.dialogs.EditSpreedParticipantDialog;
                break;
                case Zarafa.core.data.SharedComponentType['common.contextmenu']:
                        component = Zarafa.plugins.spreed.dialogs.SpreedParticipantContextMenu;
                break;
                case Zarafa.core.data.SharedComponentType['common.dialog.attachments']:
                        component = Zarafa.plugins.spreed.dialogs.AttachmentsDialog;
                break;
        }
        return component;
}