Skip to content

Instantly share code, notes, and snippets.

@jvkiii
Forked from daleyjem/ClickStream.js
Last active March 2, 2017 20:38
Show Gist options
  • Save jvkiii/01901309c4f681c7a2d448ebcb41639d to your computer and use it in GitHub Desktop.
Save jvkiii/01901309c4f681c7a2d448ebcb41639d to your computer and use it in GitHub Desktop.
Extending a Veeva ClickStream helper class for page and event tracking to include other handy utilities for the veeva-library. *Requires veeva-library.js
'use strict';
/**
* Author: John Kirkwood
* Tracking methods forked from Jeremy Daley (https://gist.github.com/daleyjem/465ce9e810231397f8ed)
* Liscence: MIT
*/
//utility methods for veeva-library.js
/*
veevaUtils.trackEvent(id, type, description, callback) : create record for tracked event
veevaUtils.trackPage() : create record of tracked page and updates record with duration
veevaUtils.trackVirtualPage(id, description) : create record of tracked virtual page and update record with duration
veevaUtils.launchApprovedEmail(vault_id, template_num, fragment_nums) : launch vault email with fragments
*/
window.veevaUtils = (function(){
//private
var virtualInterval = -1, // keep track of tracking duration
calls = [], // Queued calls
self = {}; // returned object
//----- public properties / methods ------//
//Boolean: if serving in the Veeva app
self.isVeeva = true;
/**
* This is an event call, with a zero duration. It's used for tracking
* things like clicks.
*
* @param {string} id Track Element Id
* @param {string} type Track Element Type
* @param {string} description Track Element Description
*/
self.trackEvent = function(id, type, description, callback){
var obj = {
'Track_Element_Id_vod__c': id,
'Track_Element_Type_vod__c': type,
'Track_Element_Description_vod__c': description,
'Usage_Start_Time_vod__c': new Date(),
'Usage_Duration_vod__c': 1
};
queue('create', 'Call_Clickstream_vod__c', null, obj, callback);
};
/**
* This is a page tracking call, that should be started at the load of a page. It uses a
* timer to continually update the duration on the page
*/
self.trackPage = function() {
var obj = {
'Track_Element_Type_vod__c': 'Page View',
'Usage_Start_Time_vod__c': new Date(),
'Usage_Duration_vod__c': 1
};
queue('create', 'Call_Clickstream_vod__c', null, obj, function(data){
var duration = 1;
// Every second, we need to update the Duration field for this record
window.setInterval(function(){
duration++;
obj['Usage_Duration_vod__c'] = duration;
queue('update', 'Call_Clickstream_vod__c', data.Call_Clickstream_vod__c.ID, obj, noop);
}, 1000);
});
};
/**
* Track a section within a key message, like for tabs
* @param {string} id Track Virtual Page Id
* @param {string} description Track Virtual Page Description
*/
self.trackVirtualPage = function(id, description){
// First clear the tracking of a previous virtual pageview
window.clearInterval( virtualInterval );
var obj = {
'Track_Element_Id_vod__c': id,
'Track_Element_Description_vod__c': description,
'Track_Element_Type_vod__c': 'In-Page View',
'Usage_Start_Time_vod__c': new Date(),
'Usage_Duration_vod__c': 1
};
queue('create', 'Call_Clickstream_vod__c', null, obj, function(data){
var duration = 1;
// Every second, we need to update the Duration field for this record
virtualInterval = window.setInterval(function(){
duration++;
obj['Usage_Duration_vod__c'] = duration;
queue('update', 'Call_Clickstream_vod__c', data.Call_Clickstream_vod__c.ID, obj, noop);
}, 1000);
});
};
/**
* Launch email template with fragments
* @param {string} vault_id veeva url sandbox (https://my-test-vault.veevavault.com)
* @param {string} template_num document number of email template
* @param {array of strings} fragment_nums array of document numbers of email fragments
*/
self.launchApprovedEmail = function(vault_id, template_num, fragment_nums) {
var templateId = "",
fragmentIds = [],
fragmentLength = (fragment_nums) ? fragment_nums.length : 0,
fragmentCount = 0;
com.veeva.clm.getApprovedDocument(vault_id, template_num, templateCallback);
function templateCallback(result) {
templateId = (result.Approved_Document_vod__c) ? result.Approved_Document_vod__c.ID : template_num;
if (fragmentLength > 0) {
com.veeva.clm.getApprovedDocument(vault_id, fragment_nums[0], fragmentCallback);
} else {
com.veeva.clm.launchApprovedEmail(templateId, fragmentIds, noop);
}
}
function fragmentCallback(result) {
fragmentIds.push(
(result.Approved_Document_vod__c) ? [result.Approved_Document_vod__c.ID] : result.docNum
);
fragmentCount++;
if (fragmentCount < fragmentLength) {
com.veeva.clm.getApprovedDocument(vault_id, fragment_nums[fragmentCount], fragmentCallback);
} else {
com.veeva.clm.launchApprovedEmail(templateId, fragmentIds, noop);
}
}
}
//----- private methods ------//
/**
* Veeva can't take more than one action at a time, so we have to queue up each call
* @param {string} action Something like 'Call_Clickstream_vod__c'
* @param {string} type 'update' or 'create'
* @param {object} obj Tracking fields/values to send to Veeva
* @param {Function} callback
*/
function queue(action, type, id, obj, callback){
var call = {
action: action,
type: type,
id: id,
obj: obj,
callback: callback
};
calls.push( call );
// If this is the first item in the queue, go ahead and call it right away
if (calls.length == 1)
makeCall( call );
};
function makeCall(call){
switch( call.action ) {
case 'update':
com.veeva.clm.updateRecord(call.type, call.id, call.obj, queueCallback);
break;
case 'create':
com.veeva.clm.createRecord(call.type, call.obj, queueCallback);
break;
}
// If we're running in debug mode, we wanna make act like the records were successfully created/updated
if (self.debug === true)
queueCallback( {Call_Clickstream_vod__c: {ID: new Date().getTime()}} );
}
function queueCallback(data, _action){
// Call the original callback function
calls[0].callback( data );
// Remove the current item in the queue
calls.shift();
// If there's anything left in the queue, let's call it.
if (calls.length > 0)
makeCall( calls[0] );
}
/**
* A callback "ground".
*/
function noop(data){
// Do nothing
};
/**
* Enabling Veeva methods to react while serving outside of veeva app. More can be added as needed
* veeva methods being overridden:
* com.veeva.clm.gotoSlide(keyMessage, presentation) //navigate to another keymessage slide
* com.veeva.clm.createRecord(apiName, jsonRecordObject, clmCallback) : create new record
* com.veeva.clm.updateRecord(apiName, jsonRecordObject, clmCallback) : update existing record
* com.veeva.clm.getApprovedDocument(vault_id, doc_num, clmCallback) : get approved document
* com.veeva.clm.launchApprovedEmail(templateId, fragmentIds, clmCallback) : launch veeva email
*/
function overrideVeevaLibrary() {
// com.veeva.clm.gotoSlide
$('a[href^="veeva:gotoSlide("]').on( 'click', function(e) {
e.preventDefault();
var keyMessage = $(e.currentTarget).attr('href').slice(16).split(',')[0].replace('.zip','');
document.location = `../${keyMessage}/${keyMessage}.html`;
});
com.veeva.clm.gotoSlide = function(keyMessage, presentation) {
document.location = `../${keyMessage}/${keyMessage}.html`;
};
// com.veeva.clm.createRecord
com.veeva.clm.createRecord = function(apiName, jsonRecordObject, clmCallback) {
console.log('createRecord: ', jsonRecordObject);
if (clmCallback) { clmCallback( jsonRecordObject ); }
};
// com.veeva.clm.updateRecord
com.veeva.clm.updateRecord = function(apiName, jsonRecordObject, clmCallback) {
console.log('updateRecord: ', jsonRecordObject);
if (clmCallback) { clmCallback( jsonRecordObject ); }
};
// com.veeva.clm.getApprovedDocument
com.veeva.clm.getApprovedDocument = function(vault_id, doc_num, clmCallback) {
var obj = { vaultId:vault_id, docNum:doc_num };
console.log('getApprovedDocument: ', obj);
if (clmCallback) { clmCallback(obj); }
}
// com.veeva.clm.launchApprovedEmail
com.veeva.clm.launchApprovedEmail = function(templateId, fragmentIds, clmCallback) {
var obj = { templateId:templateId, fragmentIds:fragmentIds };
console.log('launcApprovedEmail:', obj);
if (clmCallback) { clmCallback(obj); }
}
}
function findVeeva() {
try {
com.veeva.clm.getDataForCurrentObject('KeyMessage','Id', function(){ console.log('isVeeva: '+self.isVeeva) });
} catch(err) {
self.isVeeva = false;
overrideVeevaLibrary();
}
}
//----- init ------//
findVeeva();
return self;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment