Created
December 16, 2016 22:17
-
-
Save adambankin/7a8e10e09f3e527c7d91233f5d9b1b33 to your computer and use it in GitHub Desktop.
src/js/modules/strategy/views/item.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global define*/ | |
define([ | |
'jQuery', | |
'Underscore', | |
'T1', | |
'T1View', | |
'T1Model', | |
'T1Layout', | |
'text!modules/strategy/templates/item.html', | |
'text!modules/strategy/templates/spendMode.html', | |
'text!modules/strategy/templates/impressionMode.html', | |
'text!modules/strategy/templates/performanceMode.html', | |
'T1Form', | |
'T1Permissions', | |
'models/sessionUser', | |
'T1Menu', | |
'utils/CampaignStrategyUtils', | |
'T1Tooltip', | |
'T1Accordion', | |
'T1DatePicker' | |
], function ($, _, T1, T1View, T1Model, T1Layout, template, spendMode, impressionMode, performanceMode, T1Form, | |
T1Permissions, User, T1Menu, CampaignStrategyUtils) { | |
'use strict'; | |
// TODO: When new freq cap goes global, remove line below | |
var useNewFreqCap = T1Permissions.check('feature', 'use_new_freq_cap'); | |
var toInitialCaps = T1.Utils.toInitialCaps; | |
var frequencyIntervalText = { | |
'hour': 'Hour', | |
'day': 'Day', | |
'week': '7 Days', | |
'month': '30 Days' | |
}; | |
var frequencyIntervalDisplayText = { | |
'hour': '/h', | |
'day': '/d', | |
'week': '/w', | |
'month': '/m' | |
}; | |
var frequencyNoLimitText = 'No Cap'; | |
var impressionNoLimitText = 'No Cap'; | |
var dropdownList = { | |
'goal_type': { | |
options: [ | |
{ value: 'spend', text: 'SPEND' }, | |
{ value: 'reach', text: 'REACH' }, | |
{ value: 'cpc', text: 'CPC' }, | |
{ value: 'cpe', text: 'CPE' }, | |
{ value: 'cpa', text: 'CPA' }, | |
{ value: 'roi', text: 'ROI' }, | |
{ value: 'vcr', text: 'VCR' }, | |
{ value: 'ctr', text: 'CTR' } | |
], | |
bodyClassName: 'goal-type-dropdown-body', | |
headClassName: 'goal-type-dropdown-head' | |
}, | |
'type': { | |
options: [ | |
{ value: 'REM', text: 'REM' }, | |
{ value: 'GBO', text: 'GBO' }, | |
{ value: 'AUD', text: 'AUD' } | |
], | |
bodyClassName: 'small-body', | |
headClassName: 'small-head' | |
}, | |
'pacing_type': { | |
options: [ | |
{ value: 'even', text: 'Even' }, | |
{ value: 'asap', text: 'ASAP' } | |
] | |
}, | |
'pacing_amount': { | |
isCurrency: true | |
}, | |
'pacing_interval': { | |
options: [ | |
{ value: 'hour', text: 'hour' }, | |
{ value: 'day', text: 'day' } | |
] | |
}, | |
'impression_pacing_type': function () { | |
var options = [ | |
{ value: 'even', text: 'Even' }, | |
{ value: 'asap', text: 'ASAP' }, | |
{ value: 'no-limit', text: impressionNoLimitText } | |
]; | |
return { | |
options: options | |
}; | |
}, | |
'impression_pacing_amount': { | |
isCurrency: false | |
}, | |
'impression_pacing_interval': { | |
options: [ | |
{ value: 'hour', text: 'hour' }, | |
{ value: 'day', text: 'day' } | |
] | |
}, | |
'frequency_type': function (model) { | |
var goalType = model && model.get('goal_type'); | |
// TODO When new freq cap goes global, remove refs to useNewFreqCap from function | |
var options = [ | |
{ value: 'even', text: 'Even' }, | |
{ value: 'asap', text: 'ASAP' }, | |
{ value: 'no-limit', text: frequencyNoLimitText } | |
]; | |
if (useNewFreqCap && goalType !== 'reach' && goalType !== 'spend') { | |
options.unshift({ value: 'standard', text: 'T1 Optimized' }); | |
} | |
return { | |
options: options | |
}; | |
}, | |
'frequency_interval': { | |
options: [ | |
{ value: 'hour', text: frequencyIntervalText.hour }, | |
{ value: 'day', text: frequencyIntervalText.day }, | |
{ value: 'week', text: frequencyIntervalText.week }, | |
{ value: 'month', text: frequencyIntervalText.month } | |
] | |
} | |
}; | |
var pacingASAPCaution = '<p>ASAP pacing is designed to bolster spend for strategies targeting small audiences. ' + | |
'When targeting larger audiences, ASAP pacing may result in spending more than your pacing amount.</p>' + | |
'<p class="confirm-message">By clicking the ' + "'Confirm'" + | |
' button, you are acknowledging the possibility of overspend.</p>'; | |
var impPacingASAPCaution = '<p>ASAP pacing is designed to bolster delivery for strategies targeting small ' + | |
'audiences. When targeting larger audiences, ASAP pacing may result in delivering more than your pacing amount.' + | |
'</p><p class="confirm-message">By clicking the ' + "'Confirm'" + ' button, you are acknowledging the ' + | |
'possibility of over delivery.</p>'; | |
var frequencyCap = function ($groupEditEl, frequencyType) { | |
var $frequencyEls; | |
var isNoCap = frequencyType === 'no-limit' || frequencyType === 'standard'; | |
// Have to create a stub model here as it's what T1.Form.InlineEdit expects for a function that returns a DDL config | |
var freqType = dropdownList.frequency_type(new T1Model()); | |
var freqTypeIndex = freqType.options.findIndex(function (freqTypeItem) { | |
return freqTypeItem.value === frequencyType; | |
}); | |
$groupEditEl.toggleClass('no-cap', isNoCap); | |
$frequencyEls = $('[data-bind]', $groupEditEl).not('[data-bind="frequency_type"]'); | |
if (isNoCap) { | |
$('[data-bind="frequency_type"]', $groupEditEl) | |
.val(freqType.options[freqTypeIndex].value) | |
.trigger('liszt:updated'); | |
} | |
$.each($frequencyEls, function (key, el) { | |
$(el).closest('dd').toggle(!isNoCap); | |
}); | |
$('.info', $groupEditEl).toggle(!isNoCap); | |
}; | |
var impressionCap = function ($groupEditEl, impressionType, notRMX) { | |
var $impressionEls; | |
var isNoImpCap = impressionType === 'no-limit'; | |
// Have to create a stub model here as it's what T1.Form.InlineEdit expects for a function that returns a DDL config | |
var impType = dropdownList.impression_pacing_type(new T1Model()); | |
var impTypeIndex = impType.options.findIndex(function (impTypeItem) { | |
return impTypeItem.value === impressionType; | |
}); | |
$groupEditEl.toggleClass('no-cap', isNoImpCap); | |
if (notRMX === true) { | |
$impressionEls = $('[data-bind]', $groupEditEl).not('[data-bind="impression_pacing_type"]'); | |
} | |
if (isNoImpCap) { | |
$('[data-bind="impression_pacing_type"]', $groupEditEl) | |
.val(impType.options[impTypeIndex].value) | |
.trigger('liszt:updated'); | |
} | |
if ($impressionEls){ | |
$.each($impressionEls, function (key, el) { | |
$(el).closest('dd').toggle(!isNoImpCap); | |
}); | |
} | |
$('.info', $groupEditEl).toggle(!isNoImpCap); | |
}; | |
var useCampFreqCap = CampaignStrategyUtils.useCampaignFrequencyCap; | |
var ItemView, totalSpendEcpa, totalSpendEcpc, totalSpendEcpe, totalSpendEcpm, totalSpendRoi, | |
totalSpend, goalMonitoringReport; | |
var statusActiveTitle = 'Active'; | |
var statusInactiveTitle = 'Inactive'; | |
var readOnlyTitle = "You don't have permission to edit this strategy"; | |
var addToChartTitle = 'Add to Chart'; | |
var Date = T1.Date; | |
var formatsRolledUpNumbersNoAbbreviation = CampaignStrategyUtils.formatsRolledUpNumbersNoAbbreviation; | |
var divideByZero = CampaignStrategyUtils.divideByZero; | |
var getDatePickerLowerBoundForStrategy = CampaignStrategyUtils.getDatePickerLowerBoundForStrategy; | |
var populatePerformanceAlert = CampaignStrategyUtils.populatePerformanceAlert; | |
var enableTrackingSupplyTypeFeatureFlag = T1Permissions.check('feature', 'supply_type_tracking'); | |
ItemView = T1View.extend({ | |
template: template, | |
partials: { | |
spend1: spendMode, | |
performance1: performanceMode, | |
impression1: impressionMode, | |
spend7: spendMode, | |
performance7: performanceMode, | |
impression7: impressionMode, | |
spend14: spendMode, | |
performance14: performanceMode, | |
impression14: impressionMode, | |
spend30: spendMode, | |
performance30: performanceMode, | |
impression30: impressionMode, | |
spendFTD: spendMode, | |
performanceFTD: performanceMode, | |
impressionFTD: impressionMode, | |
spendCTD: spendMode, | |
performanceCTD: performanceMode, | |
impressionCTD: impressionMode | |
}, | |
menuConfig: { | |
menuTriggerEleSelector: '.strategy-settings', | |
menuColumns: [ | |
{ | |
'columnTitle': null, | |
'hideIcons': true, | |
'menuItems': [ | |
{ | |
'label': 'Edit', | |
'visible': false | |
}, | |
{ | |
'label': 'View Summary', | |
'visible': false | |
}, | |
{ | |
'label': 'Duplicate', | |
'handler': 'duplicateStrategy', | |
'visible': false | |
}, | |
{ | |
'label': 'Change log', | |
'handler': 'viewChangeLog', | |
'visible': false | |
}, | |
{ | |
'label': 'View Summary', | |
'visible': false | |
}, | |
{ | |
'label': 'CheckList', | |
'handler': 'showHealth', | |
'visible': true | |
}, | |
{ | |
'label': 'Deactivate', | |
'handler': 'deactivateHandler', | |
'visible': false | |
}, | |
{ | |
'label': 'Activate', | |
'handler': 'activateHandler', | |
'visible': false | |
} | |
] | |
} | |
] | |
}, | |
dataEvents: { | |
'model': { | |
'reset': 'reload', | |
'change:status': 'updateView', | |
'remove': 'unload', | |
'change:performanceDataArrived': 'performanceDataCompletedHandler' | |
}, | |
'campaign': { | |
'reset': 'reload', | |
'change:status': 'updateView', | |
'change:start_date': 'updateView', | |
'change:end_date': 'updateView' | |
} | |
}, | |
loaderOpts: { | |
contentClass: 'inline-edit-loader', | |
spinnerConfig: { | |
lines: 10, | |
length: 4, | |
radius: 3, | |
left: 15 | |
} | |
}, | |
eventhubEvents: { | |
'chart.add': function (data) { | |
var el = $('.chart-icon', this.el); | |
if (data.model) { | |
this.chartable = this.model.id === data.model.id; | |
if (this.chartable) { | |
el.removeClass('disabled'); | |
} else { | |
el.addClass('disabled'); | |
} | |
} | |
}, | |
'onCloseInlineEdit': function (event) { | |
var self = this; | |
if (event && event.view && event.view.cid === this.cid) { | |
self.updateView(); | |
} | |
}, | |
'change:reportInterval': 'changeReportInterval', | |
'onConfigClick': 'applyGearHover', | |
'onConfigDismiss': 'removeGearHover' | |
}, | |
events: { | |
'accordionaction .accordion': 'onAccordionAction', | |
'click .section .chart-icon': 'toggleForChart', | |
'mouseenter .spendMode .date-range .section-c': 'datesMouseEnterHandler', | |
'mouseleave .spendMode .date-range .section-c': 'datesMouseLeaveHandler', | |
'mouseenter .impressionMode .date-range .section-c': 'datesMouseEnterHandler', | |
'mouseleave .impressionMode .date-range .section-c': 'datesMouseLeaveHandler', | |
'summaryButtonClick': 'strategyButtonClickHandler', | |
'summaryPanelClose': 'summaryPanelCloseHandler', | |
'click .strategy-edit': 'editStrategy', | |
'contextmenu .strategy-edit-link': 'applyEditHover', | |
'mousemove .strategy': 'removeEditHover', | |
'contextmenu .strategy-actions-holder': 'stopEvent' | |
}, | |
initialize: function (args) { | |
var self = this; | |
var model = this.model; | |
var campaign = model.get('campaign'); | |
var campaignCollection = campaign.collection; | |
var isVideoStrategy = model.get('media_type') === 'VIDEO'; | |
var lazyLoadBadges; | |
//Allow inline-editing | |
model.allowInlineValidation = true; | |
self.asDecimalCurrency = T1.Utils.getDecimalCurrencyTemplateFunc(model.get('currency_code')); | |
self.isVideoStrategy = isVideoStrategy; | |
self.hasVideoPermission = T1Permissions.check('feature', 'video', model); | |
self.canEditStrategy = (T1Permissions.check('strategy.edit', model)); | |
self.canViewStrategy = (T1Permissions.check('strategy.readonly', model)); | |
self.canViewChangeLog = (T1Permissions.check('changeLog.view')); | |
self.strategyEditable = ((self.canEditStrategy === true && isVideoStrategy === false) || | |
(self.canEditStrategy === true && self.hasVideoPermission === true)); | |
self.viewModeFields = args.viewModeFields; | |
self.viewMode = args.viewMode; | |
goalMonitoringReport = 'rpt_goal_monitoring'; | |
totalSpend = 'total_spend'; | |
totalSpendEcpa = 'total_spend_ecpa'; | |
totalSpendEcpc = 'total_spend_ecpc'; | |
totalSpendEcpe = 'total_spend_ecpe'; | |
totalSpendEcpm = 'total_spend_ecpm'; | |
totalSpendRoi = 'total_spend_roi'; | |
self.layout = new T1Layout({ | |
el: function () { | |
return self.el; | |
}, | |
selectorPath: '.strategy-drawer', | |
layout: {} | |
}); | |
//initialize summary badges layout early so view would available | |
self.layout.append('.summary-badges', { | |
'module': 'strategy', | |
'viewType': 'summaryInfo', | |
options: { | |
model: self.model | |
} | |
}); | |
self.canEdit = T1Permissions.check('strategy.edit', model) && (isVideoStrategy ? | |
T1Permissions.check('feature', 'video') : true); | |
self.campaignCollection = campaignCollection; | |
self.campaign = campaign; | |
self.reportInterval = args.reportInterval; | |
self.currentGoalMode = args.currentGoalMode; | |
self.defaultDrawerExpandedState = args.defaultDrawerExpandedState; | |
lazyLoadBadges = this.lazyLoadBadges(); | |
T1.EventHub.subscribe('action:drawer:load-' + self.model.id, lazyLoadBadges); | |
}, | |
lazyLoadBadges: function () { | |
var self = this; | |
return _.debounce(function () { | |
var expandAction = self.isDrawerExpanded(); | |
if (!self.isBadgesDataLoaded || !expandAction) { | |
self.isBadgesDataLoaded = false; | |
self.fetchStrategyBadgesData(); | |
} else { | |
self.loadStrtegyBadges(); | |
} | |
}, 100); | |
}, | |
updateView: function () { | |
var $el = $(this.el); | |
var serialize = this.serialize(); | |
var renderQueue = ['1', '7', '14', '30', 'FTD', 'CTD']; | |
var i, addNoCapClass, impNoCapClass; | |
var freqCapValGroupNode = $el.find('.frequencyCapValGroup'); | |
var impCapValGroupNode = $el.find('.impCapValGroup'); | |
this.renderViewModes(renderQueue); | |
this.renderPartial('.item.accordion .name .name-part'); | |
for (i = 0; i < renderQueue.length; i++) { | |
this.attachDatePicker(renderQueue[i]); | |
} | |
this.updateDataBind({ | |
name: serialize.name, | |
type: serialize.type, | |
status_class: serialize.status_class, | |
statusTitle: serialize.statusTitle, | |
frequency_type: serialize.frequency_optimization ? 'T1 Optimized' : serialize.frequency_type, | |
frequency_amount: serialize.frequency_optimization ? '' : serialize.frequency_amount, | |
frequency_interval: serialize.frequency_optimization ? '' : serialize.frequency_interval, | |
frequency_optimization: serialize.frequency_optimization ? '1' : '0', | |
pacing_type: serialize.pacing_type, | |
pacing_amount: serialize.pacing_amount, | |
pacing_interval: serialize.pacing_interval, | |
impression_pacing_type: serialize.impression_pacing_type, | |
impression_pacing_amount: | |
$.trim(formatsRolledUpNumbersNoAbbreviation(serialize.impression_pacing_amount.replace(/,/g, ''))), | |
impression_pacing_interval: serialize.impression_pacing_interval, | |
roi_target: CampaignStrategyUtils.parseNumberToWhole(serialize.roi_target) + ':1' | |
}, this.el); | |
if (useNewFreqCap) { | |
// TODO: When new freq cap goes global, remove above test and below else block. | |
this.bindFrequencyCap(); | |
} else { | |
this.activateFrequencyCap(); | |
} | |
this.bindImpressionCap(); | |
this.prepareDataPoints(); | |
this.delegateEvents(); | |
this.prepareT1Menu(); //this is needed because the status change | |
addNoCapClass = serialize.frequency_type === frequencyNoLimitText; | |
freqCapValGroupNode.toggleClass('frequency-no-cap', addNoCapClass); | |
impNoCapClass = serialize.impression_pacing_type === impressionNoLimitText; | |
impCapValGroupNode.toggleClass('impression-no-cap', impNoCapClass); | |
this.updateDrawerExpander(); | |
}, | |
stopEvent: function (e) { | |
e.preventDefault(); | |
e.stopPropagation(); | |
}, | |
changeReportInterval: function (data) { | |
this.reportInterval = data.reportInterval; | |
}, | |
attachDatePicker: function (reportInterval) { | |
var self = this; | |
var currentInterval; | |
var model = this.model; | |
var campaign = model.get('campaign'); | |
var startDate = model.get('start_date'); | |
var hasStarted = CampaignStrategyUtils.hasEntityStarted(model); | |
var hasCampaignStarted = CampaignStrategyUtils.hasEntityStarted(campaign); | |
var modes = ['.spend', '.impression']; | |
_.each(modes, function(view) { | |
currentInterval = $('.views ' + view + reportInterval, self.el); | |
//Date picker only gets open in spend and impression mode. | |
//if strategy has use_campaign_start === "1" then we check if campaign has started becouse | |
//strategy date might be in the past | |
hasStarted = model.get('use_campaign_start') !== '0' ? hasCampaignStarted : hasStarted; | |
if (self.canEdit) { | |
T1.DoubleDatePicker({ | |
topOffset: 80, | |
leftOffset: 20, | |
chooseTime: true, | |
chooseTimezone: true, | |
zoneName: function () { | |
return campaign.get('zone_name'); | |
}, | |
timezoneEditable: false, | |
startTimeEditable: function () { | |
return !hasStarted; | |
}, | |
lowerBounds: function () { | |
return getDatePickerLowerBoundForStrategy(hasStarted, hasCampaignStarted, Date.parse(startDate), | |
model.get('use_campaign_start') !== '0' ? | |
Date.parse(campaign.get('initial_start_date')) : Date.parse(campaign.get('start_date'))); | |
}, | |
startDisabled: function () { | |
return hasStarted; | |
}, | |
defaultStartDate: function () { | |
return campaign.get('start_date'); | |
}, | |
defaultEndDate: function () { | |
return campaign.get('end_date'); | |
}, | |
defaultStartMessage: 'use campaign date', | |
useDefaultStart: parseInt(model.get('use_campaign_start'), 10), | |
useDefaultEnd: parseInt(model.get('use_campaign_end'), 10), | |
defaultEndMessage: 'use campaign date', | |
openPickerSelector: '.date-range .data', | |
getStartDate: function () { | |
return model.get('start_date'); | |
}, | |
getEndDate: function () { | |
return model.get('end_date'); | |
}, | |
onSave: function (args) { | |
var saveValues = args.data.saveValues; | |
var saveStartDate = campaign.get('start_date'); | |
var saveEndDate = campaign.get('end_date'); | |
var zoneName = campaign.get('zone_name'); | |
var loader = self.loader(); | |
var saveObj = { | |
use_campaign_start: saveValues.start.useDefault ? 1 : 0, | |
use_campaign_end: saveValues.end.useDefault ? 1 : 0 | |
}; | |
if (!saveObj.use_campaign_start) { | |
saveStartDate = saveValues.start.date; | |
} | |
if (!saveObj.use_campaign_end) { | |
saveEndDate = saveValues.end.date; | |
} | |
saveObj.start_date = saveObj.use_campaign_start === 0 ? saveStartDate + ' ' + zoneName : ''; | |
saveObj.end_date = saveObj.use_campaign_end === 0 ? saveEndDate + ' ' + zoneName : ''; | |
loader.start(); | |
self.model.save(saveObj, { | |
success: function () { | |
loader.stop(); | |
args.success(); | |
self.updateView.call(self); | |
}, | |
conflict: function () { | |
loader.stop(); | |
self.updateView.call(self); | |
}, | |
statusInvalid: function (data) { | |
loader.stop(); | |
args.error(data[0]); | |
} | |
}); | |
return true; | |
} | |
}, | |
currentInterval); | |
} | |
currentInterval.find('[data-datepicker]').trigger('mousedown.attachpicker'); | |
}); | |
}, | |
viewStrategySummary: function (e) { | |
T1.Location.set('#strategy/summary/' + this.model.id); | |
this.preventDefault(e); | |
}, | |
datesMouseEnterHandler: function (event) { | |
this.datesMouseEventHandler(event, true); | |
}, | |
datesMouseLeaveHandler: function (event) { | |
this.datesMouseEventHandler(event, false); | |
}, | |
datesMouseEventHandler: function (event, isMouseEnter) { | |
var $el = this.el; | |
var $currentTarget = $(event.currentTarget); | |
var $elDates = $el.find('.date-range .dates'); | |
var $elRemaining = $el.find('.days-remaining'); | |
var $targetToShow = isMouseEnter === true ? $elDates : $elRemaining; | |
var $targetToHide = isMouseEnter === true ? $elRemaining : $elDates; | |
var onHoverClass = this.canEdit === true ? 'onhover' : 'onhover-noedit'; | |
if (isMouseEnter === true) { | |
$currentTarget.addClass(onHoverClass); | |
} else { | |
$currentTarget.removeClass(onHoverClass); | |
} | |
$targetToShow.show(); | |
$targetToHide.hide(); | |
}, | |
onAccordionAction: function () { | |
//$(this.el).find(".accordion").toggleClass("selected"); | |
this.updateDrawerExpander(); | |
T1.EventHub.publish('action:drawerExpandContract', {}); | |
}, | |
updateDrawerExpander: function () { | |
var $accordion = $(this.el).find('.accordion'); | |
var needToAddExpendedClass, drawerView, viewList; | |
var drawerLayout = this.layout && this.layout.layout ? this.layout.layout : null; | |
needToAddExpendedClass = this.isDrawerExpanded(); | |
$accordion.find('.drawer-expander').toggleClass('expanded', needToAddExpendedClass); | |
//we need to close the in-line editor on the drawer view obj associated with this view - only | |
//if the drawer is being closed down. | |
if (needToAddExpendedClass !== true) { | |
viewList = drawerLayout ? drawerLayout['.strategy-drawer'] : null; | |
drawerView = viewList && $.isArray(viewList) && viewList.length > 0 ? viewList[0].view : null; | |
if (drawerView && drawerView.closeInlineEditor) { | |
drawerView.closeInlineEditor(true); | |
} | |
} | |
}, | |
fetchStrategyBadgesData: function () { | |
var self = this; | |
var view = self.layout.layout['.summary-badges'][0].view; | |
if (view) { | |
view.fetchData(true).then(function () { | |
self.loadStrtegyBadges(); | |
self.isBadgesDataLoaded(); | |
}); | |
} | |
}, | |
loadStrtegyBadges: function () { | |
this.layout.loadView('.summary-badges'); | |
}, | |
strategyButtonClickHandler: function () { | |
this.el.find('.cancel-action').click(); | |
this.$strategyList.addClass('strategy-badge-panel-open'); | |
this.$strategyListItem.addClass('strategy-badge-panel-open'); | |
}, | |
summaryPanelCloseHandler: function () { | |
this.$strategyList.removeClass('strategy-badge-panel-open'); | |
this.$strategyListItem.removeClass('strategy-badge-panel-open'); | |
}, | |
applyEditHover: function () { | |
this.el.find('.strategy-edit-holder').addClass('hover'); | |
}, | |
removeEditHover: function () { | |
this.el.find('.strategy-edit-holder').removeClass('hover'); | |
}, | |
applyGearHover: function (args) { | |
if (args && args.view && args.view.cid === this.cid) { | |
this.el.find('.strategy-actions-holder').addClass('hover'); | |
this.el.find('.strategy-edit-holder').addClass('suppress-hover'); | |
} | |
}, | |
removeGearHover: function () { | |
this.el.find('.strategy-actions-holder').removeClass('hover'); | |
this.el.find('.strategy-edit-holder').removeClass('suppress-hover'); | |
}, | |
expandCloseDrawer: function (toExpand) { | |
var self = this; | |
var $drawer = $(self.el).find('.accordion').parent().find('.drawer'); | |
var isExpanded = self.isDrawerExpanded(); | |
if ($drawer.length > 0 && toExpand !== isExpanded) { | |
//we ONLY take action if the current state is not what is desired | |
$drawer[(toExpand === true) ? 'show' : 'hide'](); | |
self.updateDrawerExpander(); | |
} | |
}, | |
isDrawerExpanded: function () { | |
var $drawer = $(this.el).find('.accordion').parent().find('.drawer'); | |
return $drawer.length > 0 && $drawer.css('display') !== 'none'; | |
}, | |
toggleForChart: function (event) { | |
var model = this.model; | |
this.stopEvent(event); | |
this.chartable = true; | |
T1.EventHub.publish('chart.add', { model: model }); | |
return false; | |
}, | |
prepareDataPoints: function () { | |
var $el = $(this.el); | |
T1.Tooltip($el.find('.pointer'), { | |
offset: '4' | |
}); | |
T1.Tooltip($el.find('.label')); | |
}, | |
load: function () { | |
var self = this; | |
var $el = this.el; | |
var $freqAmt, serialize; | |
self.render().then(function () { | |
self.prepareT1Menu(); | |
self.attachDatePicker(self.reportInterval); | |
self.$strategyList = $el.closest('.w-StrategyList'); | |
self.$strategyListItem = $el.find('.w-StrategyListItem'); | |
setTimeout(function () { | |
self.performanceDataCompletedHandler(); | |
}, 0); | |
serialize = self.serialize(); | |
$freqAmt = $el.find('[data-bind=frequency_amount]'); | |
if (!serialize.frequency_amount || serialize.frequency_amount === '0') { | |
$freqAmt.data('current-value', '1'); | |
} else { | |
$freqAmt.data('current-value', serialize.frequency_amount + ''); | |
} | |
}); | |
self.layout.append('.strategy-drawer', { | |
'module': 'strategy', | |
'viewType': 'drawer', | |
options: { | |
model: self.model, | |
defaultDrawerExpandedState: self.defaultDrawerExpandedState | |
} | |
}).then(function () { | |
setTimeout(function () { | |
self.updateDrawerExpander(); | |
}, 200); | |
}); | |
}, | |
unload: function () { | |
this.$strategyList = null; | |
this.$strategyListItem = null; | |
T1.EventHub.unsubscribe('action:drawer:load-' + this.model.id); | |
}, | |
performanceDataCompletedHandler: function () { | |
var self = this; | |
var i; | |
var renderQueue = ['1', '7', '14', '30', 'FTD', 'CTD']; | |
//we only check the ready switch before rendering for rpt-perf-data users. | |
//will remove this outer 'if' condition once this feature is no longer hidden | |
//behind the currency feature flag. the reason is, the call can come from data | |
//notification and render method - we check to ensure this runs only once. | |
if (self.model.get('perfDataReady') !== true) { | |
return; | |
} else { | |
self.model.set({ 'perfDataReady': false }); | |
} | |
renderQueue = _.without(renderQueue, self.reportInterval); | |
self.delayedRender(renderQueue); | |
if (useNewFreqCap) { | |
// TODO: When new freq cap goes global, remove above test and below else block. | |
self.bindFrequencyCap(); | |
} else { | |
self.activateFrequencyCap(); | |
} | |
self.bindImpressionCap(); | |
self.activateFrequencyCap(); | |
for (i = 0; i < renderQueue.length; i++) { | |
self.attachDatePicker(renderQueue[i]); | |
} | |
T1.EventHub.publish('strategies:itemLoaded'); | |
}, | |
prepareT1Menu: function () { | |
var self = this; | |
var model = self.model; | |
var isVideoStrategy = self.isVideoStrategy; | |
var hasVideoPermission = self.hasVideoPermission; | |
var canEditStrategy = self.canEditStrategy; | |
var canViewStrategy = self.canViewStrategy; | |
var canViewChangeLog = self.canViewChangeLog; | |
var menuConfig = $.extend(true, {}, self.menuConfig); | |
var menuItems = menuConfig.menuColumns[0].menuItems; | |
var menuIndexRef = { | |
'Edit': 0, | |
'ViewSummary': 1, | |
'Duplicate': 2, | |
'ChangeLog': 3, | |
'ViewReadOnly': 4, | |
'CheckList': 5, | |
'Deactivate': 6, | |
'Activate': 7 | |
}; | |
self.el.find(menuConfig.menuTriggerEleSelector).off(); | |
if (canViewChangeLog === true) { | |
menuItems[menuIndexRef.ChangeLog].visible = true; | |
} | |
if ((canEditStrategy === true && isVideoStrategy === false) || | |
(canEditStrategy === true && hasVideoPermission === true)) { | |
menuItems[menuIndexRef.Edit].visible = true; | |
menuItems[menuIndexRef.Edit].url = '#strategy/edit/' + model.id; | |
menuItems[menuIndexRef.ViewSummary].visible = true; | |
menuItems[menuIndexRef.ViewSummary].url = '#strategy/summary/' + model.id; | |
menuItems[menuIndexRef.Duplicate].visible = true; | |
//we need to dynamically set the deactivate/activate menu command according to the current model status | |
//we only do so if campaign level is active | |
if (self.campaign && self.campaign.get('status') === '1') { | |
if (model.get('status') === '0') { | |
menuItems[menuIndexRef.Activate].visible = true; | |
} else { | |
menuItems[menuIndexRef.Deactivate].visible = true; | |
} | |
} | |
} else if (canViewStrategy === true || (isVideoStrategy === true)) { | |
menuItems[menuIndexRef.ViewReadOnly].visible = true; | |
menuItems[menuIndexRef.ViewReadOnly].url = '#strategy/readonly/' + model.id; | |
} | |
T1Menu(menuConfig, self); | |
}, | |
editStrategy: function (event) { | |
var id = this.model.id; | |
this.stopEvent(event); | |
T1.Location.set('strategy/edit/' + id + '/details'); | |
}, | |
// TODO: When new freq cap goes global, remove this method | |
activateFrequencyCap: function () { | |
T1.Tooltip(this.el, { | |
getExternalTip: true, | |
tooltipEle: '.frequency-cap-icon', | |
className: 'w-StrategyFrequencyCap' | |
}); | |
this.bindFrequencyCap(); | |
}, | |
renderViewModes: function (queue) { | |
var self = this; | |
var el = self.el; | |
var selector, dataset, i, j; | |
var selectors = queue; | |
var modes = ['.spend', '.impression', '.performance']; | |
for (i = 0; i < modes.length; i++) { | |
for (j = 0; j < selectors.length; j++) { | |
dataset = this.serialize(selectors[j]); | |
selector = modes[i] + selectors[j]; | |
self.renderPartialTemplate({ | |
templateTarget: selector, | |
targetEl: el.find(selector), | |
data: dataset, | |
context: el, | |
template: template, | |
partials: self.partials, | |
skipDelegateEvents: true | |
}); | |
} | |
} | |
}, | |
getTimeStamp: function (dateObj) { | |
var dt = dateObj || new Date(); | |
return dt.getHours() + ':' + dt.getMinutes() + ':' + dt.getSeconds() + ':' + dt.getMilliseconds(); | |
}, | |
bindFrequencyCap: function () { | |
var $el = $(this.el); | |
var $frequencyEl = $('.budget', this.el); | |
var model = this.model; | |
$('.editable-content', $frequencyEl).on('click', function () { | |
function onFrequencyCapEdit() { | |
var $groupEditEl = $('.w-GroupInlineEditForm', $frequencyEl); | |
var freqType = (model.get('frequency_optimization') === '1') ? 'standard' : model.get('frequency_type'); | |
frequencyCap($groupEditEl, freqType); | |
$el.unbind('inlineFormEdit.open', onFrequencyCapEdit); | |
} | |
$el.bind('inlineFormEdit.open', onFrequencyCapEdit); | |
}); | |
}, | |
bindImpressionCap: function () { | |
var self = this; | |
var $el = $(this.el); | |
var modeInterval = '.impression' + this.reportInterval; | |
var $impressionEl = $el.find('.views').find(modeInterval).find('.remaining'); | |
var model = this.model; | |
$('.editable-content', $impressionEl).on('click', function () { | |
function onImpressionCapEdit() { | |
var $groupEditEl = $('.w-GroupInlineEditForm', $impressionEl); | |
var impType = model.get('impression_pacing_type'); | |
var notRMX = (self.model.get('supply_type') !== 'RMX_API'); | |
impressionCap($groupEditEl, impType, notRMX); | |
$el.unbind('inlineFormEdit.open', onImpressionCapEdit); | |
} | |
$el.bind('inlineFormEdit.open', onImpressionCapEdit); | |
}); | |
}, | |
editElementBindings: { | |
'pacing_type': { | |
'type': 'change', | |
'action': function (e) { | |
var target = $(e.currentTarget); | |
if (target.val() === 'asap') { | |
$('<div>' + pacingASAPCaution + '</div>').dialog({ | |
'autoOpen': true, | |
'modal': true, | |
'title': '<b></b>ASAP pacing confirmation', | |
'dialogClass': 'w-PacingASAPAlert', | |
'buttons': [ | |
{ | |
'text': 'Confirm', | |
'class': 'confirm', | |
'click': function () { | |
$(this).dialog('close'); | |
} | |
}, | |
{ | |
'text': 'Cancel', | |
'class': 'cancel', | |
'click': function () { | |
target.val('even').trigger('liszt:updated'); | |
$(this).dialog('close'); | |
} | |
} | |
], | |
'close': function () { | |
$(this).remove(); | |
} | |
}); | |
} | |
} | |
}, | |
'frequency_type': { | |
'type': 'change', | |
'action': function (e) { | |
var target = $(e.currentTarget); | |
var $groupEditEl = target.closest('.w-GroupInlineEditForm'); | |
frequencyCap($groupEditEl, target.val()); | |
} | |
}, | |
'impression_pacing_type': { | |
'type': 'change', | |
'action': function (e) { | |
var target = $(e.currentTarget); | |
var $groupEditEl = target.closest('.w-GroupInlineEditForm'); | |
impressionCap($groupEditEl, target.val()); | |
if (target.val() === 'asap') { | |
$('<div>' + impPacingASAPCaution + '</div>').dialog({ | |
'autoOpen': true, | |
'modal': true, | |
'title': '<b></b>ASAP pacing confirmation', | |
'dialogClass': 'w-PacingASAPAlert', | |
'buttons': [ | |
{ | |
'text': 'Confirm', | |
'class': 'confirm', | |
'click': function () { | |
$(this).dialog('close'); | |
} | |
}, | |
{ | |
'text': 'Cancel', | |
'class': 'cancel', | |
'click': function () { | |
target.val('even').trigger('liszt:updated'); | |
$(this).dialog('close'); | |
} | |
} | |
], | |
'close': function () { | |
$(this).remove(); | |
} | |
}); | |
} | |
} | |
} | |
}, | |
delayedRender: function (list) { | |
var self = this; | |
self.renderViewModes(list); | |
self.prepareDataPoints.call(self); | |
self.delegateEvents(); | |
}, | |
deactivateHandler: function (e) { | |
this.preventDefault(e); | |
this.activationHandler(false); | |
}, | |
activateHandler: function (e) { | |
this.preventDefault(e); | |
this.activationHandler(true); | |
}, | |
activationHandler: function (toActivate) { | |
var strategy = this.model; | |
var loader = this.loader(); | |
var status = (toActivate === true) ? '1' : '0'; | |
function stopLoader() { | |
loader.stop(); | |
} | |
loader.start(); | |
strategy.save({ 'status': status }, { | |
success: stopLoader, | |
conflict: stopLoader | |
}); | |
}, | |
showHealth: function (event) { | |
var strategy = this.model; | |
//close settings menu | |
$(document).trigger('click'); | |
this.stopEvent(event); | |
this.layout.append('.healthDialogue', { | |
'module': 'strategy', | |
'viewType': 'health', | |
'options': { | |
model: strategy | |
} | |
}); | |
}, | |
duplicateStrategy: function (e) { | |
var strategy = this.model; | |
//close settings menu | |
$(document).trigger('click'); | |
this.stopEvent(e); | |
this.layout.append('.duplicationDialog', { | |
'module': 'strategy', | |
'viewType': 'duplicateStrategy', | |
'options': { | |
model: strategy | |
} | |
}); | |
}, | |
viewChangeLog: function (e) { | |
var strategy = this.model; | |
//close settings menu | |
$(document).trigger('click'); | |
this.stopEvent(e); | |
this.layout.append('.changeDialog', { | |
'module': 'changelog', | |
'viewType': 'dialog', | |
'options': { | |
model: strategy, | |
entityType: 'strategy' | |
} | |
}); | |
}, | |
serializeAdditionalInformation: function (interval) { | |
var self = this; | |
var model = self.model; | |
var campaign = self.campaign; | |
var info = model.get(goalMonitoringReport); | |
var dataset = {}; | |
var start, end, loadDate, pacingRatio, start_date, end_date, budgetInformation, reports, | |
currentReportInterval, ctdReport, fieldNameForCampaignGoalPerformace, campaignPerformanceAlert, | |
strategyPerformanceAlert; | |
var startOffsetX = 5; | |
var outPacingRange = 10; | |
var coloredBarWidth = 95; | |
var effectivePerformanceField = { | |
'cpa': totalSpendEcpa, | |
'cpc': totalSpendEcpc, | |
'cpe': totalSpendEcpe, | |
'roi': totalSpendRoi | |
}; | |
var showImpCounts = true; | |
reports = {}; | |
$.each(info.toJSON(), function (index, report) { | |
reports[report.mm_interval] = report; | |
}); | |
/* | |
* Calculation for the dates & duration start | |
*/ | |
start_date = (model.get('use_campaign_start') !== '0') ? | |
campaign.get('initial_start_date') : model.get('start_date'); | |
end_date = (model.get('use_campaign_end') !== '0') ? campaign.get('end_date') : model.get('end_date'); | |
start = Date.parse(start_date); | |
end = Date.parse(end_date); | |
loadDate = reports.CTD && reports.CTD.load_date ? Date.parse(reports.CTD.load_date) : new Date(); | |
function getTipDate(dateObj) { | |
return Date.CultureInfo.abbreviatedMonthNames[dateObj.getMonth()] + ' ' + dateObj.getDate(); | |
} | |
if (T1.compareDates(start, end) !== 1) { | |
if (T1.compareDates(start, loadDate) === 1) { | |
dataset.tip_date = getTipDate(start); | |
pacingRatio = 0; | |
showImpCounts = false; | |
} else if (T1.compareDates(loadDate, end) === 1) { | |
pacingRatio = 100; | |
showImpCounts = false; | |
} else { | |
dataset.tip_date = getTipDate(loadDate); | |
pacingRatio = divideByZero(100 * (loadDate.getTime() - start.getTime()) / (end.getTime() - start.getTime())); | |
showImpCounts = true; | |
} | |
} | |
dataset.imp_count_ydy = showImpCounts && reports['1'].imp_count ? | |
$.trim(formatsRolledUpNumbersNoAbbreviation(reports['1'].imp_count)) : '--'; | |
end_date = (model.get('use_campaign_end') !== '0') ? campaign.get('end_date') : model.get('end_date'); | |
dataset.days_remaining = Math.ceil((end.valueOf() - T1.Date.parse('today')) / 86400000); | |
dataset.days_remaining = dataset.days_remaining > 0 ? dataset.days_remaining : 0; | |
/* | |
* Calculation for the dates & duration end | |
*/ | |
dataset.durationRatio = Math.round(startOffsetX + (coloredBarWidth - startOffsetX) * (pacingRatio / 100)); | |
dataset.displayPointer = pacingRatio === 100 || !dataset.durationRatio ? 'none' : 'block'; | |
//return the dataset if reporting data unavailable | |
if (!info.length) { | |
//default coloredBarWidth is set to 0 | |
dataset.coloredBarWidth = 0; | |
return dataset; | |
} | |
currentReportInterval = reports[interval] || {}; | |
function getCurrentReportValue(fieldName) { | |
return currentReportInterval[fieldName] || ''; | |
} | |
function getCurrentReportFormattedValueNoAbbreviation(fieldName) { | |
return currentReportInterval[fieldName] ? | |
$.trim(formatsRolledUpNumbersNoAbbreviation(currentReportInterval[fieldName])) : ''; | |
} | |
ctdReport = reports.CTD || {}; | |
dataset.daily_spend_to_pace = ctdReport.daily_spend_to_pace || '--'; | |
dataset.mm_goal_performance = getCurrentReportValue('mm_goal_performance'); | |
//performance view mode | |
dataset.daily_spend_to_pace = ctdReport.daily_spend_to_pace || '--'; | |
dataset.total_conversion_count = getCurrentReportFormattedValueNoAbbreviation('total_conversion_count'); | |
dataset.clicks_count = getCurrentReportFormattedValueNoAbbreviation('clicks_count'); | |
dataset.imp_count = getCurrentReportFormattedValueNoAbbreviation('imp_count'); | |
dataset.totalSpendEcpa = getCurrentReportValue(totalSpendEcpa); | |
dataset.totalSpendEcpc = getCurrentReportValue(totalSpendEcpc); | |
dataset.totalSpendEcpm = getCurrentReportValue(totalSpendEcpm); | |
dataset.totalSpendRoi = getCurrentReportValue(totalSpendRoi); | |
dataset.mm_ctr = currentReportInterval.mm_ctr ? currentReportInterval.mm_ctr + '%' : '--'; | |
dataset.mm_ctc = currentReportInterval.mm_ctc ? currentReportInterval.mm_ctc + '%' : '--'; | |
/** | |
* Calculations for the budget start | |
* */ | |
if (typeof model.getBudgetInformation === 'function') { | |
dataset.budgetInformation = budgetInformation = model.getBudgetInformation(); | |
} else { | |
dataset.budgetInformation = budgetInformation = model.get('campaign').getBudgetInformation(); | |
} | |
dataset.spent = budgetInformation.budget_spent || ''; | |
dataset.budgetMeterLabel = budgetInformation.budget_remaining; | |
dataset.total_budget = budgetInformation.total_budget; | |
/** | |
* Calculations for the budget end | |
* */ | |
dataset.campaignEffectiveGoalValue = campaign.get('goal_value'); | |
dataset.strategyEffectiveGoalValue = model.get('goal_value'); | |
dataset.strategyEffectiveGoalValueRoi = model.get('roi_target'); | |
fieldNameForCampaignGoalPerformace = effectivePerformanceField[campaign.get('goal_type')]; | |
//As per Jason in ticket CS-212- In strategies we are using | |
//CTD ONLY to show info in Pacing Bar and Actual Performance | |
dataset.campaignEffectiveGoalPerformance = getCurrentReportValue(fieldNameForCampaignGoalPerformace || | |
totalSpendEcpm); | |
dataset.strategyEffectiveGoalPerformance = dataset.mm_goal_performance; | |
if (model.get('goal_type') === 'roi') { | |
campaignPerformanceAlert = parseFloat(dataset.campaignEffectiveGoalPerformance) < | |
(parseFloat(dataset.campaignEffectiveGoalValue) / 1.25); | |
strategyPerformanceAlert = parseFloat(dataset.strategyEffectiveGoalPerformance) < | |
(parseFloat(dataset.strategyEffectiveGoalValueRoi) / 1.25); | |
} else { | |
campaignPerformanceAlert = parseFloat(dataset.campaignEffectiveGoalPerformance) > | |
(parseFloat(dataset.campaignEffectiveGoalValue) * 1.25); | |
strategyPerformanceAlert = parseFloat(dataset.strategyEffectiveGoalPerformance) > | |
(parseFloat(dataset.strategyEffectiveGoalValue) * 1.25); | |
} | |
dataset.campaignPerformanceAlert = campaignPerformanceAlert ? 'alert-item' : ''; | |
dataset.strategyPerformanceAlert = strategyPerformanceAlert ? 'alert-item' : ''; | |
dataset.totalSpend = getCurrentReportValue(totalSpend); | |
dataset.totalSpend_YDY = reports['1'] ? reports['1'][totalSpend] : ''; | |
//dependent on partial calculation | |
dataset.spend_remaining = budgetInformation.total_budget - dataset.spent; | |
dataset.budgetMeterLabel = dataset.spend_remaining; | |
//done on UI since we need blank out put when there is no data | |
dataset.budgetMeterLabel = T1.Utils.formatCurrency(dataset.budgetMeterLabel.toString(), '', | |
self.getCurrencyCode()); | |
dataset.daily_spend_to_pace = divideByZero(dataset.spend_remaining / dataset.days_remaining, true); | |
dataset = populatePerformanceAlert(dataset); | |
dataset.coloredBarWidth = budgetInformation.percnt_budget_spent ? | |
startOffsetX + Math.round(budgetInformation.percnt_budget_spent * ((coloredBarWidth - startOffsetX) / 100)) : 0; | |
dataset.coloredBarWidth = dataset.coloredBarWidth > coloredBarWidth ? coloredBarWidth : dataset.coloredBarWidth; | |
dataset.coloredBarClass = Math.abs(budgetInformation.percnt_budget_spent - pacingRatio) >= outPacingRange ? | |
'out-pacing' : 'pacing'; | |
return dataset; | |
}, | |
serializeFrequencyCapInfo: function (dataset) { | |
var self = this; | |
var model = self.model; | |
var campaignDataset = model.get('campaign').toJSON(); | |
var advertiserDataset = campaignDataset.advertiser; | |
var useT1Optimized = model.get('frequency_optimization'); | |
var frequencyType = model.get('frequency_type'); | |
var frequencyInterval = model.get('frequency_interval'); | |
var goalType = model.get('goal_type'); | |
var isRMXAPI = model.get('supply_type') === 'RMX_API'; | |
var isNoLimit = (frequencyType === 'no-limit' || useT1Optimized !== '0'); | |
var campaignCap = useCampFreqCap(campaignDataset); | |
var strategyCap = useT1Optimized === '0'; | |
var impType = model.get('impression_pacing_type'); | |
var isNoImpLimit = impType === 'no-limit'; | |
dataset.frequency_interval = (isRMXAPI && enableTrackingSupplyTypeFeatureFlag) ? | |
'' : frequencyIntervalDisplayText[frequencyInterval]; | |
dataset.isBidPrice = (goalType === 'spend'); | |
dataset.isNoLimit = isNoLimit; | |
//fill in tool tip data | |
dataset.frequency_cap_frequency_header = 'Campaign Cap: '; | |
dataset.frequency_cap_frequency_type = campaignDataset.frequency_type; | |
dataset.frequency_cap_frequency_amount = campaignDataset.frequency_amount; | |
dataset.frequency_cap_frequency_interval = campaignDataset.frequency_interval; | |
dataset.campaignCap = campaignCap; | |
if (campaignDataset.frequency_optimization === '1') { | |
dataset.upstream_cap_text = dataset.frequency_cap_frequency_header + 'T1 Optimized'; | |
} else if (dataset.frequency_cap_frequency_type !== 'no-limit') { | |
dataset.upstream_cap_text = dataset.frequency_cap_frequency_header + | |
((dataset.frequency_cap_frequency_type.toLowerCase() === 'asap') ? | |
dataset.frequency_cap_frequency_type.toUpperCase() : toInitialCaps(dataset.frequency_cap_frequency_type)) + | |
' ' + dataset.frequency_cap_frequency_amount + ' per ' + | |
toInitialCaps(dataset.frequency_cap_frequency_interval); | |
} | |
// TODO when new freq cap goes global, remove useNewFreqCap from test below | |
dataset.upstream_cap = campaignCap || (useNewFreqCap && campaignDataset.frequency_optimization === '1'); | |
if (advertiserDataset && advertiserDataset.frequency_type !== 'no-limit') { | |
dataset.upstream_cap_text = (dataset.upstream_cap_text) ? dataset.upstream_cap_text + '<br />' : ''; | |
dataset.upstream_cap_text += 'Advertiser Cap: ' + ((advertiserDataset.frequency_type.toLowerCase() === 'asap') ? | |
advertiserDataset.frequency_type.toUpperCase() : toInitialCaps(advertiserDataset.frequency_type)) + ' ' + | |
advertiserDataset.frequency_amount + ' per ' + toInitialCaps(advertiserDataset.frequency_interval); | |
dataset.upstream_cap = true; | |
} | |
if (!dataset.upstream_cap_text) { | |
dataset.upstream_cap = false; | |
} | |
if (isNoLimit || (!strategyCap && campaignCap)) { | |
dataset.frequency_type = frequencyNoLimitText; | |
dataset.frequencyNoCapClass = 'frequency-no-cap'; | |
} | |
if (isNoImpLimit) { | |
dataset.impression_pacing_type = self.model.get('supply_type') === 'RMX_API' ? '--' : impressionNoLimitText; | |
dataset.impNoCapClass = 'impression-no-cap'; | |
} | |
if (!campaignCap) { | |
//not using the campaign cap so hide the icon | |
dataset.freq_cap_state = 'frequency-cap-icon-hide'; | |
} | |
dataset.frequency_optimization = useT1Optimized === '1'; | |
}, | |
serialize: function (interval) { | |
var self = this; | |
var model = this.model; | |
var dateFormat = 'MM/dd/yy'; | |
var campaign = this.campaign; | |
var dataset = model.toJSON(); | |
var filler = '--'; | |
var start_date, end_date, spaces; | |
var campaign_status = parseInt(campaign.get('status'), 10); | |
var status = parseInt(dataset.status, 10); | |
var isActive = (campaign_status && status) ? true : false; | |
var statusTitle = (isActive) ? statusActiveTitle : statusInactiveTitle; | |
var reportInterval = interval || self.reportInterval; | |
var isCustom = this.chartable; | |
var isBatch = (model.get('supply_type') === 'BATCH'); | |
start_date = (dataset.use_campaign_start !== '0') ? campaign.get('initial_start_date') : dataset.start_date; | |
end_date = (dataset.use_campaign_end !== '0') ? campaign.get('end_date') : dataset.end_date; | |
dataset.startDateAsString = T1.Date.parse(start_date) ? | |
T1.Date.parse(start_date).toString(dateFormat) : | |
filler; | |
dataset.endDateAsString = T1.Date.parse(end_date) ? | |
T1.Date.parse(end_date).toString(dateFormat) : | |
filler; | |
dataset.readOnlyTitle = (self.canEdit) ? '' : readOnlyTitle; | |
dataset.currentStatusTitle = statusTitle; | |
dataset.status_class = function (target) { | |
var inactiveClass = 'inactive'; | |
var result = (!isActive) ? inactiveClass : ''; | |
if (target) { | |
$(target).toggleClass(inactiveClass, !isActive); | |
} | |
return result; | |
}; | |
dataset.statusTitle = function (target) { | |
$(target).attr('title', statusTitle); | |
return statusTitle; | |
}; | |
dataset.isActive = isActive; | |
dataset.typeInfo = (self.currentGoalMode === 'campaignGoal') ? campaign.get('goal_type') : dataset.goal_type; | |
dataset.strategyTypeInfo = dataset.goal_type === 'roi' ? 'ROI' : dataset.goal_type; | |
dataset.campaignTypeInfo = campaign.get('goal_type') === 'roi' ? 'ROI' : campaign.get('goal_type'); | |
dataset.chart_class = (isCustom) ? '' : 'disabled'; | |
dataset.chartActionTitle = addToChartTitle; | |
dataset = $.extend(dataset, self.serializeAdditionalInformation(reportInterval)); | |
dataset.hasFrequencyCap = !isBatch; | |
this.serializeFrequencyCapInfo(dataset); | |
dataset.hasBatchPacing = !isBatch; | |
dataset.defaultText = function () { | |
return function (text) { | |
return (text === '') ? ' --' : text; | |
}; | |
}; | |
dataset.pacing_interval_value = dataset.pacing_interval; | |
dataset.pacing_interval = frequencyIntervalDisplayText[dataset.pacing_interval] || ''; | |
dataset.impression_pacing_interval = frequencyIntervalDisplayText[dataset.impression_pacing_interval] || ''; | |
dataset.impression_pacing_amount = $.trim(formatsRolledUpNumbersNoAbbreviation(dataset.impression_pacing_amount)); | |
dataset.hasMaxBid = dataset.use_optimization === '1'; | |
dataset.isStrategyROI = dataset.goal_type === 'roi'; | |
dataset.roi_target = CampaignStrategyUtils.parseNumberToWhole(dataset.roi_target) + ':1'; | |
// cantEditRoi it temp var to not allow user edit roi_target and should be removed | |
//when the feature flag becomes absolite | |
dataset.asDecimalCurrency = this.asDecimalCurrency; | |
if (dataset.strategyTypeInfo === 'ROI' && dataset.strategyEffectiveGoalPerformance) { | |
dataset.isTypeROI = true; | |
} | |
dataset.showStrategyEdit = this.strategyEditable; | |
// TODO: When new freq cap goes global, remove next line | |
dataset.useNewFreqCap = useNewFreqCap; | |
if (dataset.frequency_optimization && model.get('supply_type') !== 'RMX_API') { | |
dataset.frequency_type = 'T1 Optimized'; | |
dataset.frequency_amount = ''; | |
dataset.frequency_interval = ''; | |
} | |
if (enableTrackingSupplyTypeFeatureFlag) { | |
dataset.enableTrackingSupplyTypeFeatureFlag = model.get('supply_type') === 'RMX_API'; | |
if (dataset.enableTrackingSupplyTypeFeatureFlag) { | |
dataset.isStrategyROI = false; | |
dataset.goal_type = 'tracker'; | |
dataset.goal_value = ''; | |
dataset.strategyEffectiveGoalPerformance = filler; | |
dataset.frequency_type = filler; | |
dataset.pacing_amount = filler; | |
dataset.frequency_amount = ''; | |
} | |
} | |
if (dataset.goal_type === 'vcr' || dataset.goal_type === 'ctr') { | |
dataset.goal_type_is_percentage = true; | |
if (dataset.goal_value.length > 2) { | |
dataset.goal_value = dataset.goal_value.substring(0, dataset.goal_value.length - 2); | |
} | |
if (dataset.goal_type === 'ctr' && this.campaign.get('goal_type') === 'ctr') { | |
dataset.strategyEffectiveGoalPerformance = this.campaign.get('goal_value'); | |
if (dataset.strategyEffectiveGoalPerformance.length > 2) { | |
dataset.strategyEffectiveGoalPerformance = dataset.strategyEffectiveGoalPerformance.substring( | |
0, dataset.strategyEffectiveGoalPerformance.length - 2); | |
} | |
dataset.effective_goal_value_is_percentage = true; | |
} else { | |
dataset.effective_goal_value_is_percentage = false; | |
} | |
} else { | |
dataset.goal_type_is_percentage = false; | |
} | |
// CAW-2091 - We now allow long names to wrap, and by default we prefer to break on spaces (of course). | |
// However, some clients use long names with no spaces (typically underscores instead) so for them we | |
// need to allow word breaks. | |
// CAW-2506 - Modified wrapping logic to only normal-wrap if there are 3 or more spaces... Otherwise break-all | |
spaces = (dataset.name.match(/\s/g) || []).length; | |
dataset.wordBreakName = !(spaces > 2); | |
dataset.useNewFreqCapAndEnableTrackingSupplyTypeFeatureFlag = dataset.useNewFreqCap || | |
dataset.enableTrackingSupplyTypeFeatureFlag; | |
return dataset; | |
} | |
}); | |
return T1Form.InlineEdit(ItemView, dropdownList); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment