Controllers.prototype.manageCampaign = (function () {
return newManageCampaign;
function newManageCampaign(c, t, d, rCb, tmplCpm, cmpVal, dftVal) { return new ManageCampaign(c, t, d, rCb, tmplCpm, cmpVal, dftVal); }
function ManageCampaign(core, target, data, returnCB, templateCampaign, campaignValue, draftValue) {
var uf = null,
bf = null,
events = new EventManager,
focusDefined = isDefined(campaignValue),
template = getTemplate(focusDefined && !templateCampaign, draftValue),
appsList = null,
data = null,
element = null,
elements = null,
forecast = null;
new DataManager(core.userID, focusDefined || !!draftValue, campaignValue, draftValue, templateCampaign, init);
this.exit = exit;
function Data(d, id, core) {
var impBudget = getValue(d, "impBudget", 0);
// Not accessed by the UI
this.id = d.id || id;
// Main
this.active = getValue(d, 'active', true);
this.archived = getValue(d, 'archived');
this.name = getValue(d, 'name');
this.notes = getValue(d, 'notes');
this.budget = getValue(d, "budget", 0);
this.impBudget = impBudget;
this.budgetType = impBudget == 0 ? "credits" : "impressions";
this.optBucket = getValue(d, 'optBucket', 0);
this.keywords = getValue(d, 'keywords', []);
this.placement = getValue(d, 'placement');
this.scheduled = getValue(d, 'scheduled', false);
this.start = getValue(d, 'start', 0);
this.end = getValue(d, 'end', 0);
// Segments
this.segments = getValue(d, 'segments');
// Adgroups
this.adGroups = getValue(d, 'adGroups');
// Misc not related to a standard campaign
this.type = getValue(d, 'type', 'meteora');
this.remoteID = getValue(d, 'remoteID');
// Apps
this.apps = getApps(d);
var originalKeys = Object.keys(this); // used by the clean func
// Used by JS front-end for certain messages and notifications.
// This data will not be processed by the back-end.
this.originalBudget = getValue(d, "budget", -1);
this.originalBudgetType = getValue(d, "budgetType", "");
this.originalStart = getValue(d, "start");
this.originalEnd = getValue(d, "end");
this.billing = getValue(d, "billing", null);
this.profiles = getValue(d, "profiles", null);
this.pixelFired = didThePixelFireToday(d.lastPixelHit);
this.brand = core.brand;
// Full lists
this.lists = d.lists;
this.ioState = d.ioState.has === true;
this.forecast = (d.campaignForecast || d.campaignDraftForecast || { forecast: null }).forecast;
// clean returns a clean Data object without all the extra things we add to it for the UI
this.clean = function (d) { // Can't wait for typescript
var cp = {};
loop(originalKeys, function (_, key) {
var val = d[key];
if (val != null) {
cp[key] = val;
}
});
return cp;
};
function getValue(d, k, r) { if (r === undefined) r = null; if (isDefined(d) && isDefined(d[k])) return d[k]; else return r; }
function getApps(d) {
var empty = !isDefined(d.apps),
apps = getValue(d, 'apps', {});
if (campaignValue === null && draftValue === null || empty) {
setApp('pacing');
setApp('geography');
setApp('weather');
setApp('college');
setApp('domainTargeting');
setApp('frequencyCap');
setApp('contentCategories');
setApp('ipTargeting');
}
var qv = getQueryVariables();
if (!!qv.apps) {
var qvApps = qv.apps.split(",");
loop(qvApps, function (k, v) { setApp(v); });
}
return apps;
function setApp(k) {
if (!isDefined(apps[k])) { apps[k] = {}; }
}
}
}
function init(error, d) {
appsList = d['apps/list/short'] || {};
if (d.campaignDraftForecast) {
forecast = d.campaignDraftForecast.forecast;
} else if (d.campaignForecast) {
forecast = d.campaignForecast.forecast;
}
if (hasElements(d.adGroupsList) && hasElements(d.segmentsList)) {
element = getElementFromString(template);
data = new Data(getFocusObj(d), campaignValue, core);
setElements(d);
setFns(d);
setTabbedWin(data, d);
events.add(element.querySelector('.saveButton'), 'click', save);
if (!!elements.addAnother) events.add(elements.addAnother, 'click', addAnother);
if (!!elements.saveDraft) events.add(elements.saveDraft, 'click', draft);
target.appendChild(element);
} else {
element = baseFresh(d, target).element;
}
returnCB();
function hasElements(arr) { return isArray(arr) && arr.length > 0; }
}
function getFocusObj(d) {
var o = {};
if (!!d.campaigns) {
o = d.campaigns.data;
} else if (!!d.campaignTemplate) {
o = d.campaignTemplate.settings;
}
o.billing = d.billing;
o.profiles = d.profiles;
o.lastPixelHit = d.lastPixelHit;
o.lists = {
'segments': getSegments(d.segmentsList, d.proximityList.data, d.evegmentsList, d.kochava, d.ifaSegments),
'adGroups': d.adGroupsList
};
o.ioState = d.ioState;
return o;
}
function getSegments(retargeting, proximity, event, koch, ifas) {
var segs = [];
loop(koch, function (_, v) {
segs.push(new Segment(v.id, v.name, "kochava"));
});
loop((ifas || {}).data, function (_, v) {
segs.push(new Segment(v.id, v.name, "ifa"));
});
loop(retargeting, function (_, v) {
segs.push(new Segment(v.id, v.data.name, "retargeting"));
});
loop(proximity, function (id, v) {
segs.push(new Segment(id, v.name, "proximity"));
});
loop(event, function (_, v) {
segs.push(new Segment(v.segmentId, v.name, "event"));
});
return segs;
}
function setElements(d) {
elements = new Elements(element, {
'sidePanel': { "target": baseSidePanel(data, element.querySelector('section'), forecast, d.statement) },
'section': { 'selector': 'section' },
'tabbedWindow': {},
'main': {},
'segments': {},
'adGroups': {},
'apps': {},
'saveDraft': { 'selector': '.draftButton' },
'addAnother': { 'selector': '.addAnother' },
});
}
function setFns(d) {
uf = new UtilityFns(elements.sidePanel.refresh, core, removeApp, getAppName, d);
bf = new BaseFns(updateTabs);
}
function setTabbedWin(d) {
var a = [];
a.push(new Tab(d, elements, 'main', 'Main', baseMain, uf, bf, campaignValue));
a.push(new Tab(d, elements, 'segments', 'Segments', baseSegments, uf, bf, campaignValue));
a.push(new Tab(d, elements, 'adGroups', 'Ad Groups', baseAdGroups, uf, bf, campaignValue));
a.push(new Tab(d, elements, 'apps', 'Apps', baseApps, uf, bf, campaignValue));
elements.tabbedWindow = new TabbedContainer(elements.section, {
'data': a,
'config': {
'prepend': true
}
}, tabSelected);
}
// Need to look into this and see if it actually works.
function tabSelected(e) { if (e === 3) elements.apps.set(); }
function updateTabs(e) {
if (e === 0) {
elements.tabbedWindow.hideTab(1);
} else {
elements.tabbedWindow.showTab(1);
}
}
function getAppName(key, def) {
var app = appsList[key];
return isDefined(app) ? app.name : (def || 'N/A'); // it should "always" be defined, but in case it isn't, don't crash.
}
function removeApp(key) {
if (!!campaignValue) {
apiRequest("DELETE", "campaign/app/byKey/" + key, campaignValue, null, removeAppCb);
} else {
removeAppCb({ 'key': key }, 200);
}
}
function removeAppCb(e, s) {
if (s !== 200) {
uf.setError("There was an error removing this app")
return;
}
if (!e.key) {
return;
}
delete data.apps[e.key];
var t = elements.apps.getApp(e.key)
if (!!t && !!t.exit) {
t.exit();
}
}
function save(e) { preventDefault(e); saveCampaign(data, core.userID, templateCampaign, campaignValue, draftValue, uf); }
function draft(e) { preventDefault(e); saveDraft(data, core.userID, draftValue, uf); }
// This works just like save at the moment. We need to adjust this so that it clears the input fields and start the
// campaign creation process over after saving.
function addAnother(e) { preventDefault(e); saveCampaign(data, core.userID, templateCampaign, campaignValue, draftValue, uf); }
function exit() { removeChild(target, element); if (events) events.reset(); if (elements) elements.exit(); }
}
function DataManager(uid, fd, cmpV, dftV, tmplCmp, fn) {
var count = 0,
total = fd ? 2 : 1,
d = {},
apiReq = {
'adGroupsList': null,
'billing': null,
'profiles': null,
'apps/list/short': null,
'proximityList': { "source": "segments/proximity/byOwner" },
'segmentsList': null,
'evegmentsList': null,
'domainList': null,
"ioState": null,
'system/apps/list': { 'noID': true }
},
editReq = {};
if (core.isAdmin || core.brand.name === 'Sito Mobile') {
apiReq.kochava = {
source: 'segments/kochava',
noID: true,
};
apiReq.ifaSegments = {
source: 'ifaSegmentsList'
};
}
if (tmplCmp) {
editReq.campaignTemplate = null;
} else if (!!dftV) {
editReq.campaigns = { 'source': 'campaignDraft', 'noID': true, 'args': dftV };
editReq.campaignDraftForecast = { 'source': 'campaignDraftForecast', 'noID': true, 'args': dftV };
} else {
editReq.campaigns = { 'source': 'campaigns/byCID' };
editReq.campaignForecast = null;
// TODO: Need to replace this with statement endpoint
editReq.statement = { 'source': 'statements/byCID', 'args': cmpV, 'noID': true };
}
new ApiManager(apiReq, uid, check);
if (fd) new ApiManager(editReq, cmpV, check);
function check(e, v) { if (isDefined(v)) setValues(v); if (++count == total) fn(null, d); }
function setValues(v) { for (var k in v) { d[k] = v[k]; } }
}
function Segment(id, label, type) {
this.id = id || "";
this.label = label || "";
this.type = type || "";
}
function BaseFns(ut) {
this.updateTabs = ut;
}
function UtilityFns(rfsh, core, removeApp, getAppName, d) {
var notif = core.notifications;
this.refreshSidePanel = rfsh;
this.notif = notif;
this.setSuccess = notif.setSuccess;
this.setError = notif.setError;
this.setMissingFields = notif.setMissingFields;
this.removeApp = removeApp;
this.getAppName = getAppName;
this.data = d;
this.core = core;
}
function Tab(d, eles, k, ttl, fn, uf, bf, cmpV) {
var fnv = fn(d, cmpV, uf, bf);
this.key = k;
this.title = ttl;
this.element = fnv.getE();
eles[k] = fnv;
}
function didThePixelFireToday(pixel) {
if (!pixel || typeof pixel !== 'string' || pixel.length < 10) {
return false;
}
// In case the user's timezone is too far ahead
return (Date.now() - Date.parse(pixel.substr(0, 10))) / (24 * 3600 * 1000) < 2;
}
function getTemplate(editState, draftValue) {
var actionName = editState === true ? 'Edit' : 'Create',
updateName = editState === true ? 'Save' : 'Create',
header = '' + actionName + ' Campaign