Ctrl K
ComunidadGuías…

tine20/Calendar/js/EventContextAttendeesItem.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/*
 * Tine 2.0
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2015 Metaways Infosystems GmbH (http://www.metaways.de)
 */


Tine.Calendar.EventContextAttendeesItem = Ext.extend(Ext.menu.Item, {
    event: null,
    datetime: null,

    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('Calendar');

        this.text = this.app.i18n._('Attendee/Resources')

        this.hidden = this.app.getMainScreen().getCenterPanel().isActiveView('Grid') || ! (
            this.event
            && this.event.get('editGrant')
            && Tine.Tinebase.appMgr.get('Calendar').featureEnabled('featureExtendedEventContextActions')
        );

        this.menu = [];
        this.view = this.app.getMainScreen().getCenterPanel().getCalendarPanel(this.app.getMainScreen().getCenterPanel().activeView).getView();

        var attendeeFilter = Ext.state.Manager.get('calendar-attendee-filter-grid'),
            explicitAttendee = attendeeFilter && Ext.isArray(attendeeFilter.explicitAttendee) ? attendeeFilter.explicitAttendee : [],
            currentAttendee = Tine.Calendar.Model.Attender.getAttendeeStore(this.event ? this.event.get('attendee') : []);

        currentAttendee.each(function(r) {
            this.menu.push(Object.assign({
                record: r,
                checked: true,
                handleClick: this.handleClick
            }, this.renderAttender(r)));
        }, this);

        Ext.each(explicitAttendee, function(attendeeData) {
            // memberOf is a filter only type and can't be an event attendee
            if (attendeeData.user_type === 'memberOf') return;

            var r = new Tine.Calendar.Model.Attender(attendeeData, 'new-' + Ext.id()),
                isCurrent = Tine.Calendar.Model.Attender.getAttendeeStore.getAttenderRecord(currentAttendee, r);

            if (! isCurrent) {
                this.menu.push(Object.assign({
                    record: r,
                    checked: false,
                    handleClick: this.handleClick
                }, this.renderAttender(r)));
            }
        }, this);

        var other = new Ext.Action({
            text: this.app.i18n._('Additional Attendees...'),
            handler: this.onOtherClick,
            scope: this
        });
        this.menu.push(other);

        Tine.Calendar.EventContextAttendeesItem.superclass.initComponent.call(this);

        this.menu.on('hide', this.onMenuHide, this);

        // NOTE: the submenu is rendered lazily on hover - async names (HTMLProxy) would never be replaced in the DOM
        this.menu.items.each(function(item) {
            if (item.namePromise) {
                item.namePromise.then((name) => {
                    if (!item.isDestroyed) {
                        item.setText(item.typeHtml + Ext.util.Format.htmlEncode(name));
                    }
                });
            }
        }, this);
    },

    /**
     * returns menu item config (text) for given attender
     * attendee names might be rendered async (e.g. contact title templates). In this case the name gets
     * resolved and set later, see initComponent
     *
     * @param {Tine.Calendar.Model.Attender} attender
     * @return {Object} {text, typeHtml, namePromise}
     */
    renderAttender: function(attender) {
        const proto = Tine.Calendar.AttendeeGridPanel.prototype;
        const iconStyle = 'display: inline-block; vertical-align: middle; width: 16px; height: 16px; margin: 0 5px 0 0;';

        // resources: use the specific resource type icon instead of the generic type icon + icon in name
        const resourceIcon = attender.get('user_type') === 'resource' ?
            proto.renderAttenderResourceIcon.call(proto, attender.get('user_id')) : '';

        const name = proto.renderAttenderName.call(proto, attender.get('user_id'), resourceIcon ? {noIcon: true} : false, attender);
        // NOTE: String.prototype has asString too - plain strings are already html
        const isAsync = !!name?.isHTMLProxy;
        const typeHtml = resourceIcon ? resourceIcon.replace('<img', `<img style="${iconStyle}"`) :
            proto.renderAttenderType.call(proto, attender.get('user_type'), {}, attender)
                .replace('<div', `<div style="${iconStyle} background-position: 0px;"`);

        return {
            typeHtml: typeHtml,
            namePromise: isAsync ? name.asString() : null,
            text: typeHtml + (isAsync ? '&#160;' : (name || ''))
        };
    },

    /**
     * prevent menu hide
     */
    handleClick: function(e) {
        if(this.setChecked && !this.disabled && !(this.checked && this.group)){// disable unselect on radio item
            this.setChecked(!this.checked);
            this.parentMenu.dirty = true;
        }
        e.stopEvent();
    },

    /**
     * show extra window & prevent autosave
     */
    onOtherClick: function() {
        this.menu.un('hide', this.onMenuHide, this);

        var data = [],
            fakeRecord = this.event.copy();

        Ext.each(this.getSelectedRecords(), function(r) {
            data.push(r.data)
        }, this);
        fakeRecord.set('attendee', '');
        fakeRecord.set('attendee', data);

        this.attendeeGridPanel = new Tine.Calendar.AttendeeGridPanel({
            header: false,
            border: false
        });
        this.attendeeGridPanel.onRecordLoad(fakeRecord);

        var win = Tine.WindowFactory.getWindow({
            layout: 'fit',
            width: 500,
            height: 300,
            modal: true,
            title: this.app.i18n._('Attendee'),
            items: [{
                xtype: 'form',
                buttonAlign: 'right',
                border: false,
                layout: 'fit',
                items: this.attendeeGridPanel,
                buttons: [{
                    text: i18n._('Cancel'),
                    minWidth: 70,
                    scope: this,
                    handler: function (btn) {win.close()},
                    iconCls: 'action_cancel'
                }, {
                    text: i18n._('Ok'),
                    minWidth: 70,
                    scope: this,
                    handler: function(btn) {
                        this.attendeeGridPanel.onRecordUpdate(this.event);
                        this.view.editing = this.event;
                        this.app.getMainScreen().getCenterPanel().onUpdateEvent(this.event, false, 'update');
                        win.close();
                    },
                    variant: 'primary',
                    iconCls: 'action_saveAndClose'
                }]
            }]
        });

        win.show();
    },

    /**
     * autosave
     */
    onMenuHide: function() {
        if (this.updateRecord(this.getSelectedRecords())) {
            this.menu.un('hide', this.onMenuHide, this);
        }
    },

    updateRecord: function(selectedRecords) {
        var data = [];

        Ext.each(selectedRecords, function(r) {
            data.push(r.data)
        }, this);

        if (this.menu.dirty) {
            this.event.set('attendee', '');
            this.event.set('attendee', data);
            this.view.editing = this.event;
            this.app.getMainScreen().getCenterPanel().onUpdateEvent(this.event, false, 'update');
            this.ownerCt.destroy.defer(100, this.ownerCt);
            return true;
        }
    },

    getSelectedRecords: function() {
        var records = [];

        this.menu.items.each(function(item) {
            if (item.checked) {
                records.push(item.record);
            }
        }, this);

        return records;
    }
});

Ext.ux.ItemRegistry.registerItem('Calendar-MainScreenPanel-ContextMenu', Tine.Calendar.EventContextAttendeesItem, 140);