(function() {
// Dependencies
var RequestNumber = Retreaver.Base.RequestNumber;
/**
* @constructor
* @memberOf Retreaver
* @param {Object} options
* @param {String} options.campaign_key - Campaign key
* @example
* var campaign = new Retreaver.Campaign({ campaign_key: '67d9fb1917ae8f4eaff36831b41788c3' });
*/
var Campaign = function(options) {
function initialize(data) {
// initialize data store
self.store(data);
}
function find_and_replace_number(replacement_numbers) {
for (var i = 0; i < replacement_numbers.length; i++) {
var rn = replacement_numbers[i];
Retreaver.Vendor.findAndReplaceDOMText(document.getElementsByTagName('body')[0], {
find: rn['find'],
replace: rn['replace_with']
});
var links = document.getElementsByTagName('a');
for (var j = 0; j < links.length; j++) {
var link = links[j];
var href = link.getAttribute('href');
if (href !== null) {
var match = href.match(/^(tel:|clk[a-z]\/tel\/)(.*)/);
if (match && match[2] === rn['find']) {
link.setAttribute('href', match[1] + rn['replace_with']);
}
}
}
}
}
function get_integration_config(number, integration) {
const integrations = number.get("integrations");
if (typeof(integrations) != 'object') {
return;
}
const integrationConfig = integrations[integration];
if (typeof(integrationConfig) == 'undefined') {
return;
}
return integrationConfig;
}
function handle_google_analytics_integration(number) {
googleAnalyticsConfig = get_integration_config(number, "google_analytics");
if (typeof(googleAnalyticsConfig) == "undefined") {
return;
}
const obtainGoogleAnalyticsCookies = new Promise(function(resolve) {
const googleAnalyticsInterval = setInterval(function() {
const gaSessionIdPattern = /_ga_[^=]+=([^;]*)/;
const gaSessionMatch = document.cookie.match(gaSessionIdPattern);
const gaSessionMatched = gaSessionMatch && gaSessionMatch[1];
const gaClientIdPattern = /_ga=([^;]*)/;
const gaClientMatch = document.cookie.match(gaClientIdPattern);
const gaClientMatched = gaClientMatch && gaClientMatch[1];
if (gaSessionMatched && gaClientMatched) {
resolve({
gaSessionId: gaSessionMatched,
gaClientId: gaClientMatched,
});
clearInterval(googleAnalyticsInterval);
}
}, googleAnalyticsConfig["checkIntervalMs"]); // Try to get the Google Analytics session data every X milliseconds
})
obtainGoogleAnalyticsCookies.then(function (sessionData) {
number.replace_tags({
ga_session_id: sessionData.gaSessionId,
ga_client_id: sessionData.gaClientId,
});
});
}
function handle_true_call_integration(number) {
const trueCallConfig = get_integration_config(number, "truecall.com");
if (typeof(trueCallConfig) == "undefined") {
return;
}
// Load the trueCall script into the page it it's missing
if(!document.getElementById("__tc_script") || !window.TrueCall) {
(function () {
const trueCallScriptTag = document.createElement('script');
trueCallScriptTag.type = 'text/javascript';
trueCallScriptTag.async = true;
trueCallScriptTag.defer = true;
trueCallScriptTag.dataset.campaign_uuid = trueCallConfig["tcCampaignUuid"];
trueCallScriptTag.dataset.use_set_did = "1";
trueCallScriptTag.id = "__tc_script"
trueCallScriptTag.src = trueCallConfig["scriptSrc"];
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(trueCallScriptTag);
})();
}
const trueCallInterval = setInterval(function() {
if (window.TrueCall) {
window.TrueCall.setDID(number.get("number")).then(function() {
clearInterval(trueCallInterval);
return window.TrueCall.getIdAsync();
}).then(function(trueCallId) {
const tags = {};
tags[trueCallConfig["tagName"]] = trueCallId;
number.replace_tags(tags);
});
}
}, trueCallConfig["checkIntervalMs"]);
}
function handle_red_track_integration(number) {
const redTrackConfig = get_integration_config(number, "red_track");
if (typeof(redTrackConfig) == "undefined") {
return;
}
function getRedTrackClickID(name) {
const value = '; ' + document.cookie;
const parts = value.split('; ' + name + '=');
if (parts.length == 2) return parts.pop().split(';').shift();
}
const obtainRedTrackClickID = new Promise( function (resolve) {
const myInterval = setInterval(function () {
const redTrackClickID = getRedTrackClickID('rtkclickid-store');
if (redTrackClickID) {
resolve(redTrackClickID);
clearInterval(myInterval);
}
}, redTrackConfig["checkIntervalMs"]);
});
obtainRedTrackClickID.then(function (redTrackClickID) {
const tags = {};
tags[redTrackConfig["tagName"]] = redTrackClickID;
number.replace_tags(tags);
});
}
var self = this;
self.type = 'campaigns';
self.primary_key('campaign_key');
self.numbers = [];
/**
* Fetch a campaign number.
* @memberOf Retreaver.Campaign
* @function request_number
* @instance
* @param {Object} [tags] - A collection of tags as key-value pairs. The number returned will match these tags.
* @param {getNumberCallback} callback - Callback fired if the request completes successfully.
* @param {Function} error_callback - Callback fired if the request raises an error.
* @example
* campaign.request_number({calling_about: 'support'}, function (number) {
* alert(number.get('number'))
* }, function(response){
* alert('something went wrong: ' + response);
* };
*/
self.request_number = function(tags, callback, error_callback) {
// if the first argument is a function, the user has decided to skip passing tags
// therefore cascade the arguments upwards so that everything works as expected
if (typeof(tags) === 'function') {
// argument 3 becomes argument 2
error_callback = callback;
// argument 2 becomes argument 1
callback = tags;
// argument 1 becomes an empty tags object
tags = {};
}
if (typeof callback === 'undefined') {
callback = function () {
};
}
if (typeof tags === 'undefined') {
tags = {};
}
// assign the tags (this is important since it runs it through set_number_matching_tags)
self.set('number_matching_tags', tags);
// request the number
new RequestNumber(self.get('campaign_key', 'number_matching_tags')).perform(function(data) {
// did retreaver return a valid number?
if (typeof(data) !== 'undefined' && typeof(data.number) !== 'undefined' && data.number !== '') {
// initialize number
var number = new Retreaver.Number(data.number);
try {
handle_true_call_integration(number);
} catch (e) {
console.error("Could not integrate with truecall.com, ", e);
}
try {
handle_red_track_integration(number);
} catch (e) {
console.error("Could not integrate with Red Track, ", e);
}
try {
handle_google_analytics_integration(number);
} catch (e) {
console.error("Could not integrate with google analytics, ", e);
}
// if there is a replacement in the response, replace all occurrences
// of that number on the page with the retreaver number
if (typeof(data.number.replacement_numbers) !== 'undefined') {
find_and_replace_number(data.number.replacement_numbers);
}
// call callback
callback.apply(self, [number]);
}
// otherwise fire the error callback
else if (typeof(error_callback) === 'function') {
error_callback.apply(self, [data]);
}
});
};
/**
* Auto replace all numbers on page according to campaign settings
* Calls campaign.request_number
* @memberOf Retreaver.Campaign
* @function auto_replace_numbers
* @instance
* @param {Object} [tags] - A collection of tags as key-value pairs. The number returned will match these tags.
* @param {getNumberCallback} callback - Callback fired if the request completes successfully.
* @param {Function} error_callback - Callback fired if the request raises an error.
* @example
* campaign.auto_replace_numbers({calling_about: 'support'}, function (number) {
* alert(number.get('number'))
* }, function(response){
* alert('something went wrong: ' + response);
* };
*/
self.auto_replace_numbers = function(tags, callback, error_callback) {
if (typeof callback === 'undefined') {
callback = function() {};
}
if (typeof error_callback === 'undefined') {
error_callback = function() {};
}
self.request_number(tags, callback, error_callback);
};
/**
* Retreaver.Campaign#request_number callback fired after the request completes.
* @callback getNumberCallback
* @param {Retreaver.Number} - The number that was returned
*/
self.numbers = function() {
var output = [];
if (typeof(Retreaver.Base.Data._store) !== 'undefined') {
// get numbers
var numbers = Retreaver.Base.Data._store['numbers'];
// present?
if (typeof(numbers) !== 'undefined') {
// collect numbers matching this campaign
for (var primary_key in numbers) {
var number = numbers[primary_key];
if (self.get('campaign_key') == number.campaign_key) {
output.push(new Retreaver.Number(number));
}
}
}
}
return output;
};
self.set_number_matching_tags = function(tags) {
if (typeof(tags) === 'string') {
tags = Retreaver.Number.extract_tags_from_string(tags);
}
if (tags && (typeof tags === "object") && !(tags instanceof Array)) {
return tags
} else {
throw "ArgumentError: Expected number_matching_tags to be an object. eg: {tag: 'value'}";
}
};
initialize(options);
};
Campaign.prototype = new Retreaver.Base.Model();
Retreaver.Campaign = Campaign;
})();