Ext.namespace('Zarafa.common.rules.dialogs'); /** * @class Zarafa.common.rules.dialogs.UserSelectionLink * @extends Ext.BoxComponent * @xtype zarafa.userselectionlink */ Zarafa.common.rules.dialogs.UserSelectionLink = Ext.extend(Ext.BoxComponent, { /** * @cfg {String} fieldLabel The label which must be applied to template * as a prefix to the list of attachments. */ emptyText :_('Select one...'), /** * @cfg {String} userStringSeparator The separator which is used to separate list * of user while displaying them as string. */ userStringSeparator : _('and'), /** * @cfg {Zarafa.core.data.IPMRecipientStore} store The store in which * the recipients are stored */ store : undefined, /** * The Action type which is handled by this view * This is set during {@link #setAction}. * @property * @type Zarafa.common.rules.data.ActionFlags */ actionFlag : undefined, /** * The action property which was configured during * {@link #setAction}. * @property * @type Object */ action : undefined, /** * The Condition type which is handled by this view * This is set during {@link #setCondition}. * @property * @type Zarafa.common.rules.data.ConditionFlags */ conditionFlag : undefined, /** * The condition property which was configured during * {@link #setCondition}. * @property * @type Object */ condition : undefined, /** * True if the action/condition was modified by the user, if this is false, * then {@link #getCondition} will return {@link #condition} instead * of returning a new object and {@link #getAction} will return {@link #action} * instead of returning a new Object. * @property * @type Boolean */ isModified : false, /** * True if the action/condition is complete and valid, * False will denote that action/condition is invalid or incomplete * if this is true, then {@link #getCondition} will return {@link #condition} instead * of returning a new object and {@link #getAction} will return {@link #action} * instead of returning a new Object. * @property * @type Boolean */ isValid : true, /** * @constructor * @param {Object} config configuration object. */ constructor : function(config) { config = config || {}; Ext.applyIf(config,{ xtype: 'zarafa.userselectionlink', border : false, autoScroll:true, anchor : '100%', multiSelect : false, store : new Zarafa.core.data.IPMRecipientStore(), tpl : new Ext.XTemplate( '<div class="zarafa-user-link">' + '<tpl for="list">' + '<tpl if="!Ext.isEmpty(values.display_name)">' + '"{display_name:htmlEncode}"' + '</tpl>' + '<tpl if="Ext.isEmpty(values.display_name) && !Ext.isEmpty(values.smtp_address)">' + '"{smtp_address:htmlEncode}"' + '</tpl>' + '<tpl if="xcount > 0 && xindex != xcount">' + '<span> {parent.seperator} </span>' + '</tpl>' + '</tpl>' + '</div>', { compiled : true } ) }); Zarafa.common.rules.dialogs.UserSelectionLink.superclass.constructor.call(this, config); }, /** * This function is called after the component has been rendered. * This will register the {@link #onActivate} and {@link #onClick} event handlers. * @private */ afterRender : function() { Zarafa.common.rules.dialogs.UserSelectionLink.superclass.initComponent.apply(this, arguments); this.mon(this.getActionEl(), 'click', this.onClick, this); this.mon(this.store, 'update', this.onRecipientUpdate, this); this.mon(this.store, 'add', this.onRecipientAdd, this); this.mon(this.store, 'resolved', this.onRecipientAdd, this); }, /** * Handler will be called when recipient in {@link Zarafa.core.data.IPMRecipientStore IPMRecipientStore}. * It could happen that recipient is updated after we have closed addressbook dialog (mainly in case of resolving) * so we need to update the ui also * @param {Zarafa.core.data.IPMRecipientStore} store The store which fired the event * @param {Zarafa.core.data.IPMRecipientRecord} record The record which was updated * @param {String} operation The update operation being performed. * @private */ onRecipientUpdate : function(store, records, operation) { if (operation !== Ext.data.Record.COMMIT) { // update ui, after store is updated this.update(this.store); } }, /** * Handler will be called when recipient is added to {@link Zarafa.core.data.IPMRecipientStore IPMRecipientStore}. * @param {Zarafa.core.data.IPMRecipientStore} store The store which fired the event * @param {Zarafa.core.data.IPMRecipientRecord} records The records which have been added * @private */ onRecipientAdd : function(store, records) { var record = records[0]; // Only force expanding the distlist when it's a local distlist. if (record.get('object_type') === Zarafa.core.mapi.ObjectType.MAPI_DISTLIST && record.get('address_type') === 'MAPIPDL') { Ext.MessageBox.show({ title: _('Kopano WebApp'), msg: _('Distribution lists are not supported in rules, would you like to replace the distribution list with its members?'), buttons: Ext.MessageBox.YESNO, fn: this.onExpandDistList.createDelegate(this, [record], 1), scope: this }); } }, /** * Handler for messagebox which asks the user to expand the distribution list of remove it. * @param {String} btn string containing either 'yes' or 'no * @param {Zarafa.core.data.IPMRecipientRecord} recip The records which should been expanded */ onExpandDistList: function(btn, recip) { if(btn === 'yes') { this.store.expand(recip, true); } this.store.remove(recip); }, /** * Called when user clicks on a {@link Zarafa.common.rules.dialogs.UserSelectionLink} * It opens user selection dialog dialog * @param {Ext.DataView} dataView Reference to this object * @param {Number} index The index of the target node * @param {HTMLElement} node The target node * @param {Ext.EventObject} evt The mouse event * @protected */ onClick : function(dataView, index, node, evt) { var hideGroups = []; if(this.conditionFlag === Zarafa.common.rules.data.ConditionFlags.RECEIVED_FROM) { hideGroups.push('distribution_list'); } var label; if (this.conditionFlag === Zarafa.common.rules.data.ConditionFlags.RECEIVED_FROM) { label = _('From'); } else { label = _('To'); } // Open addressbook dialog for selection of users Zarafa.common.Actions.openABUserMultiSelectionContent({ listRestriction : { hide_groups : hideGroups }, callback : function(record) { this.isModified = true; this.update(this.store); }, convert : function(r) { return r.convertToRecipient(); }, scope : this, store : this.store, modal : true, selectionCfg : [{ xtype : 'zarafa.recipientfield', fieldLabel : label + ':', height : 50, boxStore : this.store, flex : 1 }] }); }, /** * Apply an action onto the DataView, this will parse the condition and show * the contents in a user-friendly way to the user. * @param {Zarafa.common.rules.data.ConditionFlags} conditionFlag The condition type * which identifies the exact type of the condition. * @param {Object} condition The condition to apply */ setCondition : function(conditionFlag, condition) { this.store.removeAll(); this.isValid = false; if (condition) { var Restrictions = Zarafa.core.mapi.Restrictions; var subs; switch (conditionFlag) { case Zarafa.common.rules.data.ConditionFlags.SENT_TO: // Check if a RES_OR restriction was provided, if // so we need to loop over all recipients from the list. if (condition[0] === Restrictions.RES_OR) { subs = condition[1]; } else { subs = [ condition ]; } for (var i = 0, len = subs.length; i < len; i++) { var value = subs[i][1][Restrictions.RESTRICTION]; // Do not add empty recipient, it is possible that restriction might not have recipient. if(value[1] && value[1][Restrictions.PROPS] && value[1][Restrictions.PROPS]['0x0001001E']) { var recipient = this.store.parseRecipient(value[1][Restrictions.PROPS]['0x0001001E']); recipient.set('display_type', value[1][Restrictions.PROPS]['PR_DISPLAY_TYPE']); recipient.set('search_key', value[1][Restrictions.RESTRICTION][1][Restrictions.VALUE]['0x00010102']); this.store.add(recipient); this.isValid = true; } } break; case Zarafa.common.rules.data.ConditionFlags.RECEIVED_FROM: // Check if a RES_OR restriction was provided, if // so we need to loop over all recipients from the list. if (condition[0] === Restrictions.RES_OR) { subs = condition[1]; } else { subs = [ condition ]; } for (var i = 0, len = subs.length; i < len; i++) { var value = subs[i][1]; // Do not add empty recipient, it is possible that restriction might not have recipient. if(value[Restrictions.PROPS] && value[Restrictions.PROPS]['0x0001001E']) { var recipient = this.store.parseRecipient(value[Restrictions.PROPS]['0x0001001E']); recipient.set('display_type', value[Restrictions.PROPS]['PR_DISPLAY_TYPE']); recipient.set('search_key', value[Restrictions.RESTRICTION][1][Restrictions.VALUE]['0x00010102']); this.store.add(recipient); this.isValid = true; } } break; default: break; } } this.conditionFlag = conditionFlag; this.condition = condition; this.userStringSeparator = _('or'); this.isModified = !Ext.isDefined(condition); this.update(this.store); }, /** * Obtain the condition as configured by the user * @return {Object} The condition */ getCondition : function() { if (this.isModified !== true && this.isValid === true) { return this.condition; } var conditions = []; // No recipients selected, this means // we can't create a condition. if (this.store.getCount() === 0) { return false; } switch (this.conditionFlag) { case Zarafa.common.rules.data.ConditionFlags.SENT_TO: this.store.each(function(recipient) { if (recipient.isResolved()) { conditions.push(this.createToRestriction(recipient)); } }, this); break; case Zarafa.common.rules.data.ConditionFlags.RECEIVED_FROM: this.store.each(function(recipient) { if (recipient.isResolved()) { conditions.push(this.createFromRestriction(recipient)); } }, this); break; default: // invalid actionFlag return false; } // If there was only 1 recipient, we don't need to convert // it to a OR subrestriction. If we have more then 1 recipient, // then we should create the OR restriction. if (conditions.length === 1) { return conditions[0]; } else if (conditions.length > 1) { return Zarafa.core.data.RestrictionFactory.createResOr(conditions); } else { return false; } }, /** * Convert a {@link Zarafa.core.data.IPMRecipientRecord Recipient} into * a Restriction used for the {@link #getCondition}. * @param {Zarafa.core.data.IPMRecipientRecord} recipient The recipient for which * the restriction should be created * @return {Object} The restriction * @private */ createToRestriction : function(recipient) { var RestrictionFactory = Zarafa.core.data.RestrictionFactory; var Restrictions = Zarafa.core.mapi.Restrictions; return RestrictionFactory.createResSubRestriction('PR_MESSAGE_RECIPIENTS', RestrictionFactory.dataResComment( RestrictionFactory.dataResProperty('PR_SEARCH_KEY', Restrictions.RELOP_EQ, recipient.get('search_key'), '0x00010102'), { '0x60000003' : Zarafa.core.mapi.RecipientType.MAPI_TO, '0x00010102' : recipient.get('search_key'), '0x0001001E' : recipient.get('display_name') + ' <' + recipient.get('smtp_address') + '>', 'PR_DISPLAY_TYPE' : recipient.get('display_type') } ) ); }, /** * Convert a {@link Zarafa.core.data.IPMRecipientRecord Recipient} into * a Restriction used for the {@link #getCondition}. * @param {Zarafa.core.data.IPMRecipientRecord} recipient The recipient for which * the restriction should be created * @return {Object} The restriction * @private */ createFromRestriction : function(recipient) { var RestrictionFactory = Zarafa.core.data.RestrictionFactory; var Restrictions = Zarafa.core.mapi.Restrictions; return RestrictionFactory.dataResComment( RestrictionFactory.dataResProperty('PR_SENDER_SEARCH_KEY', Restrictions.RELOP_EQ, recipient.get('search_key'), '0x00010102'), { '0x60000003' : Zarafa.core.mapi.RecipientType.MAPI_TO, '0x00010102' : recipient.get('search_key'), '0x0001001E' : recipient.get('display_name') + ' <' + recipient.get('smtp_address') + '>', 'PR_DISPLAY_TYPE' : recipient.get('display_type') } ); }, /** * Apply an action onto the DataView, this will parse the action and show * the contents in a user-friendly way to the user. * @param {Zarafa.common.rules.data.ActionFlags} actionFlag The action type * which identifies the exact type of the action. * @param {Object} action The action to apply */ setAction : function(actionFlag, action) { this.store.removeAll(); this.isValid = false; if (action) { var RecordFactory = Zarafa.core.data.RecordFactory; var CustomObjectType = Zarafa.core.data.RecordCustomObjectType; for (var i = 0, len = action.adrlist.length; i < len; i++) { var address = action.adrlist[i]; this.isValid = true; var recipient = RecordFactory.createRecordObjectByCustomType(CustomObjectType.ZARAFA_RECIPIENT, { 'entryid' : address['PR_ENTRYID'], 'object_type' : address['PR_OBJECT_TYPE'], 'display_name' : address['PR_DISPLAY_NAME'], 'display_type' : address['PR_DISPLAY_TYPE'], 'email_address' : address['PR_EMAIL_ADDRESS'], 'smtp_address' : address['PR_SMTP_ADDRESS'], 'address_type' : address['PR_ADDRTYPE'], 'recipient_type' : address['PR_RECIPIENT_TYPE'], 'search_key' : address['PR_SEARCH_KEY'] }); this.store.add(recipient); } } this.actionFlag = actionFlag; this.action = action; this.userStringSeparator = _('and'); this.isModified = !Ext.isDefined(action); this.update(this.store); }, /** * Obtain the action as configured by the user * @return {Object} The action */ getAction : function() { if (this.isModified !== true && this.isValid === true) { return this.action; } var action = {}; // No recipients selected, this means // we can't create an action. if (this.store.getCount() === 0) { return false; } // Set the Address list in the action action.adrlist = []; this.store.each(function(recipient) { action.adrlist.push({ PR_ENTRYID : recipient.get('entryid'), PR_OBJECT_TYPE : recipient.get('object_type'), PR_DISPLAY_NAME : recipient.get('display_name'), PR_DISPLAY_TYPE : recipient.get('display_type'), PR_EMAIL_ADDRESS : recipient.get('email_address') || recipient.get('smtp_address'), PR_SMTP_ADDRESS : recipient.get('smtp_address'), PR_ADDRTYPE : recipient.get('address_type'), PR_RECIPIENT_TYPE : recipient.get('recipient_type'), PR_SEARCH_KEY : recipient.get('search_key') }); }, this); // Fill in the additional properties required for the action. var ActionFlags = Zarafa.common.rules.data.ActionFlags; var RuleActions = Zarafa.core.mapi.RuleActions; var FlavorFlags = Zarafa.core.mapi.FlavorFlags; switch (this.actionFlag) { case ActionFlags.REDIRECT: action.action = RuleActions.OP_FORWARD; action.flags = 0; action.flavor = FlavorFlags.FWD_PRESERVE_SENDER | FlavorFlags.FWD_DO_NOT_MUNGE_MSG; break; case ActionFlags.FORWARD: action.action = RuleActions.OP_FORWARD; action.flags = 0; action.flavor = 0; break; case ActionFlags.FORWARD_ATTACH: action.action = RuleActions.OP_FORWARD; action.flags = 0; action.flavor = FlavorFlags.FWD_AS_ATTACHMENT; break; default: // invalid actionFlag return false; } return action; }, /** * Update the contents of this dataview, this will apply the {@link #tpl} for * the {@link #store}. * @param {Zarafa.core.data.IPMRecipientStore} store The store to show */ update : function(store) { var data = { seperator : this.userStringSeparator, list : Ext.pluck(store.getRange(), 'data') }; if (Ext.isEmpty(data.list)) { data.list = [{ display_name : this.emptyText }]; } Zarafa.common.rules.dialogs.UserSelectionLink.superclass.update.call(this, this.tpl.apply(data)); } }); Ext.reg('zarafa.userselectionlink', Zarafa.common.rules.dialogs.UserSelectionLink);