APIs

Show:
/**
 * BlockCollection block resides inside a scene or timeline and manages internal playback of scenes and resoucres
 * @class BlockCollection
 * @extends Block
 * @constructor
 * @param {string} i_placement location where objects resides which can be scene or timeline
 * @param {string} i_campaign_timeline_chanel_player_id required and set as block id when block is inserted onto timeline_channel
 * @return {Object} Block instance
 */
define(['jquery', 'backbone', 'Block', 'bootstrap-table-editable', 'bootstrap-table-sort-rows'], function ($, Backbone, Block, bootstraptableeditable, bootstraptablesortrows) {

        var BlockCollection = Block.extend({

            /**
             Constructor
             @method initialize
             **/
            constructor: function (options) {
                var self = this;
                self.m_blockType = 4100;
                _.extend(options, {blockType: self.m_blockType});
                Block.prototype.constructor.call(this, options);

                self.m_collectionTable = $(Elements.COLLECTION_TABLE);
                self.m_collectionEventTable = $(Elements.COLLECTION_EVENTS_TABLE);
                self.m_selectRowIndex = -1;
                self._initSubPanel(Elements.BLOCK_COLLECTION_COMMON_PROPERTIES);
                self._listenCollectionRowDragged();
                self._listenCollectionRowDropped();
                self._listenAddResource();
                self._listenAddEvent();
                self._listenRemoveEvent();
                self._listenRemoveResource();
                self._listenModeChange();
                self._listenCollectionRowChanged();
                self._listenCollectionRowEventChanged();


                self.m_blockProperty.collectionDatatableInit();

                /* can set global mode if we wish */
                //$.fn.editable.defaults.mode = 'inline';

                self.m_actions = {
                    firstPage: 'beginning',
                    nextPage: 'next',
                    prevPage: 'previous',
                    lastPage: 'last',
                    selectPage: 'selected'
                }
            },

            /**
             Listen to changes in volume control
             @method _listenVolumeChange
             **/
            _listenCollectionRowDragged: function () {
                var self = this;
                self.m_collectionRowDraggedHandler = function (e) {
                    if (!self.m_selected)
                        return;
                    self.m_selectRowIndex = e.edata;
                };
                BB.comBroker.listen(BB.EVENTS.COLLECTION_ROW_DRAG, self.m_collectionRowDraggedHandler);
            },

            /**
             Listen to when collection row was edited
             @method _listenCollectionRowChanged
             **/
            _listenCollectionRowChanged: function () {
                var self = this;
                self.m_collectionRowChangedHandler = function (e) {
                    if (!self.m_selected)
                        return;
                    var domPlayerData = self._getBlockPlayerData();
                    var rowIndex = e.edata.rowIndex;
                    var newName = e.edata.name;
                    var newDuration = parseInt(e.edata.duration);
                    if (_.isNaN(newDuration)) {
                        bootbox.alert($(Elements.MSG_BOOTBOX_ENTRY_IS_INVALID).text());
                        self._populateTableCollection(domPlayerData);
                        return;
                    }
                    var item = $(domPlayerData).find('Collection').children().get(rowIndex);
                    $(item).attr('page', newName).attr('duration', newDuration);
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableCollection(domPlayerData);
                    self._populateTableEvents();
                };
                BB.comBroker.listen(BB.EVENTS.COLLECTION_ROW_CHANGED, self.m_collectionRowChangedHandler);
            },

            /**
             Listen to when collection row was edited
             @method _listenCollectionRowEventChanged
             **/
            _listenCollectionRowEventChanged: function () {
                var self = this;
                self.m_collectionRowEventChangedHandler = function (e) {
                    if (!self.m_selected)
                        return;
                    var domPlayerData = self._getBlockPlayerData();
                    var rowIndex = e.edata.rowIndex;
                    var event = e.edata.event;
                    var action = e.edata.action;
                    var item = $(domPlayerData).find('EventCommands').children().get(rowIndex);
                    $(item).attr('from', event);
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableCollection(domPlayerData);
                };
                BB.comBroker.listen(BB.EVENTS.COLLECTION_EVENT_ROW_CHANGED, self.m_collectionRowEventChangedHandler);
            },

            /**
             Listen in Event Action dropdown selections
             @method _listenDropdownEvenActionSelection
             **/
            _listenDropdownEvenActionSelection: function () {
                var self = this;
                if (self.m_onDropDownEventActionHandler)
                    $(Elements.CLASS_COLLECTION_EVENT_ACTION).off('change', self.m_onDropDownEventActionHandler);
                self.m_onDropDownEventActionHandler = function (e) {
                    if (!self.m_selected)
                        return;
                    var selected = $("option:selected", this).val();
                    var actions = _.invert(self.m_actions);
                    var action = actions[selected];
                    var index = $(this).closest('[data-index]').attr('data-index');
                    var domPlayerData = self._getBlockPlayerData();
                    var target = $(domPlayerData).find('EventCommands').children().get(parseInt(index));
                    $(target).attr('command',action);
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableEvents();
                };
                $(Elements.CLASS_COLLECTION_EVENT_ACTION).on('change', self.m_onDropDownEventActionHandler);
            },

            /**
             Listen in Event Action go to dropdown selections
             @method _listenDropdownEvenActionGoToSelection
             **/
            _listenDropdownEvenActionGoToSelection: function () {
                var self = this;
                if (self.m_onDropDownEventActionGoToHandler)
                    $(Elements.CLASS_COLLECTION_EVENT_ACTION_GOTO).off('change', self.m_onDropDownEventActionGoToHandler);
                self.m_onDropDownEventActionGoToHandler = function (e) {
                    if (!self.m_selected)
                        return;
                    var selected = $("option:selected", this).val();
                    var index = $(this).closest('[data-index]').attr('data-index');
                    var domPlayerData = self._getBlockPlayerData();
                    var target = $(domPlayerData).find('EventCommands').children().get(parseInt(index));
                    $(target).find('Params').remove();
                    $(target).append('<Params><Page name="' + selected + '"/></Params>');
                    self._setBlockPlayerData(pepper.xmlToStringIEfix(domPlayerData), BB.CONSTS.NO_NOTIFICATION, true);
                    self._populateTableEvents();
                };
                $(Elements.CLASS_COLLECTION_EVENT_ACTION_GOTO).on('change', self.m_onDropDownEventActionGoToHandler);
            },


            /**
             Listen to changes in volume control
             @method _listenVolumeChange
             **/
            _listenCollectionRowDropped: function () {
                var self = this;
                self.m_collectionRowDroppedHandler = function (e) {
                    if (!self.m_selected)
                        return;
                    var droppedRowIndex = e.edata;
                    var domPlayerData = self._getBlockPlayerData();
                    var target = $(domPlayerData).find('Collection').children().get(parseInt(droppedRowIndex));
                    var source = $(domPlayerData).find('Collection').children().get(self.m_selectRowIndex);
                    droppedRowIndex > self.m_selectRowIndex ? $(target).after(source) : $(target).before(source);
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableCollection(domPlayerData);
                };
                BB.comBroker.listen(BB.EVENTS.COLLECTION_ROW_DROP, self.m_collectionRowDroppedHandler);
            },

            /**
             Load up property values in the common panel
             @method _populate
             @return none
             **/
            _populate: function () {
                var self = this;
                self._setCollectionBlockGlobalValidationOwner(self);
                var domPlayerData = self._getBlockPlayerData();
                var xSnippetCollection = $(domPlayerData).find('Collection');
                var mode = $(xSnippetCollection).attr('mode');
                self._populateTableCollection(domPlayerData);

                if (mode == "kiosk") {
                    self._populateModeSliderUI(true);
                    self._populateTableEvents();
                } else {
                    self._populateModeSliderUI(false);
                }
            },

            /**
             Load event list to the UI
             @method _populateTableCollection
             @param {Object} i_domPlayerData
             **/
            _populateTableCollection: function (i_domPlayerData) {
                var self = this;
                self.m_collectionTable.bootstrapTable('removeAll');
                var data = [], rowIndex = 0;
                $(i_domPlayerData).find('Collection').children().each(function (k, page) {
                    var resource_hResource, scene_hDataSrc;
                    var type = $(page).attr('type');
                    if (type == 'resource') {
                        resource_hResource = $(page).find('Resource').attr('hResource');
                    } else {
                        scene_hDataSrc = $(page).find('Player').attr('hDataSrc');
                    }
                    log('populating ' + resource_hResource);
                    data.push({
                        rowIndex: rowIndex,
                        checkbox: true,
                        name: $(page).attr('page'),
                        duration: $(page).attr('duration'),
                        type: type,
                        resource_hResource: resource_hResource,
                        scene_hDataSrc: scene_hDataSrc
                    });
                    rowIndex++;
                });
                self.m_collectionTable.bootstrapTable('load', data);
            },

            /**
             Load event list to block props UI
             @method _populateTableEvents
             **/
            _populateTableEvents: function () {
                var self = this;
                var data = [], rowIndex = 0;
                var domPlayerData = self._getBlockPlayerData();
                self.m_collectionEventTable.bootstrapTable('removeAll');
                $(domPlayerData).find('EventCommands').children().each(function (k, eventCommand) {
                    var pageName = '';
                    if ($(eventCommand).attr('command') == 'selectPage')
                        pageName = $(eventCommand).find('Page').attr('name');
                    data.push({
                        rowIndex: rowIndex,
                        checkbox: true,
                        event: $(eventCommand).attr('from'),
                        pageName: pageName,
                        action: self.m_actions[$(eventCommand).attr('command')]
                    });
                    rowIndex++;
                });
                self.m_collectionEventTable.bootstrapTable('load', data);
                self._listenDropdownEvenActionSelection();
                self._listenDropdownEvenActionGoToSelection();

                // disable drag cursor due to bug in bootstrap-table lib (can't disable dragging, yach...)
                setTimeout(function () {
                    $('tr', Elements.KIOSK_EVENTS_CONTAINER).css({
                        cursor: 'pointer'
                    });
                }, 500);
            },

            /**
             Listen to mode change between Kiosk and Slideshow modes
             @method _listenModeChange
             **/
            _listenModeChange: function () {
                var self = this;
                self.sliderInput = function () {
                    if (!self.m_selected)
                        return;
                    var mode = $(Elements.COLLECTION_KIOSK_MODE).prop('checked');
                    self._populateModeSliderUI(mode);
                    var domPlayerData = self._getBlockPlayerData();
                    $(domPlayerData).find('Collection').attr('mode', mode ? 'kiosk' : 'slideshow');
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableEvents();
                };
                $(Elements.COLLECTION_KIOSK_MODE).on('change', self.sliderInput);
            },

            /**
             Render the checkbox slider according to current Kiosk mode for block
             @method _populateModeSliderUI
             @param {Boolean} i_status
             **/
            _populateModeSliderUI: function (i_status) {
                var self = this;
                if (i_status) {
                    $(Elements.COLLECTION_KIOSK_MODE).prop('checked', true);
                    $(Elements.KIOSK_EVENTS_CONTAINER).show();
                    $(Elements.COLLECTION_SLIDESHOW_DURATION_CONTAINER).hide();
                } else {
                    $(Elements.COLLECTION_KIOSK_MODE).prop('checked', false);
                    $(Elements.KIOSK_EVENTS_CONTAINER).hide();
                    $(Elements.COLLECTION_SLIDESHOW_DURATION_CONTAINER).show();
                }
            },

            /**
             Listen to when AddBlockListView announced that a new resource or scene needs to be added
             and if this collection block is selected, go ahead and create one in Bootstrap-table and msdb
             @method _listenAddResource
             **/
            _listenAddResource: function () {
                var self = this;
                self.m_addNewCollectionListItem = function () {
                    BB.comBroker.stopListenWithNamespace(BB.EVENTS.ADD_NEW_BLOCK_LIST, self);
                    if (!self.m_selected)
                        return;
                    var addBlockView;
                    if (self.m_placement == BB.CONSTS.PLACEMENT_CHANNEL) {
                        addBlockView = BB.comBroker.getService(BB.SERVICES.ADD_BLOCK_VIEW);
                    } else if (self.m_placement = BB.CONSTS.PLACEMENT_SCENE) {
                        addBlockView = BB.comBroker.getService(BB.SERVICES.ADD_SCENE_BLOCK_VIEW);
                    }
                    addBlockView.setPlacement(BB.CONSTS.PLACEMENT_LISTS);
                    addBlockView.selectView();

                    BB.comBroker.listenWithNamespace(BB.EVENTS.ADD_NEW_BLOCK_LIST, self, function (e) {
                        if (!self.m_selected)
                            return;
                        e.stopImmediatePropagation();
                        e.preventDefault();
                        self._addCollectionNewListItem(e);
                        BB.comBroker.fire(BB.EVENTS.BLOCK_SELECTED, this, null, self.m_block_id);
                    });
                };
                $(Elements.ADD_RESOURCE_TO_COLLECTION).on('click', self.m_addNewCollectionListItem);
            },

            /**
             Listen to when user wants to add new events (i.e. when in Kiosk mode)
             @method _listenAddEvent
             **/
            _listenAddEvent: function () {
                var self = this;
                self.m_addNewCollectionEvent = function () {
                    if (!self.m_selected)
                        return;
                    var domPlayerData = self._getBlockPlayerData();
                    var buff = '<EventCommand from="event" condition="" command="firstPage" />';
                    $(domPlayerData).find('EventCommands').append($(buff));
                    self._setBlockPlayerData(pepper.xmlToStringIEfix(domPlayerData), BB.CONSTS.NO_NOTIFICATION, true);
                    self._populateTableEvents();
                };
                $(Elements.ADD_COLLECTION_EVENTS).on('click', self.m_addNewCollectionEvent);
            },

            /**
             Listen to when removing a resource from collection list
             The algorithm will uses our bootstrap-table own inject rowIndex value
             and counts up to match with the order of <Pages/> in msdb collection, once matched against same value
             we delete the proper ordered collection item from msdb and refresh the entire table
             @method _listenRemoveResource
             **/
            _listenRemoveEvent: function () {
                var self = this;
                self.m_removeCollectionEvent = function () {
                    if (!self.m_selected)
                        return;
                    if (self.m_collectionEventTable.bootstrapTable('getSelections').length == 0) {
                        bootbox.alert($(Elements.MSG_BOOTBOX_NO_ITEM_SELECTED).text());
                        return;
                    }
                    var rowIndex = $('input[name=btSelectItem]:checked', Elements.COLLECTION_EVENTS_TABLE).closest('tr').attr('data-index');
                    var domPlayerData = self._getBlockPlayerData();
                    $(domPlayerData).find('EventCommands').children().eq(rowIndex).remove();
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableEvents();
                };
                $(Elements.REMOVE_COLLECTION_EVENTS).on('click', self.m_removeCollectionEvent);
            },

            /**
             Listen to when removing a resource from collection list
             The algorithm will uses our bootstrap-table own inject rowIndex value
             and counts up to match with the order of <Pages/> in msdb collection, once matched against same value
             we delete the proper ordered collection item from msdb and refresh the entire table
             @method _listenRemoveResource
             **/
            _listenRemoveResource: function () {
                var self = this;
                self.m_removeCollectionListItem = function () {
                    if (!self.m_selected)
                        return;
                    if (self.m_collectionTable.bootstrapTable('getSelections').length == 0) {
                        bootbox.alert($(Elements.MSG_BOOTBOX_NO_ITEM_SELECTED).text());
                        return;
                    }
                    var rowIndex = $('input[name=btSelectItem]:checked', Elements.COLLECTION_TABLE).closest('tr').attr('data-index');
                    var domPlayerData = self._getBlockPlayerData();
                    $(domPlayerData).find('Collection').children().eq(rowIndex).remove();
                    self._setBlockPlayerData(domPlayerData, BB.CONSTS.NO_NOTIFICATION);
                    self._populateTableCollection(domPlayerData);
                    self._populateTableEvents();
                };
                $(Elements.REMOVE_RESOURCE_FOR_COLLECTION).on('click', self.m_removeCollectionListItem);
            },

            /**
             Add a new collection item which can include a Scene or a resource (not a component)
             @method _addCollectionNewListItem
             @param {Event} e
             **/
            _addCollectionNewListItem: function (e) {
                var self = this;
                var domPlayerData = self._getBlockPlayerData();
                var xSnippetCollection = $(domPlayerData).find('Collection');
                var buff = '';
                // log(e.edata.blockCode, e.edata.resourceID, e.edata.sceneID);
                if (e.edata.blockCode == BB.CONSTS.BLOCKCODE_SCENE) {
                    // add scene to collection
                    // if block resides in scene don't allow cyclic reference to collection scene inside current scene
                    if (self.m_placement == BB.CONSTS.PLACEMENT_SCENE) {
                        var sceneEditView = BB.comBroker.getService(BB.SERVICES['SCENE_EDIT_VIEW']);
                        if (!_.isUndefined(sceneEditView)) {
                            var selectedSceneID = sceneEditView.getSelectedSceneID();
                            selectedSceneID = pepper.getSceneIdFromPseudoId(selectedSceneID);
                            if (selectedSceneID == e.edata.sceneID) {
                                bootbox.alert($(Elements.MSG_BOOTBOX_SCENE_REFER_ITSELF).text());
                                return;
                            }
                        }
                    }
                    var sceneRecord = pepper.getScenePlayerRecord(e.edata.sceneID);
                    var sceneName = $(sceneRecord.player_data_value).attr('label');
                    var nativeID = sceneRecord['native_id'];
                    buff = '<Page page="' + sceneName + '" type="scene" duration="5">' +
                        '<Player src="' + nativeID + '" hDataSrc="' + e.edata.sceneID + '" />' +
                        '</page>';
                } else {
                    // Add resources to collection
                    var resourceName = pepper.getResourceRecord(e.edata.resourceID).resource_name;
                    log('updating hResource ' + e.edata.resourceID);
                    buff = '<Page page="' + resourceName + '" type="resource" duration="5">' +
                        '<Player player="' + e.edata.blockCode + '">' +
                        '<Data>' +
                        '<Resource hResource="' + e.edata.resourceID + '" />' +
                        '</Data>' +
                        '</Player>' +
                        '</page>';
                }
                $(xSnippetCollection).append($(buff));
                self._setBlockPlayerData(pepper.xmlToStringIEfix(domPlayerData), BB.CONSTS.NO_NOTIFICATION, true);
                self._populateTableEvents();
            },

            /**
             Populate the common block properties panel, called from base class if exists
             @method _loadBlockSpecificProps
             @return none
             **/
            _loadBlockSpecificProps: function () {
                var self = this;
                self._populate();
                this._viewSubPanel(Elements.BLOCK_COLLECTION_COMMON_PROPERTIES);
            },

            /**
             re-take ownership for a caller block instance and register global Validators for bootstrap-table to format data
             This function has to run everytime we populate the UI since it is a shared global function
             and we have to override it so 'this' refers to correct BlockCollection instance
             @method _setCollectionBlockGlobalValidationOwner
             **/
            _setCollectionBlockGlobalValidationOwner: function (i_this) {
                // add draggable icons
                BB.lib.collectionDragIcons = function () {
                    return '<div class="dragIconTable"><i class="fa fa-arrows-v"></i></div>';
                };

                // register a global shared function to validate checkbox state
                BB.lib.collectionChecks = function (value, row, index) {
                    return {
                        checked: false,
                        disabled: false
                    }
                };

                // build selection dropdown for even "action", if row.action == name, set it as selected in dropdown
                BB.lib.collectionEventAction = function (value, row, index) {
                    var buffer = '<select class="' + BB.lib.unclass(Elements.CLASS_COLLECTION_EVENT_ACTION) + ' btn">';
                    _.forEach(i_this.m_actions, function (name, value) {
                        if (row.action == name) {
                            buffer += '<option selected>' + name + '</option>';
                        } else {
                            buffer += '<option>' + name + '</option>';
                        }
                    });
                    return buffer + '</select>';
                };

                // build selection dropdown for event "to item" and if row.action is selected un-hide the dropdown in "to item" events and select the proper <option>
                BB.lib.collectionEventActionGoToItem = function (value, row, index) {
                    var buffer = '';
                    var collectionPageNames = i_this._getCollectionPageNames();
                    var visibilityClass = row.action == 'selected' ? '' : 'hidden';
                    buffer = '<select class="' + visibilityClass + ' ' + BB.lib.unclass(Elements.CLASS_COLLECTION_EVENT_ACTION_GOTO) + ' btn">';
                    collectionPageNames.forEach(function (k, v) {
                        var selected = row.pageName == k ? 'selected' : '';
                        buffer += '<option ' + selected + '>' + k + '</option>';
                    });
                    return buffer;
                };
            },

            /**
             Get all the collection pages names for current collection block
             this is called against the last block instance that registered the global function of
             setCollectionBlockGlobalValidationOwner
             @method _getCollectionPageNames
             **/
            _getCollectionPageNames: function () {
                var self = this;
                var data = [];
                var domPlayerData = self._getBlockPlayerData();
                $(domPlayerData).find('Collection').children().each(function (k, page) {
                    data.push($(page).attr('page'));
                });
                return data;
            },

            /**
             Delete this block
             @method deleteBlock
             @params {Boolean} i_memoryOnly if true only remove from existance but not from msdb
             **/
            deleteBlock: function (i_memoryOnly) {
                var self = this;
                $(Elements.ADD_RESOURCE_TO_COLLECTION).off('click', self.m_addNewCollectionListItem);
                $(Elements.ADD_COLLECTION_EVENTS).off('click', self.m_addNewCollectionEvent);
                $(Elements.COLLECTION_KIOSK_MODE).off('change', self.sliderInput);
                $(Elements.REMOVE_COLLECTION_EVENTS).off('click', self.m_removeCollectionEvent);
                $(Elements.CLASS_COLLECTION_EVENT_ACTION).off('change', self.m_onDropDownEventActionHandler);
                $(Elements.CLASS_COLLECTION_EVENT_ACTION_GOTO).off('change', self.m_onDropDownEventActionGoToHandler);
                $(Elements.REMOVE_RESOURCE_FOR_COLLECTION).off('click', self.m_removeCollectionListItem);
                BB.comBroker.stopListen(BB.EVENTS.ADD_NEW_BLOCK_LIST); // removing for everyone which is ok, since gets added in real time
                BB.comBroker.stopListen(BB.EVENTS.COLLECTION_ROW_DROP, self.m_collectionRowDroppedHandler);
                BB.comBroker.stopListen(BB.EVENTS.COLLECTION_ROW_DRAG, self.m_collectionRowDraggedHandler);
                BB.comBroker.stopListen(BB.EVENTS.COLLECTION_ROW_CHANGED, self.m_collectionRowChangedHandler);
                BB.comBroker.stopListen(BB.EVENTS.COLLECTION_EVENT_ROW_CHANGED, self.m_collectionRowEventChangedHandler);
                self._deleteBlock(i_memoryOnly);
            }
        });
        return BlockCollection;
    }
);