APIs

Show:
  1. /**
  2. CampaignView module manages campaign related logic and UI
  3. @class CampaignView
  4. @constructor
  5. @return {Object} instantiated CampaignView
  6. **/
  7. define(['jquery', 'backbone', 'SequencerView', 'ChannelListView', 'StackView', 'Timeline', 'ScreenLayoutSelectorView', 'StorylineView', 'BlockFactory'], function ($, Backbone, SequencerView, ChannelListView, StackView, Timeline, ScreenLayoutSelectorView, StorylineView, BlockFactory) {
  8.  
  9. /**
  10. Custom event fired when a timeline or channel or block within the timeline has changed
  11. it ignores the event.
  12. @event CAMPAIGN_TIMELINE_CHANGED
  13. @param {This} caller
  14. @param {Self} context caller
  15. @param {Event} timelineID of the timeline selected
  16. @static
  17. @final
  18. **/
  19. BB.EVENTS.CAMPAIGN_TIMELINE_CHANGED = 'CAMPAIGN_TIMELINE_CHANGED';
  20.  
  21. /**
  22. Custom event fired when a requesing an expanded view of the timelines and storyboard
  23. @event CAMPAIGN_EXPANDED_VIEW
  24. @param {This} caller
  25. @param {Self} context caller
  26. @static
  27. @final
  28. **/
  29. BB.EVENTS.CAMPAIGN_EXPANDED_VIEW = 'CAMPAIGN_EXPANDED_VIEW';
  30.  
  31. /**
  32. Custom event fired before changing to a new campaign
  33. @event CAMPAIGN_SELECTED
  34. @param {This} caller
  35. @param {Self} context caller
  36. @param {Event}
  37. @static
  38. @final
  39. **/
  40. BB.EVENTS.CAMPAIGN_RESET = 'CAMPAIGN_RESET';
  41.  
  42. BB.SERVICES.CAMPAIGN_VIEW = 'CampaignView';
  43.  
  44. var CampaignView = BB.View.extend({
  45.  
  46. /**
  47. Init the instance and listen to VIEW_CHANGED event so we know when it's time to act.
  48. If no campaign was selected, we launch the campaign wizard creator, otherwise we populate the campaign / timelines.
  49. We also use this method to wire the rest of the campaigns elements.
  50. @method initialize
  51. @return none
  52. **/
  53. initialize: function () {
  54. var self = this;
  55. self.m_timelines = {}; // hold references to all created timeline instances
  56. self.m_timelineViewStack = new StackView.Fader({el: Elements.SELECTED_TIMELINE, duration: 333});
  57. self.m_selected_timeline_id = -1;
  58. self.m_selected_campaign_id = -1;
  59. self.m_property = BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']);
  60.  
  61. self.m_blockFactory = BB.comBroker.getService(BB.SERVICES['BLOCK_FACTORY']);
  62. if (!self.m_blockFactory)
  63. self.m_blockFactory = new BlockFactory();
  64.  
  65. self.m_sequencerView = new SequencerView({
  66. el: Elements.SCREEN_LAYOUTS_UL
  67. });
  68.  
  69. self.m_storylineView = new StorylineView({
  70. el: Elements.STORYLINE_ELEM
  71. });
  72.  
  73. BB.comBroker.setService(BB.SERVICES['SEQUENCER_VIEW'], self.m_sequencerView);
  74.  
  75. self.m_channelListView = new ChannelListView({
  76. el: Elements.CHANNEL_LIST_ELEM_VIEW
  77. });
  78. BB.comBroker.setService(BB.SERVICES.CHANNEL_LIST_VIEW, self.m_channelListView);
  79.  
  80. self.m_property.initPanel(Elements.CHANNEL_PROPERTIES);
  81. self.m_property.initPanel(Elements.TIMELINE_PROPERTIES);
  82.  
  83. self._listenCampaignSelected();
  84. self._listenDelTimeline();
  85. self._listenTimelineViewSelected();
  86. self._listenBackToCampaigns();
  87. self._listenAddNewTimeline();
  88. self._listenCampaignPreview();
  89. self._listenSelectNextChannel();
  90. self._listenCampaignTimelinePreview();
  91. self._listenToggleTimelinesCollapsible();
  92. self._listenScreenTemplateEdit();
  93. self._listenTimelineLengthChanged();
  94. self._listenCampaignExpandedView();
  95.  
  96. // pepper.getCampaignsSchedules();
  97. },
  98.  
  99. /**
  100. Listen to campaign selection
  101. @method _listenCampaignSelected
  102. **/
  103. _listenCampaignSelected: function () {
  104. var self = this;
  105. BB.comBroker.listen(BB.EVENTS.CAMPAIGN_SELECTED, function (e) {
  106. self._reset();
  107. self.m_selected_campaign_id = e.edata;
  108. self._render();
  109. });
  110. },
  111.  
  112. /**
  113. If loading an existing campaign (i.e.: we are not creating a brand new one) we load
  114. all campaign data from msdb and populate UI
  115. @method _render
  116. **/
  117. _render: function () {
  118. var self = this;
  119. self.m_selected_campaign_id = BB.comBroker.getService(BB.SERVICES.CAMPAIGN_SELECTOR).getSelectedCampaign();
  120. if (self.m_selected_campaign_id == -1)
  121. return;
  122. self._loadTimelinesFromDB();
  123. self._loadSequencerFirstTimeline();
  124. self._updatedTimelinesLengthUI();
  125. },
  126.  
  127. /**
  128. Load all of the campaign's timelines from msdb and populate the sequencer.
  129. @method _loadTimelinesFromDB
  130. @return none
  131. **/
  132. _loadTimelinesFromDB: function () {
  133. var self = this;
  134. var sequenceOrder = [];
  135.  
  136. var timelineIDs = pepper.getCampaignTimelines(self.m_selected_campaign_id);
  137. for (var i = 0; i < timelineIDs.length; i++) {
  138. var campaign_timeline_id = timelineIDs[i];
  139. var sequenceIndex = pepper.getCampaignTimelineSequencerIndex(campaign_timeline_id);
  140. sequenceOrder[parseInt(sequenceIndex)] = parseInt(campaign_timeline_id);
  141. }
  142.  
  143. $(sequenceOrder).each(function (sequenceIndex, campaign_timeline_id) {
  144. // create the timelines
  145. self.m_timelines[campaign_timeline_id] = new Timeline({campaignTimelineID: campaign_timeline_id});
  146. });
  147. },
  148.  
  149. /**
  150. Select the first timeline in the sequencer UI and if fails, select main Campaign > timeline.
  151. @method _loadSequencerFirstTimeline
  152. @return none
  153. **/
  154. _loadSequencerFirstTimeline: function () {
  155. var self = this;
  156. self.m_sequencerView.selectFirstTimeline();
  157. //var firstTimelineID = pepper.getCampaignTimelineIdOfSequencerIndex(self.m_selected_campaign_id, 0);
  158. //if (self.m_sequencerView.selectTimeline(firstTimelineID) == -1)
  159. // self.m_timelineViewStack.selectView(self.m_noneSelectedTimelines);
  160. },
  161.  
  162. /**
  163. This is a key method that we use to listen to fire event of ScreenLayoutSelectorView.ON_VIEWER_SELECTED.
  164. Upon the event we examine e.context.m_owner to find out who was the owner if the fired event (i.e.: instanceof)
  165. so we can select tha appropriate campaign or timeline in the UI. See further notes in code.
  166. @method _listenTimelineViewSelected
  167. @return none
  168. **/
  169. _listenTimelineViewSelected: function () {
  170. var self = this;
  171.  
  172. BB.comBroker.listen(BB.EVENTS.ON_VIEWER_SELECTED, function (e) {
  173. var autoSelectFirstTimeline = true;
  174. var campaign_timeline_board_viewer_id = e.caller.campaign_timeline_board_viewer_id;
  175. var campaign_timeline_id = e.caller.campaign_timeline_id;
  176. self.m_selected_timeline_id = campaign_timeline_id;
  177.  
  178. ////////////////////////////////////////////////
  179. //// Timeline selected from Sequencer class
  180. ////////////////////////////////////////////////
  181.  
  182. if (e.context.m_owner instanceof SequencerView) {
  183. //self.m_timelineViewStack.selectView(self.m_timelines[campaign_timeline_id].getStackViewID());
  184. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, this, null, campaign_timeline_id);
  185. self._updatedTimelinesLengthUI();
  186. return;
  187. }
  188.  
  189. ////////////////////////////////////////////////
  190. //// Timeline selected from Timeline class
  191. ////////////////////////////////////////////////
  192.  
  193. if (e.context.m_owner instanceof Timeline) {
  194. var recCampaignTimelineViewerChanels = pepper.getChannelIdFromCampaignTimelineBoardViewer(campaign_timeline_board_viewer_id, campaign_timeline_id);
  195. var campaign_timeline_channel_id = recCampaignTimelineViewerChanels['campaign_timeline_chanel_id']
  196. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_CHANNEL_SELECTED, this, null, campaign_timeline_channel_id);
  197. return;
  198. }
  199.  
  200. ////////////////////////////////////////////////
  201. //// Timeline selected from TemplateWizard
  202. ////////////////////////////////////////////////
  203.  
  204. var board_id = undefined;
  205. var campaign_board_id = undefined;
  206.  
  207. if (e.context.m_owner instanceof ScreenLayoutSelectorView) {
  208. if (self.m_selected_campaign_id == -1) {
  209.  
  210. ////////////////////////////////////////////////
  211. // Created a brand new campaign and a new board
  212. ////////////////////////////////////////////////
  213.  
  214. var width = BB.comBroker.getService(BB.SERVICES['RESOLUTION_SELECTOR_VIEW']).getResolution().split('x')[0];
  215. var height = BB.comBroker.getService(BB.SERVICES['RESOLUTION_SELECTOR_VIEW']).getResolution().split('x')[1];
  216. board_id = pepper.createBoard('board', width, height);
  217.  
  218. var newTemplateData = pepper.createNewTemplate(board_id, e.caller.screenTemplateData.screenProps);
  219. var board_template_id = newTemplateData['board_template_id']
  220. var viewers = newTemplateData['viewers'];
  221.  
  222. self.m_selected_campaign_id = pepper.createCampaign('campaign');
  223. campaign_board_id = pepper.assignCampaignToBoard(self.m_selected_campaign_id, board_id);
  224.  
  225. // set campaign name
  226. var campaignName = BB.comBroker.getService(BB.SERVICES['CAMPAIGN_NAME_SELECTOR_VIEW']).getCampaignName();
  227. pepper.setCampaignRecord(self.m_selected_campaign_id, 'campaign_name', campaignName);
  228.  
  229. BB.comBroker.fire(BB.EVENTS.LOAD_CAMPAIGN_LIST);
  230.  
  231. } else {
  232.  
  233. ////////////////////////////////////////////////
  234. // Add Timeline to an existing campaign
  235. ////////////////////////////////////////////////
  236.  
  237. campaign_board_id = pepper.getFirstBoardIDofCampaign(self.m_selected_campaign_id);
  238. board_id = pepper.getBoardFromCampaignBoard(campaign_board_id);
  239. var newTemplateData = pepper.createNewTemplate(board_id, e.caller.screenTemplateData.screenProps);
  240. var board_template_id = newTemplateData['board_template_id']
  241. var viewers = newTemplateData['viewers'];
  242. autoSelectFirstTimeline = false;
  243. }
  244.  
  245. campaign_timeline_id = pepper.createNewTimeline(self.m_selected_campaign_id);
  246. pepper.setCampaignTimelineSequencerIndex(self.m_selected_campaign_id, campaign_timeline_id, 0);
  247. pepper.setTimelineTotalDuration(campaign_timeline_id, '0');
  248. pepper.createCampaignTimelineScheduler(self.m_selected_campaign_id, campaign_timeline_id);
  249.  
  250. var campaign_timeline_board_template_id = pepper.assignTemplateToTimeline(campaign_timeline_id, board_template_id, campaign_board_id);
  251. var channels = pepper.createTimelineChannels(campaign_timeline_id, viewers);
  252. pepper.assignViewersToTimelineChannels(campaign_timeline_board_template_id, viewers, channels);
  253.  
  254. self.m_timelines[campaign_timeline_id] = new Timeline({campaignTimelineID: campaign_timeline_id});
  255. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, this, null, campaign_timeline_id);
  256. BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']).reSequenceTimelines();
  257.  
  258. if (autoSelectFirstTimeline) {
  259. self._loadSequencerFirstTimeline();
  260. } else {
  261. self.m_sequencerView.selectTimeline(campaign_timeline_id);
  262. }
  263. return;
  264. }
  265. });
  266. },
  267.  
  268. /**
  269. Go back to campaign selection screen
  270. @method _listenBackToCampaigns
  271. **/
  272. _listenBackToCampaigns: function () {
  273. var self = this;
  274. $(Elements.BACK_TO_CAMPAIGNS).on('click', function () {
  275. BB.comBroker.getService(BB.SERVICES.CAMPAIGN_SELECTOR).setSelectedCampaign(-1);
  276. BB.comBroker.getService(BB.SERVICES['PROPERTIES_VIEW']).resetPropertiesView();
  277. self.options.stackView.slideToPage(Elements.CAMPAIGN_SELECTOR, 'left');
  278. });
  279. },
  280.  
  281. /**
  282. Wire the UI for adding a new timeline
  283. @method _listenAddNewTimeline
  284. **/
  285. _listenAddNewTimeline: function () {
  286. var self = this;
  287. $(Elements.ADD_NEW_TIMELINE_BUTTON).on('click', function () {
  288. BB.comBroker.getService(BB.SERVICES['SCREEN_LAYOUT_SELECTOR_VIEW']).slideBackDirection('right');
  289. self.options.stackView.slideToPage(Elements.SCREEN_LAYOUT_SELECTOR, 'left');
  290. });
  291. },
  292.  
  293. /**
  294. Wire the UI for launching campaign preview
  295. @method _listenCampaignPreview
  296. **/
  297. _listenCampaignPreview: function () {
  298. var self = this;
  299. $(Elements.CAMPAIGN_PREVIEW).on('click', function () {
  300. var livePreview = BB.comBroker.getService(BB.SERVICES['LIVEPREVIEW']);
  301. livePreview.launchCampaign(self.m_selected_campaign_id);
  302. });
  303. },
  304.  
  305. /**
  306. Listen to select next channel clicj
  307. @method _listenSelectNextChannel
  308. **/
  309. _listenSelectNextChannel: function () {
  310. var self = this;
  311. $(Elements.SELECT_NEXT_CHANNEL).on('click', function () {
  312. BB.comBroker.getService(BB.SERVICES.STORYLINE).selectNextChannel();
  313. });
  314. },
  315.  
  316. /**
  317. Wire the UI for launching specific timeline preview
  318. @method _listenCampaignTimelinePreview
  319. **/
  320. _listenCampaignTimelinePreview: function () {
  321. var self = this;
  322. $(Elements.TIMELIME_PREVIEW).on('click', function () {
  323. var livePreview = BB.comBroker.getService(BB.SERVICES['LIVEPREVIEW']);
  324. livePreview.launchTimeline(self.m_selected_campaign_id, self.m_selected_timeline_id);
  325. });
  326. },
  327.  
  328. /**
  329. Wire the UI for timeline deletion.
  330. @method _listenDelTimeline
  331. @return none
  332. **/
  333. _listenDelTimeline: function () {
  334. var self = this;
  335. $(Elements.REMOVE_TIMELINE_BUTTON).on('click', function (e) {
  336. var totalTimelines = pepper.getCampaignTimelines(self.m_selected_campaign_id).length;
  337. if (totalTimelines == 1) {
  338. bootbox.dialog({
  339. message: $(Elements.MSG_CANT_DELETE_TIMELINE).text(),
  340. buttons: {
  341. danger: {
  342. label: $(Elements.MSG_BOOTBOX_OK).text(),
  343. className: "btn-danger"
  344. }
  345. }
  346. });
  347. } else {
  348. bootbox.confirm($(Elements.MSG_BOOTBOX_SURE_REMOVE_TIMELINE).text(), function (i_result) {
  349. if (i_result == true) {
  350. $.proxy(self._deleteTimeline(), self);
  351. }
  352. });
  353. }
  354. });
  355. },
  356.  
  357. /**
  358. Toggle the arrow of the collapsible timelines / sequencer UI widget
  359. @method _listenToggleTimelinesCollapsible
  360. **/
  361. _listenToggleTimelinesCollapsible: function () {
  362. $(Elements.TOGGLE_TIMELINES_COLLAPSIBLE).on('click', function () {
  363. var toggle = $(this).find('span')[0];
  364. if ($(toggle).hasClass('glyphicon-chevron-down')) {
  365. $(toggle).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right')
  366. } else {
  367. $(toggle).removeClass('glyphicon-chevron-right').addClass('glyphicon-chevron-down')
  368. }
  369. });
  370. },
  371.  
  372. /**
  373. Listen screen template edit button
  374. @method _listenScreenTemplateEdit
  375. **/
  376. _listenScreenTemplateEdit: function () {
  377. var self = this;
  378. $(Elements.EDIT_SCREEN_LAYOUT).on('click', function (e) {
  379. var screenLayoutEditor = BB.comBroker.getService(BB.SERVICES.SCREEN_LAYOUT_EDITOR_VIEW);
  380. var boardTemplateIDs = pepper.getTemplatesOfTimeline(self.m_selected_timeline_id);
  381. screenLayoutEditor.selectView(self.m_selected_timeline_id, boardTemplateIDs[0]);
  382. });
  383. },
  384.  
  385. /**
  386. When a timeline is deleted, remove it from the local timelines hash and notify sequencer.
  387. @method _deleteTimeline
  388. @param {Event} e
  389. @param {Object} i_caller
  390. @return none
  391. **/
  392. _deleteTimeline: function () {
  393. var self = this;
  394. self.m_timelines[self.m_selected_timeline_id].deleteTimeline();
  395. delete self.m_timelines[self.m_selected_timeline_id];
  396. self._loadSequencerFirstTimeline();
  397. },
  398.  
  399. /**
  400. Listen for updates on changes in length of currently selected timeline through the pepper framework
  401. @method _listenTimelineLengthChanged
  402. **/
  403. _listenTimelineLengthChanged: function () {
  404. var self = this;
  405. pepper.listen(Pepper.TIMELINE_LENGTH_CHANGED, $.proxy(self._updatedTimelinesLengthUI, self));
  406. },
  407.  
  408. /**
  409. Listen to when we should expand the view of all collapsible bootstrap widgets in our campaign view moduke
  410. @method _listenCampaignExpandedView
  411. **/
  412. _listenCampaignExpandedView: function () {
  413. var self = this;
  414. BB.comBroker.listen(BB.EVENTS.CAMPAIGN_EXPANDED_VIEW, function (e) {
  415. if (!$(Elements.SCREEN_SELECTOR_CONTAINER_COLLAPSE).hasClass('in'))
  416. $(Elements.TOGGLE_TIMELINES_COLLAPSIBLE).trigger('click');
  417. if (!$(Elements.STORYLINE_CONTAINER_COLLAPSE).hasClass('in'))
  418. $(Elements.TOGGLE_STORYLINE_COLLAPSIBLE).trigger('click');
  419. $(Elements.SELECT_NEXT_CHANNEL).trigger('click');
  420. })
  421. },
  422.  
  423. /**
  424. Update UI of total timelines length on length changed
  425. @method _updatedTimelinesLengthUI
  426. **/
  427. _updatedTimelinesLengthUI: function () {
  428. var self = this;
  429. var totalDuration = 0;
  430. self.m_xdate = BB.comBroker.getService('XDATE');
  431. $.each(self.m_timelines, function (timelineID) {
  432. totalDuration = parseInt(pepper.getTimelineTotalDuration(timelineID)) + totalDuration;
  433. });
  434. var durationFormatted = self.m_xdate.clearTime().addSeconds(totalDuration).toString('HH:mm:ss');
  435. $(Elements.TIMELINES_TOTAL_LENGTH).text(durationFormatted);
  436. },
  437.  
  438. /**
  439. Reset the module and settings
  440. @method _restart
  441. **/
  442. _reset: function () {
  443. var self = this;
  444. self.m_timelines = {};
  445. self.m_selected_timeline_id = -1;
  446. self.m_selected_campaign_id = -1;
  447. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_RESET);
  448. },
  449.  
  450. /**
  451. Get currently selected campaign, which we hold a reference to.
  452. @method getSelectedCampaign
  453. @return {Number} m_selected_campaign_id
  454. **/
  455. getSelectedCampaign: function () {
  456. var self = this;
  457. return self.m_selected_campaign_id;
  458. },
  459.  
  460. /**
  461. Get currently selected timeline id for campaign
  462. @method getSelectedTimeline
  463. @return {Number} m_selected_timeline_id
  464. **/
  465. getSelectedTimeline: function () {
  466. var self = this;
  467. return self.m_selected_timeline_id;
  468. },
  469.  
  470. /**
  471. Get selected timeline instance, which we hold a reference to, via it's timeline_id.
  472. @method getTimelineInstance
  473. @param {Number} i_campaign_timeline_id
  474. @return {Object} timeline instance
  475. **/
  476. getTimelineInstance: function (i_campaign_timeline_id) {
  477. var self = this;
  478. return self.m_timelines[i_campaign_timeline_id];
  479. },
  480.  
  481. /**
  482. Get the timeline viewstack and provide to others.
  483. @method getTimelineViewStack
  484. @return {Object} timeline viewStack instance
  485. **/
  486. getTimelineViewStack: function () {
  487. var self = this;
  488. return self.m_timelineViewStack;
  489. },
  490.  
  491. /**
  492. recreate the UI for all timelines in the timelined sequence supplied
  493. @method populateTimelines
  494. @params {Array} order of timelines to create
  495. **/
  496. populateTimelines: function (i_ordered_timelines_ids) {
  497. var self = this;
  498. _.each(i_ordered_timelines_ids, function (timelineID) {
  499. self.m_timelines[timelineID].populateTimeline();
  500. });
  501. },
  502.  
  503. /**
  504. Duplicate a campaign_timeline including it's screen layout, channels and blocks
  505. @method duplicateTimeline
  506. @param {Number} i_playerData
  507. @return {Number} Unique clientId.
  508. **/
  509. duplicateTimeline: function (i_campaign_timeline_id, i_screenProps) {
  510. return;
  511. var self = this;
  512. var campaign_board_id = pepper.getFirstBoardIDofCampaign(self.m_selected_campaign_id);
  513. var board_id = pepper.getBoardFromCampaignBoard(campaign_board_id);
  514. var newTemplateData = pepper.createNewTemplate(board_id, i_screenProps);
  515. var board_template_id = newTemplateData['board_template_id']
  516. var viewers = newTemplateData['viewers'];
  517. var campaign_timeline_id = pepper.createNewTimeline(self.m_selected_campaign_id);
  518. pepper.setCampaignTimelineSequencerIndex(self.m_selected_campaign_id, campaign_timeline_id, 0);
  519. pepper.setTimelineTotalDuration(campaign_timeline_id, '0');
  520.  
  521. var campaign_timeline_board_template_id = pepper.assignTemplateToTimeline(campaign_timeline_id, board_template_id, campaign_board_id);
  522. var channels = pepper.createTimelineChannels(campaign_timeline_id, viewers);
  523. pepper.assignViewersToTimelineChannels(campaign_timeline_board_template_id, viewers, channels);
  524.  
  525. self.m_timelines[campaign_timeline_id] = new Timeline({campaignTimelineID: campaign_timeline_id});
  526. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, this, null, campaign_timeline_id);
  527. BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']).reSequenceTimelines();
  528. self.m_sequencerView.selectTimeline(campaign_timeline_id);
  529. }
  530.  
  531. });
  532.  
  533. return CampaignView;
  534. });
  535.  
  536.