/**
CampaignView module manages campaign related logic and UI
@class CampaignView
@constructor
@return {Object} instantiated CampaignView
**/
define(['jquery', 'backbone', 'SequencerView', 'ChannelListView', 'StackView', 'Timeline', 'ScreenLayoutSelectorView', 'StorylineView', 'BlockFactory'], function ($, Backbone, SequencerView, ChannelListView, StackView, Timeline, ScreenLayoutSelectorView, StorylineView, BlockFactory) {
/**
Custom event fired when a timeline or channel or block within the timeline has changed
it ignores the event.
@event CAMPAIGN_TIMELINE_CHANGED
@param {This} caller
@param {Self} context caller
@param {Event} timelineID of the timeline selected
@static
@final
**/
BB.EVENTS.CAMPAIGN_TIMELINE_CHANGED = 'CAMPAIGN_TIMELINE_CHANGED';
/**
Custom event fired when a requesing an expanded view of the timelines and storyboard
@event CAMPAIGN_EXPANDED_VIEW
@param {This} caller
@param {Self} context caller
@static
@final
**/
BB.EVENTS.CAMPAIGN_EXPANDED_VIEW = 'CAMPAIGN_EXPANDED_VIEW';
/**
Custom event fired before changing to a new campaign
@event CAMPAIGN_SELECTED
@param {This} caller
@param {Self} context caller
@param {Event}
@static
@final
**/
BB.EVENTS.CAMPAIGN_RESET = 'CAMPAIGN_RESET';
BB.SERVICES.CAMPAIGN_VIEW = 'CampaignView';
var CampaignView = BB.View.extend({
/**
Init the instance and listen to VIEW_CHANGED event so we know when it's time to act.
If no campaign was selected, we launch the campaign wizard creator, otherwise we populate the campaign / timelines.
We also use this method to wire the rest of the campaigns elements.
@method initialize
@return none
**/
initialize: function () {
var self = this;
self.m_timelines = {}; // hold references to all created timeline instances
self.m_timelineViewStack = new StackView.Fader({el: Elements.SELECTED_TIMELINE, duration: 333});
self.m_selected_timeline_id = -1;
self.m_selected_campaign_id = -1;
self.m_property = BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']);
self.m_blockFactory = BB.comBroker.getService(BB.SERVICES['BLOCK_FACTORY']);
if (!self.m_blockFactory)
self.m_blockFactory = new BlockFactory();
self.m_sequencerView = new SequencerView({
el: Elements.SCREEN_LAYOUTS_UL
});
self.m_storylineView = new StorylineView({
el: Elements.STORYLINE_ELEM
});
BB.comBroker.setService(BB.SERVICES['SEQUENCER_VIEW'], self.m_sequencerView);
self.m_channelListView = new ChannelListView({
el: Elements.CHANNEL_LIST_ELEM_VIEW
});
BB.comBroker.setService(BB.SERVICES.CHANNEL_LIST_VIEW, self.m_channelListView);
self.m_property.initPanel(Elements.CHANNEL_PROPERTIES);
self.m_property.initPanel(Elements.TIMELINE_PROPERTIES);
self._listenCampaignSelected();
self._listenDelTimeline();
self._listenTimelineViewSelected();
self._listenBackToCampaigns();
self._listenAddNewTimeline();
self._listenCampaignPreview();
self._listenSelectNextChannel();
self._listenCampaignTimelinePreview();
self._listenToggleTimelinesCollapsible();
self._listenScreenTemplateEdit();
self._listenTimelineLengthChanged();
self._listenCampaignExpandedView();
// pepper.getCampaignsSchedules();
},
/**
Listen to campaign selection
@method _listenCampaignSelected
**/
_listenCampaignSelected: function () {
var self = this;
BB.comBroker.listen(BB.EVENTS.CAMPAIGN_SELECTED, function (e) {
self._reset();
self.m_selected_campaign_id = e.edata;
self._render();
});
},
/**
If loading an existing campaign (i.e.: we are not creating a brand new one) we load
all campaign data from msdb and populate UI
@method _render
**/
_render: function () {
var self = this;
self.m_selected_campaign_id = BB.comBroker.getService(BB.SERVICES.CAMPAIGN_SELECTOR).getSelectedCampaign();
if (self.m_selected_campaign_id == -1)
return;
self._loadTimelinesFromDB();
self._loadSequencerFirstTimeline();
self._updatedTimelinesLengthUI();
},
/**
Load all of the campaign's timelines from msdb and populate the sequencer.
@method _loadTimelinesFromDB
@return none
**/
_loadTimelinesFromDB: function () {
var self = this;
var sequenceOrder = [];
var timelineIDs = pepper.getCampaignTimelines(self.m_selected_campaign_id);
for (var i = 0; i < timelineIDs.length; i++) {
var campaign_timeline_id = timelineIDs[i];
var sequenceIndex = pepper.getCampaignTimelineSequencerIndex(campaign_timeline_id);
sequenceOrder[parseInt(sequenceIndex)] = parseInt(campaign_timeline_id);
}
$(sequenceOrder).each(function (sequenceIndex, campaign_timeline_id) {
// create the timelines
self.m_timelines[campaign_timeline_id] = new Timeline({campaignTimelineID: campaign_timeline_id});
});
},
/**
Select the first timeline in the sequencer UI and if fails, select main Campaign > timeline.
@method _loadSequencerFirstTimeline
@return none
**/
_loadSequencerFirstTimeline: function () {
var self = this;
self.m_sequencerView.selectFirstTimeline();
//var firstTimelineID = pepper.getCampaignTimelineIdOfSequencerIndex(self.m_selected_campaign_id, 0);
//if (self.m_sequencerView.selectTimeline(firstTimelineID) == -1)
// self.m_timelineViewStack.selectView(self.m_noneSelectedTimelines);
},
/**
This is a key method that we use to listen to fire event of ScreenLayoutSelectorView.ON_VIEWER_SELECTED.
Upon the event we examine e.context.m_owner to find out who was the owner if the fired event (i.e.: instanceof)
so we can select tha appropriate campaign or timeline in the UI. See further notes in code.
@method _listenTimelineViewSelected
@return none
**/
_listenTimelineViewSelected: function () {
var self = this;
BB.comBroker.listen(BB.EVENTS.ON_VIEWER_SELECTED, function (e) {
var autoSelectFirstTimeline = true;
var campaign_timeline_board_viewer_id = e.caller.campaign_timeline_board_viewer_id;
var campaign_timeline_id = e.caller.campaign_timeline_id;
self.m_selected_timeline_id = campaign_timeline_id;
////////////////////////////////////////////////
//// Timeline selected from Sequencer class
////////////////////////////////////////////////
if (e.context.m_owner instanceof SequencerView) {
//self.m_timelineViewStack.selectView(self.m_timelines[campaign_timeline_id].getStackViewID());
BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, this, null, campaign_timeline_id);
self._updatedTimelinesLengthUI();
return;
}
////////////////////////////////////////////////
//// Timeline selected from Timeline class
////////////////////////////////////////////////
if (e.context.m_owner instanceof Timeline) {
var recCampaignTimelineViewerChanels = pepper.getChannelIdFromCampaignTimelineBoardViewer(campaign_timeline_board_viewer_id, campaign_timeline_id);
var campaign_timeline_channel_id = recCampaignTimelineViewerChanels['campaign_timeline_chanel_id']
BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_CHANNEL_SELECTED, this, null, campaign_timeline_channel_id);
return;
}
////////////////////////////////////////////////
//// Timeline selected from TemplateWizard
////////////////////////////////////////////////
var board_id = undefined;
var campaign_board_id = undefined;
if (e.context.m_owner instanceof ScreenLayoutSelectorView) {
if (self.m_selected_campaign_id == -1) {
////////////////////////////////////////////////
// Created a brand new campaign and a new board
////////////////////////////////////////////////
var width = BB.comBroker.getService(BB.SERVICES['RESOLUTION_SELECTOR_VIEW']).getResolution().split('x')[0];
var height = BB.comBroker.getService(BB.SERVICES['RESOLUTION_SELECTOR_VIEW']).getResolution().split('x')[1];
board_id = pepper.createBoard('board', width, height);
var newTemplateData = pepper.createNewTemplate(board_id, e.caller.screenTemplateData.screenProps);
var board_template_id = newTemplateData['board_template_id']
var viewers = newTemplateData['viewers'];
self.m_selected_campaign_id = pepper.createCampaign('campaign');
campaign_board_id = pepper.assignCampaignToBoard(self.m_selected_campaign_id, board_id);
// set campaign name
var campaignName = BB.comBroker.getService(BB.SERVICES['CAMPAIGN_NAME_SELECTOR_VIEW']).getCampaignName();
pepper.setCampaignRecord(self.m_selected_campaign_id, 'campaign_name', campaignName);
BB.comBroker.fire(BB.EVENTS.LOAD_CAMPAIGN_LIST);
} else {
////////////////////////////////////////////////
// Add Timeline to an existing campaign
////////////////////////////////////////////////
campaign_board_id = pepper.getFirstBoardIDofCampaign(self.m_selected_campaign_id);
board_id = pepper.getBoardFromCampaignBoard(campaign_board_id);
var newTemplateData = pepper.createNewTemplate(board_id, e.caller.screenTemplateData.screenProps);
var board_template_id = newTemplateData['board_template_id']
var viewers = newTemplateData['viewers'];
autoSelectFirstTimeline = false;
}
campaign_timeline_id = pepper.createNewTimeline(self.m_selected_campaign_id);
pepper.setCampaignTimelineSequencerIndex(self.m_selected_campaign_id, campaign_timeline_id, 0);
pepper.setTimelineTotalDuration(campaign_timeline_id, '0');
pepper.createCampaignTimelineScheduler(self.m_selected_campaign_id, campaign_timeline_id);
var campaign_timeline_board_template_id = pepper.assignTemplateToTimeline(campaign_timeline_id, board_template_id, campaign_board_id);
var channels = pepper.createTimelineChannels(campaign_timeline_id, viewers);
pepper.assignViewersToTimelineChannels(campaign_timeline_board_template_id, viewers, channels);
self.m_timelines[campaign_timeline_id] = new Timeline({campaignTimelineID: campaign_timeline_id});
BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, this, null, campaign_timeline_id);
BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']).reSequenceTimelines();
if (autoSelectFirstTimeline) {
self._loadSequencerFirstTimeline();
} else {
self.m_sequencerView.selectTimeline(campaign_timeline_id);
}
return;
}
});
},
/**
Go back to campaign selection screen
@method _listenBackToCampaigns
**/
_listenBackToCampaigns: function () {
var self = this;
$(Elements.BACK_TO_CAMPAIGNS).on('click', function () {
BB.comBroker.getService(BB.SERVICES.CAMPAIGN_SELECTOR).setSelectedCampaign(-1);
BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']).resetPropertiesView();
self.options.stackView.slideToPage(Elements.CAMPAIGN_SELECTOR, 'left');
});
},
/**
Wire the UI for adding a new timeline
@method _listenAddNewTimeline
**/
_listenAddNewTimeline: function () {
var self = this;
$(Elements.ADD_NEW_TIMELINE_BUTTON).on('click', function () {
BB.comBroker.getService(BB.SERVICES['SCREEN_LAYOUT_SELECTOR_VIEW']).slideBackDirection('right');
self.options.stackView.slideToPage(Elements.SCREEN_LAYOUT_SELECTOR, 'left');
});
},
/**
Wire the UI for launching campaign preview
@method _listenCampaignPreview
**/
_listenCampaignPreview: function () {
var self = this;
$(Elements.CAMPAIGN_PREVIEW).on('click', function () {
var livePreview = BB.comBroker.getService(BB.SERVICES['LIVEPREVIEW']);
livePreview.launchCampaign(self.m_selected_campaign_id);
});
},
/**
Listen to select next channel clicj
@method _listenSelectNextChannel
**/
_listenSelectNextChannel: function () {
var self = this;
$(Elements.SELECT_NEXT_CHANNEL).on('click', function () {
BB.comBroker.getService(BB.SERVICES.STORYLINE).selectNextChannel();
});
},
/**
Wire the UI for launching specific timeline preview
@method _listenCampaignTimelinePreview
**/
_listenCampaignTimelinePreview: function () {
var self = this;
$(Elements.TIMELIME_PREVIEW).on('click', function () {
var livePreview = BB.comBroker.getService(BB.SERVICES['LIVEPREVIEW']);
livePreview.launchTimeline(self.m_selected_campaign_id, self.m_selected_timeline_id);
});
},
/**
Wire the UI for timeline deletion.
@method _listenDelTimeline
@return none
**/
_listenDelTimeline: function () {
var self = this;
$(Elements.REMOVE_TIMELINE_BUTTON).on('click', function (e) {
var totalTimelines = pepper.getCampaignTimelines(self.m_selected_campaign_id).length;
if (totalTimelines == 1) {
bootbox.dialog({
message: $(Elements.MSG_CANT_DELETE_TIMELINE).text(),
buttons: {
danger: {
label: $(Elements.MSG_BOOTBOX_OK).text(),
className: "btn-danger"
}
}
});
} else {
bootbox.confirm($(Elements.MSG_BOOTBOX_SURE_REMOVE_TIMELINE).text(), function (i_result) {
if (i_result == true) {
$.proxy(self._deleteTimeline(), self);
}
});
}
});
},
/**
Toggle the arrow of the collapsible timelines / sequencer UI widget
@method _listenToggleTimelinesCollapsible
**/
_listenToggleTimelinesCollapsible: function () {
$(Elements.TOGGLE_TIMELINES_COLLAPSIBLE).on('click', function () {
var toggle = $(this).find('span')[0];
if ($(toggle).hasClass('glyphicon-chevron-down')) {
$(toggle).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right')
} else {
$(toggle).removeClass('glyphicon-chevron-right').addClass('glyphicon-chevron-down')
}
});
},
/**
Listen screen template edit button
@method _listenScreenTemplateEdit
**/
_listenScreenTemplateEdit: function () {
var self = this;
$(Elements.EDIT_SCREEN_LAYOUT).on('click', function (e) {
var screenLayoutEditor = BB.comBroker.getService(BB.SERVICES.SCREEN_LAYOUT_EDITOR_VIEW);
var boardTemplateIDs = pepper.getTemplatesOfTimeline(self.m_selected_timeline_id);
screenLayoutEditor.selectView(self.m_selected_timeline_id, boardTemplateIDs[0]);
});
},
/**
When a timeline is deleted, remove it from the local timelines hash and notify sequencer.
@method _deleteTimeline
@param {Event} e
@param {Object} i_caller
@return none
**/
_deleteTimeline: function () {
var self = this;
self.m_timelines[self.m_selected_timeline_id].deleteTimeline();
delete self.m_timelines[self.m_selected_timeline_id];
self._loadSequencerFirstTimeline();
},
/**
Listen for updates on changes in length of currently selected timeline through the pepper framework
@method _listenTimelineLengthChanged
**/
_listenTimelineLengthChanged: function () {
var self = this;
pepper.listen(Pepper.TIMELINE_LENGTH_CHANGED, $.proxy(self._updatedTimelinesLengthUI, self));
},
/**
Listen to when we should expand the view of all collapsible bootstrap widgets in our campaign view moduke
@method _listenCampaignExpandedView
**/
_listenCampaignExpandedView: function () {
var self = this;
BB.comBroker.listen(BB.EVENTS.CAMPAIGN_EXPANDED_VIEW, function (e) {
if (!$(Elements.SCREEN_SELECTOR_CONTAINER_COLLAPSE).hasClass('in'))
$(Elements.TOGGLE_TIMELINES_COLLAPSIBLE).trigger('click');
if (!$(Elements.STORYLINE_CONTAINER_COLLAPSE).hasClass('in'))
$(Elements.TOGGLE_STORYLINE_COLLAPSIBLE).trigger('click');
$(Elements.SELECT_NEXT_CHANNEL).trigger('click');
})
},
/**
Update UI of total timelines length on length changed
@method _updatedTimelinesLengthUI
**/
_updatedTimelinesLengthUI: function () {
var self = this;
var totalDuration = 0;
self.m_xdate = BB.comBroker.getService('XDATE');
$.each(self.m_timelines, function (timelineID) {
totalDuration = parseInt(pepper.getTimelineTotalDuration(timelineID)) + totalDuration;
});
var durationFormatted = self.m_xdate.clearTime().addSeconds(totalDuration).toString('HH:mm:ss');
$(Elements.TIMELINES_TOTAL_LENGTH).text(durationFormatted);
},
/**
Reset the module and settings
@method _restart
**/
_reset: function () {
var self = this;
self.m_timelines = {};
self.m_selected_timeline_id = -1;
self.m_selected_campaign_id = -1;
BB.comBroker.fire(BB.EVENTS.CAMPAIGN_RESET);
},
/**
Get currently selected campaign, which we hold a reference to.
@method getSelectedCampaign
@return {Number} m_selected_campaign_id
**/
getSelectedCampaign: function () {
var self = this;
return self.m_selected_campaign_id;
},
/**
Get currently selected timeline id for campaign
@method getSelectedTimeline
@return {Number} m_selected_timeline_id
**/
getSelectedTimeline: function () {
var self = this;
return self.m_selected_timeline_id;
},
/**
Get selected timeline instance, which we hold a reference to, via it's timeline_id.
@method getTimelineInstance
@param {Number} i_campaign_timeline_id
@return {Object} timeline instance
**/
getTimelineInstance: function (i_campaign_timeline_id) {
var self = this;
return self.m_timelines[i_campaign_timeline_id];
},
/**
Get the timeline viewstack and provide to others.
@method getTimelineViewStack
@return {Object} timeline viewStack instance
**/
getTimelineViewStack: function () {
var self = this;
return self.m_timelineViewStack;
},
/**
recreate the UI for all timelines in the timelined sequence supplied
@method populateTimelines
@params {Array} order of timelines to create
**/
populateTimelines: function (i_ordered_timelines_ids) {
var self = this;
_.each(i_ordered_timelines_ids, function (timelineID) {
self.m_timelines[timelineID].populateTimeline();
});
},
/**
Duplicate a campaign_timeline including it's screen layout, channels and blocks
@method duplicateTimeline
@param {Number} i_playerData
@return {Number} Unique clientId.
**/
duplicateTimeline: function (i_campaign_timeline_id, i_screenProps) {
return;
var self = this;
var campaign_board_id = pepper.getFirstBoardIDofCampaign(self.m_selected_campaign_id);
var board_id = pepper.getBoardFromCampaignBoard(campaign_board_id);
var newTemplateData = pepper.createNewTemplate(board_id, i_screenProps);
var board_template_id = newTemplateData['board_template_id']
var viewers = newTemplateData['viewers'];
var campaign_timeline_id = pepper.createNewTimeline(self.m_selected_campaign_id);
pepper.setCampaignTimelineSequencerIndex(self.m_selected_campaign_id, campaign_timeline_id, 0);
pepper.setTimelineTotalDuration(campaign_timeline_id, '0');
var campaign_timeline_board_template_id = pepper.assignTemplateToTimeline(campaign_timeline_id, board_template_id, campaign_board_id);
var channels = pepper.createTimelineChannels(campaign_timeline_id, viewers);
pepper.assignViewersToTimelineChannels(campaign_timeline_board_template_id, viewers, channels);
self.m_timelines[campaign_timeline_id] = new Timeline({campaignTimelineID: campaign_timeline_id});
BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, this, null, campaign_timeline_id);
BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']).reSequenceTimelines();
self.m_sequencerView.selectTimeline(campaign_timeline_id);
}
});
return CampaignView;
});