APIs

Show:
  1. /**
  2. StoryLineView module manages the Timeline > Channels UI while displaying the visual length over time for each block on the selected channel
  3. @class StorylineView
  4. @constructor
  5. @param {String}
  6. @return {Object} instantiated StorylineView
  7. **/
  8. define(['jquery', 'backbone', 'text', 'text!_templates/_storyboard.html'], function ($, Backbone, text, storylineTemplate) {
  9.  
  10. /**
  11. Custom event fired when a block is selected on the storyline
  12. @event STORYLINE_BLOCK_SELECTED
  13. @param {This} caller
  14. @param {Self} context caller
  15. @param {Event}
  16. @static
  17. @final
  18. **/
  19. BB.EVENTS.STORYLINE_BLOCK_SELECTED = 'STORYLINE_BLOCK_SELECTED';
  20.  
  21. BB.SERVICES.STORYLINE = 'StoryLine';
  22.  
  23. var StorylineView = BB.View.extend({
  24.  
  25. /**
  26. Constructor
  27. @method initialize
  28. **/
  29. initialize: function () {
  30. var self = this;
  31. self.m_storyWidth = 0;
  32. self.m_owner = self;
  33. self.m_selectedTimelineID = undefined;
  34. self.m_selectedBlockID = undefined;
  35. self.m_selectedChannel = undefined;
  36. self.m_blockZindex = 3; // future drag support
  37. BB.comBroker.setService(BB.SERVICES.STORYLINE, self);
  38. BB.comBroker.listen(BB.EVENTS.SIDE_PANEL_SIZED, $.proxy(self._updateWidth, self));
  39. self._listenReset();
  40. self._listenTimelineSelected();
  41. self._listenTimelineChanged();
  42. self._listenBlockSelection();
  43. self._listenTimelineBlockRemoved();
  44. self._listenStackViewSelected();
  45. self._listenToggleStorylineCollapsible();
  46. self._listenAppResized();
  47. self._listenContextMenu();
  48. self._listenExitPreview();
  49. self._updateWidth();
  50.  
  51. //setTimeout(function(){
  52. // self.collapseStoryLine()
  53. //},8000)
  54. },
  55.  
  56. /**
  57. Draw a fresh storyline for current timeline
  58. @method _render
  59. **/
  60. _render: function () {
  61. var self = this;
  62. if (_.isUndefined(self.m_render)) {
  63. self.m_render = _.debounce(function () {
  64. $(Elements.STORYLINE_ELEM).empty();
  65. self.m_storylineContainerSnippet = $(storylineTemplate).find(Elements.STORYLINE_CONTAINER).parent();
  66. self.m_TableSnippet = $(storylineTemplate).find('table').parent();
  67. self.m_ChannelSnippet = $(storylineTemplate).find(Elements.CLASS_STORYLINE_CHANNEL).parent();
  68. self._populateScala();
  69. self._populateChannels();
  70. self._listenSelections();
  71. self._addBlockSelection(self.m_selectedBlockID);
  72. self._addChannelSelection(self.m_selectedChannel);
  73. }, 100);
  74. }
  75. self.m_render();
  76. },
  77.  
  78. /**
  79. Listen to reset of when switching to different campaign so we forget current state
  80. @method _listenReset
  81. **/
  82. _listenReset: function () {
  83. var self = this;
  84. BB.comBroker.listen(BB.EVENTS.CAMPAIGN_RESET, function () {
  85. self.m_storyWidth = 0;
  86. self.m_selectedTimelineID = undefined;
  87. self.m_selectedBlockID = undefined;
  88. self.m_selectedChannel = undefined;
  89. });
  90. },
  91.  
  92. /**
  93. Anytime the containing StackView is selected, re-render the Storyline as resources or scenes could have been
  94. removed while we were gone
  95. @method _listenStackViewSelected
  96. **/
  97. _listenStackViewSelected: function () {
  98. var self = this;
  99. var appContentFaderView = BB.comBroker.getService(BB.SERVICES['APP_CONTENT_FADER_VIEW']);
  100. var campaignSliderStackView = BB.comBroker.getService(BB.SERVICES['CAMPAIGN_SLIDER_STACK_VIEW']);
  101.  
  102. campaignSliderStackView.on(BB.EVENTS.SELECTED_STACK_VIEW, function (e) {
  103. if (e == BB.comBroker.getService(BB.SERVICES['CAMPAIGN_VIEW'])) {
  104. self._delayedRender();
  105. }
  106. });
  107. appContentFaderView.on(BB.EVENTS.SELECTED_STACK_VIEW, function (e) {
  108. if (e == BB.comBroker.getService(BB.SERVICES['CAMPAIGN_MANAGER_VIEW'])) {
  109. self._delayedRender();
  110. }
  111. });
  112. },
  113.  
  114. /**
  115. Listen for block selection
  116. @method _listenBlockSelection
  117. **/
  118. _listenBlockSelection: function () {
  119. var self = this;
  120. BB.comBroker.listen(BB.EVENTS.BLOCK_SELECTED, function (e) {
  121. var blockID = e.edata;
  122. if (!_.isNumber(blockID)) // ignore scene blocks
  123. return;
  124. self._addBlockSelection(blockID);
  125. });
  126. },
  127.  
  128. /**
  129. Listen to when the app is resized so we can re-render
  130. @method _listenAppResized
  131. **/
  132. _listenAppResized: function () {
  133. var self = this;
  134. BB.comBroker.listen(BB.EVENTS.APP_SIZED, function (e) {
  135. self._delayedRender();
  136. });
  137. },
  138.  
  139. /**
  140. Add block selection by marking it on the storyline and remembering selection
  141. @method _addBlockSelection
  142. @param {Number} i_blockID
  143. **/
  144. _addBlockSelection: function (i_blockID) {
  145. var self = this;
  146. if (_.isUndefined(i_blockID))
  147. return;
  148. self._removeBlockSelection();
  149. self.m_selectedBlockID = i_blockID;
  150. var blockElem = $(Elements.STORYLINE_CONTAINER).find('[data-timeline_channel_block_id="' + i_blockID + '"]');
  151. $(blockElem).addClass(BB.lib.unclass(Elements.CLASS_TIMELINE_BLOCK_SELECTED));
  152. },
  153.  
  154. /**
  155. Add channel selection by marking it on the storyline and remembering selection
  156. @method _addChannelSelection
  157. @param {Number} i_selectedChannel
  158. **/
  159. _addChannelSelection: function (i_selectedChannel) {
  160. var self = this;
  161. if (_.isUndefined(i_selectedChannel))
  162. return;
  163. self._removeChannelSelection();
  164. self.m_selectedChannel = i_selectedChannel;
  165. var blockElem = $(Elements.STORYLINE_CONTAINER).find('[data-timeline_channel_id="' + i_selectedChannel + '"]');
  166. blockElem = $(blockElem).filter('.channelHead');
  167. $(blockElem).addClass(BB.lib.unclass(Elements.CLASS_CHANNEL_HEAD_SELECTED));
  168. },
  169.  
  170. /**
  171. Remove currently selected channel by removing selection as well forgetting it
  172. @method _removeChannelSelection
  173. **/
  174. _removeChannelSelection: function () {
  175. var self = this;
  176. self.m_selectedChannel = undefined;
  177. $(Elements.CLASS_CHANNEL_HEAD_SELECTED, Elements.STORYLINE_CONTAINER).removeClass(BB.lib.unclass(Elements.CLASS_CHANNEL_HEAD_SELECTED));
  178. },
  179.  
  180. /**
  181. Remove currently selected block by removing selection as well forgetting it
  182. @method _removeBlockSelection
  183. **/
  184. _removeBlockSelection: function () {
  185. var self = this;
  186. self.m_selectedBlockID = undefined;
  187. $(Elements.CLASS_TIMELINE_BLOCK, Elements.STORYLINE_CONTAINER).removeClass(BB.lib.unclass(Elements.CLASS_TIMELINE_BLOCK_SELECTED));
  188. },
  189.  
  190. /**
  191. Build the UI for the top seconds / minutes scala of the storyline
  192. @method _populateScala
  193. **/
  194. _populateScala: function () {
  195. var self = this, i;
  196. var ticks = [];
  197. var format = 's';
  198. var totalDuration = parseInt(pepper.getTimelineTotalDuration(self.m_selectedTimelineID));
  199. if (totalDuration > 420) {
  200. totalDuration = totalDuration / 60;
  201. format = 'm';
  202. }
  203.  
  204. var tick = totalDuration / 4;
  205. for (i = 1; i < 5; i++) {
  206. tick = BB.lib.parseToFloatDouble(tick);
  207. ticks.push(tick * i);
  208. }
  209.  
  210. ticks.unshift(0);
  211. ticks[ticks.length - 1] = totalDuration;
  212. var l = String((ticks[ticks.length - 1]).toFixed(2)).length;
  213. var lastTick = '';
  214. var scalaRuler = $(self.m_TableSnippet).find(Elements.CLASS_SCALA_RULER);
  215. for (i = 0; i < ticks.length; i++) {
  216. if (i == ticks.length - 1)
  217. lastTick = 'width="1%"'
  218. var value = BB.lib.padZeros(BB.lib.parseToFloatDouble(ticks[i]), l) + format; // log(value);
  219. $(scalaRuler).append('<td class="scalaNum"' + lastTick + ' >' + value + '</td>');
  220. }
  221. $(Elements.STORYLINE_ELEM).append(self.m_TableSnippet);
  222. },
  223.  
  224. /**
  225. Populate UI channels
  226. @method _populateChannels
  227. **/
  228. _populateChannels: function () {
  229. var self = this;
  230. var channelsIDs = pepper.getChannelsOfTimeline(self.m_selectedTimelineID);
  231. for (var n = 0; n < channelsIDs.length; n++) {
  232. var channelID = channelsIDs[n];
  233. var channelSnippet = _.template(_.unescape(self.m_ChannelSnippet.html()), {value: n + 1});
  234. var viewerID = pepper.getAssignedViewerIdFromChannelId(channelID);
  235. $(self.m_storylineContainerSnippet).find('section').append(channelSnippet);
  236. var channelHead = $(self.m_storylineContainerSnippet).find(Elements.CLASS_CHANNEL_HEAD + ':last');
  237. var channelBody = $(self.m_storylineContainerSnippet).find(Elements.CLASS_CHANNEL_BODY + ':last');
  238. $(channelHead).attr('data-timeline_channel_id', channelID);
  239. $(channelBody).attr('data-timeline_channel_id', channelID);
  240. $(channelHead).attr('data-campaign_timeline_board_viewer_id', viewerID);
  241. $(channelBody).attr('data-campaign_timeline_board_viewer_id', viewerID);
  242. self._populateBlocks(channelID);
  243. }
  244. $(Elements.STORYLINE_ELEM).append(self.m_storylineContainerSnippet);
  245. self._updateWidth();
  246. setTimeout(function () {
  247. self._updateWidth();
  248. }, 5);
  249. },
  250.  
  251. /**
  252. Populate UI blocks
  253. @method _populateBlocks
  254. @params {Number} i_campaign_timeline_chanel_id
  255. **/
  256. _populateBlocks: function (i_campaign_timeline_chanel_id) {
  257. var self = this;
  258. var timeline = BB.comBroker.getService(BB.SERVICES['CAMPAIGN_VIEW']).getTimelineInstance(self.m_selectedTimelineID);
  259. var channel = timeline.getChannelInstance(i_campaign_timeline_chanel_id);
  260. var blocks = channel.getBlocks();
  261. var snippet, totalPercent = 0;
  262. for (var block in blocks) {
  263. var blockData = blocks[block].getBlockData();
  264. var blockID = blockData.blockID;
  265. var fontAwesome = blocks[block].getBlockData().blockFontAwesome;
  266. var totalDuration = parseInt(pepper.getTimelineTotalDuration(self.m_selectedTimelineID));
  267. var blockDuration = pepper.getBlockTimelineChannelBlockLength(blockID).totalInSeconds;
  268. var percent = (parseFloat(blockDuration) / parseFloat(totalDuration) * 100);
  269. totalPercent += percent;
  270.  
  271. var blockWidth = (self.m_storyWidth * percent) / 100;
  272. if (blockWidth < 1)
  273. continue;
  274. if (blockWidth < 25) {
  275. snippet = '<div class="timelineBlock" data-timeline_channel_block_id="' + blockID + '" style="width: ' + percent + '%;"></div>';
  276. } else {
  277. snippet = '<div class="timelineBlock" data-timeline_channel_block_id="' + blockID + '" style="width: ' + percent + '%;"><i style="font-size: 14px" class="fa ' + fontAwesome + '"></i></div>';
  278.  
  279. /* future support draggable */
  280. // snippet = '<div class="draggable ui-widget-content ui-draggable ui-draggable-handle timelineBlock" data-timeline_channel_block_id="' + blockID + '" style="width: ' + percent + '%;"><i style="font-size: 14px" class="fa ' + fontAwesome + '"></i></div>';
  281.  
  282. }
  283. /* future support draggable */
  284. // setTimeout(function(){
  285. // $(".timelineBlock").draggable({
  286. // axis: "x",
  287. // start: function(event, ui) { $(this).css("z-index", self.m_blockZindex++); }
  288. // });
  289. //},700);
  290.  
  291. $(self.m_storylineContainerSnippet).find('.channelBody:last').append(snippet);
  292. }
  293. },
  294.  
  295. /**
  296. Compute the storyline UI width total width
  297. @method _updateWidth
  298. **/
  299. _updateWidth: function () {
  300. var self = this;
  301. self.m_storyWidth = parseInt($(Elements.STORYLINE_CONTAINER).width()) - 25;
  302. $(Elements.CLASS_CHANNEL_BODY_CONTAINER).width(self.m_storyWidth);
  303. },
  304.  
  305. /**
  306. Listen to changes in the timeline (channel, block length etc) so we can re-render the storyline
  307. @method _listenTimelineChanged
  308. **/
  309. _listenTimelineChanged: function () {
  310. var self = this;
  311. pepper.listen(Pepper.BLOCK_LENGTH_CHANGED, $.proxy(self._render, self));
  312. BB.comBroker.listen(BB.EVENTS.CAMPAIGN_TIMELINE_CHANGED, function () {
  313. self._render();
  314. })
  315. },
  316.  
  317. /**
  318. Listen to a new timeline selection so we can re-render the storyline
  319. @method _listenTimelineSelected
  320. **/
  321. _listenTimelineSelected: function () {
  322. var self = this;
  323. BB.comBroker.listen(BB.EVENTS.CAMPAIGN_TIMELINE_SELECTED, function (e) {
  324. self._deselection();
  325. self.m_selectedTimelineID = e.edata;
  326. self._render();
  327. });
  328. },
  329.  
  330. /**
  331. Forget all current selections
  332. @method _deselection
  333. **/
  334. _deselection: function () {
  335. var self = this;
  336. self.m_selectedTimelineID = undefined;
  337. self.m_selectedBlockID = undefined;
  338. self.m_selectedChannel = undefined;
  339. },
  340.  
  341. /**
  342. Listen to channel selection so we can re-render storyline
  343. @method _listenSelections
  344. **/
  345. _listenSelections: function () {
  346. var self = this;
  347. $(Elements.CLASS_CHANNEL_HEAD).off('click');
  348. $(Elements.CLASS_CHANNEL_HEAD).on('click', function (e) {
  349. $.proxy(self._blockChannelSelected(e), self);
  350. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_CHANNEL_SELECTED, this, null, self.m_selectedChannel);
  351. });
  352. $(Elements.CLASS_STORYLINE_CHANNEL).off('click');
  353. $(Elements.CLASS_STORYLINE_CHANNEL).on('click', function (e) {
  354. $.proxy(self._blockChannelSelected(e), self);
  355. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_CHANNEL_SELECTED, this, null, self.m_selectedChannel);
  356. });
  357. $(Elements.CLASS_TIMELINE_BLOCK).off('click contextmenu');
  358. $(Elements.CLASS_TIMELINE_BLOCK).on('click contextmenu', function (e) {
  359. $.proxy(self._blockSelected(e), self);
  360.  
  361. /* future support draggable */
  362. // $(this).addClass('top').removeClass('bottom');
  363. // $(this).siblings().removeClass('top').addClass('bottom');
  364. // $(this).css("z-index", self.m_blockZindex++);
  365. });
  366. },
  367.  
  368. /**
  369. When a block is selected within a channel, get the resource element so we can select it and fire
  370. the BLOCK_SELECTED event
  371. @method _blockSelected
  372. @param {Event} e
  373. **/
  374. _blockChannelSelected: function (e) {
  375. var self = this;
  376. if (e.button == 0) {
  377. e.stopImmediatePropagation();
  378. $(Elements.STORYLINE_CONTEXT_MENU).hide();
  379. }
  380.  
  381. var blockElem = $(e.target);
  382.  
  383. if (_.isUndefined($(blockElem).attr('class')))
  384. return true;
  385.  
  386. if ($(blockElem).hasClass(BB.lib.unclass(Elements.CLASS_STORYLINE_CHANNEL)))
  387. blockElem = $(blockElem).find(Elements.CLASS_CHANNEL_HEAD);
  388.  
  389. if ($(blockElem).hasClass(BB.lib.unclass(Elements.CLASS_TIMELINE_BLOCK)))
  390. blockElem = $(blockElem).closest(Elements.CLASS_CHANNEL_BODY);
  391.  
  392. var timeline_channel_id = $(blockElem).data('timeline_channel_id');
  393. var campaign_timeline_board_viewer_id = $(blockElem).data('campaign_timeline_board_viewer_id');
  394.  
  395. //if (_.isUndefined(timeline_channel_id) || _.isUndefined(campaign_timeline_board_viewer_id))
  396. // return false;
  397.  
  398. if (self.m_selectedChannel == timeline_channel_id)
  399. return true;
  400.  
  401. self.m_selectedChannel = timeline_channel_id;
  402. var screenData = {
  403. m_owner: self,
  404. campaign_timeline_id: self.m_selectedTimelineID,
  405. campaign_timeline_board_viewer_id: campaign_timeline_board_viewer_id
  406. };
  407. self._removeBlockSelection();
  408. self._addChannelSelection(self.m_selectedChannel);
  409. var sequencer = BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']);
  410. sequencer.selectViewer(screenData.campaign_timeline_id, screenData.campaign_timeline_board_viewer_id);
  411. BB.comBroker.fire(BB.EVENTS.ON_VIEWER_SELECTED, this, screenData);
  412. return true;
  413. },
  414.  
  415. /**
  416. When a block is selected within a channel, get the resource element so we can select it and fire
  417. the BLOCK_SELECTED event
  418. @method _blockSelected
  419. @param {Event} e
  420. **/
  421. _blockSelected: function (e) {
  422. var self = this;
  423. //e.stopImmediatePropagation();
  424. var blockElem = $(e.target);
  425. self.selected_block_id = $(blockElem).data('timeline_channel_block_id');
  426. // if label was selected
  427. if (_.isUndefined(self.selected_block_id)) {
  428. blockElem = $(e.target).parent();
  429. self.selected_block_id = $(blockElem).data('timeline_channel_block_id');
  430. }
  431. e['target'] = blockElem[0];
  432. self._blockChannelSelected(e);
  433. BB.comBroker.fire(BB.EVENTS.STORYLINE_BLOCK_SELECTED, this, null, self.selected_block_id);
  434. $(blockElem).addClass(BB.lib.unclass(Elements.CLASS_TIMELINE_BLOCK_SELECTED));
  435. //return false;
  436. },
  437.  
  438. /**
  439. Toggle the arrow of the collapsible storyline UI widget
  440. @method _listenToggleStorylineCollapsible
  441. **/
  442. _listenToggleStorylineCollapsible: function () {
  443. var self = this;
  444. $(Elements.TOGGLE_STORYLINE_COLLAPSIBLE).on('click', function () {
  445. var toggle = $(this).find('span')[0];
  446. if ($(toggle).hasClass('glyphicon-chevron-down')) {
  447. $(toggle).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right')
  448. } else {
  449. $(toggle).removeClass('glyphicon-chevron-right').addClass('glyphicon-chevron-down')
  450. }
  451. $(Elements.STORYLINE_ELEM).fadeIn(500).queue(function () {
  452. self._render();
  453. }).dequeue().delay(500).queue(function () {
  454. self._render();
  455. }).dequeue();
  456. });
  457. },
  458.  
  459. /**
  460. Listen to any canvas right click
  461. @method _listenContextMenu
  462. **/
  463. _listenContextMenu: function () {
  464. var self = this;
  465. $(Elements.STORYLINE_ELEM).contextmenu({
  466. target: Elements.STORYLINE_CONTEXT_MENU,
  467. before: function (e, element, target) {
  468. e.preventDefault();
  469. //self.m_mouseX = e.offsetX;
  470. //self.m_mouseY = e.offsetY;
  471. if (_.isUndefined(self.m_selectedBlockID))
  472. return false;
  473. return true;
  474. },
  475. onItem: function (context, e) {
  476. self._onContentMenuSelection($(e.target).attr('name'))
  477. }
  478. });
  479. },
  480.  
  481. /**
  482. Re-render the storyboard upon live preview exit
  483. @method _listenExitPreview
  484. **/
  485. _listenExitPreview: function () {
  486. var self = this;
  487. BB.comBroker.listen(BB.EVENTS.PREVIEW_EXIT, function (e) {
  488. self._delayedRender();
  489. });
  490. },
  491.  
  492. /**
  493. Delayed render of stoeyboard
  494. @method _delayedRender
  495. **/
  496. _delayedRender: function () {
  497. var self = this;
  498. setTimeout(function () {
  499. self._updateWidth();
  500. self._render();
  501. }, 500);
  502. },
  503.  
  504. /**
  505. On Scene right click context menu selection command
  506. @method _onContentMenuSelection
  507. @param {String} i_command
  508. **/
  509. _onContentMenuSelection: function (i_command) {
  510. var self = this;
  511. var campaign_timeline_id = BB.comBroker.getService(BB.SERVICES.CAMPAIGN_VIEW).getSelectedTimeline();
  512. if (campaign_timeline_id == -1 || _.isUndefined(campaign_timeline_id))
  513. return;
  514.  
  515. switch (i_command) {
  516. case 'nextChannel':
  517. {
  518. self.selectNextChannel();
  519. break;
  520. }
  521. case 'addContent':
  522. {
  523. $(Elements.ADD_BLOCK_BUTTON).trigger('click');
  524. break;
  525. }
  526. case 'removeContent':
  527. {
  528. $(Elements.REMOVE_BLOCK_BUTTON).trigger('click');
  529. break;
  530. }
  531. case 'first':
  532. {
  533. BB.comBroker.getService(BB.SERVICES.CHANNEL_LIST_VIEW).moveBlockFirst();
  534. break;
  535. }
  536. case 'last':
  537. {
  538. BB.comBroker.getService(BB.SERVICES.CHANNEL_LIST_VIEW).moveBlockLast();
  539. break;
  540. }
  541. }
  542. return true;
  543. },
  544.  
  545. /**
  546. Listen to when a timeline block is removed
  547. @method _listenTimelineBlockRemoved
  548. @param {Object} e
  549. **/
  550. _listenTimelineBlockRemoved: function () {
  551. var self = this;
  552. pepper.listen(Pepper.REMOVE_TIMELINE_CHANNEL_BLOCK, function (e) {
  553. self.m_selectedBlockID = undefined;
  554. self._removeBlockSelection();
  555. });
  556. },
  557.  
  558. /**
  559. Collapse the storyline bootstrap panel and title
  560. @method collapseStoryLine
  561. **/
  562. collapseStoryLine: function () {
  563. var self = this;
  564. if (!$(Elements.STORYLINE_CONTAINER_COLLAPSE).hasClass('in'))
  565. return;
  566. $('.panel-collapse', Elements.STORYLINE_COLLAPSIBLE).collapse('hide');
  567. $('.panel-title', Elements.STORYLINE_COLLAPSIBLE).attr('data-toggle', 'collapse');
  568. var coll = $(Elements.STORYLINE_COLLAPSIBLE);
  569. var toggle = $(coll).find('span')[0];
  570. $(toggle).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right')
  571. },
  572.  
  573. /**
  574. Select next channel
  575. @method selectNextChannel
  576. **/
  577. selectNextChannel: function () {
  578. var self = this;
  579. var timeline_channel_id, campaign_timeline_board_viewer_id;
  580. var channelsIDs = pepper.getChannelsOfTimeline(self.m_selectedTimelineID);
  581. if (_.isUndefined(self.m_selectedChannel)) {
  582. timeline_channel_id = channelsIDs[0];
  583. } else {
  584. for (var ch in channelsIDs) {
  585. if (channelsIDs[ch] == self.m_selectedChannel) {
  586. if (_.isUndefined(channelsIDs[parseInt(ch) + 1])) {
  587. timeline_channel_id = channelsIDs[0];
  588. } else {
  589. timeline_channel_id = channelsIDs[parseInt(ch) + 1];
  590. }
  591. }
  592. }
  593. }
  594. campaign_timeline_board_viewer_id = pepper.getAssignedViewerIdFromChannelId(timeline_channel_id);
  595. // note: workaround for when viewer is unassigned, need to investigate
  596. if (_.isUndefined(campaign_timeline_board_viewer_id))
  597. return;
  598. var screenData = {
  599. m_owner: self,
  600. campaign_timeline_id: self.m_selectedTimelineID,
  601. campaign_timeline_board_viewer_id: campaign_timeline_board_viewer_id
  602. };
  603. self._removeBlockSelection();
  604. self._addChannelSelection(timeline_channel_id);
  605. BB.comBroker.getService(BB.SERVICES['SEQUENCER_VIEW']).selectViewer(screenData.campaign_timeline_id, screenData.campaign_timeline_board_viewer_id);
  606. BB.comBroker.fire(BB.EVENTS.ON_VIEWER_SELECTED, this, screenData);
  607. BB.comBroker.fire(BB.EVENTS.CAMPAIGN_TIMELINE_CHANNEL_SELECTED, this, null, self.m_selectedChannel);
  608. }
  609. });
  610.  
  611. return StorylineView;
  612.  
  613. });